forked from dakrone/clj-http
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Roman Scherer
committed
Sep 8, 2011
1 parent
65eae47
commit b693ae3
Showing
4 changed files
with
301 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
(ns clj-http.cookies | ||
(:import (org.apache.http.client.params ClientPNames CookiePolicy) | ||
(org.apache.http.cookie CookieOrigin) | ||
(org.apache.http.params BasicHttpParams) | ||
(org.apache.http.impl.cookie BasicClientCookie2) | ||
(org.apache.http.impl.cookie BrowserCompatSpecFactory) | ||
(org.apache.http.message BasicHeader)) | ||
(:use [clojure.contrib.string :only (as-str blank? join lower-case)] | ||
clj-http.util)) | ||
|
||
(defn- cookie-spec [] | ||
(.newInstance | ||
(BrowserCompatSpecFactory.) | ||
(doto (BasicHttpParams.) | ||
(.setParameter ClientPNames/COOKIE_POLICY CookiePolicy/BROWSER_COMPATIBILITY)))) | ||
|
||
(defn- compact-map | ||
"Removes all map entries where value is nil." | ||
[m] (reduce #(if (get m %2) (assoc %1 %2 (get m %2)) %1) (sorted-map) (sort (keys m)))) | ||
|
||
(defn- to-cookie | ||
"Converts a ClientCookie object into a tuple where the first item is | ||
the name of the cookie and the second item the content of the | ||
cookie." | ||
[cookie] | ||
[(.getName cookie) | ||
(compact-map | ||
{:comment (.getComment cookie) | ||
:comment-url (.getCommentURL cookie) | ||
:discard (not (.isPersistent cookie)) | ||
:domain (.getDomain cookie) | ||
:expires (if (.getExpiryDate cookie) (.getExpiryDate cookie)) | ||
:path (.getPath cookie) | ||
:ports (if (.getPorts cookie) (seq (.getPorts cookie))) | ||
:secure (.isSecure cookie) | ||
:value (url-decode (.getValue cookie)) | ||
:version (.getVersion cookie)})]) | ||
|
||
(defn- to-basic-client-cookie | ||
"Converts a cookie seq into a BasicClientCookie2." | ||
[[cookie-name cookie-content]] | ||
(doto (BasicClientCookie2. (as-str cookie-name) (url-encode (as-str (:value cookie-content)))) | ||
(.setComment (:comment cookie-content)) | ||
(.setCommentURL (:comment-url cookie-content)) | ||
(.setDiscard (or (:discard cookie-content) true)) | ||
(.setDomain (:domain cookie-content)) | ||
(.setExpiryDate (:expires cookie-content)) | ||
(.setPath (:path cookie-content)) | ||
(.setPorts (int-array (:ports cookie-content))) | ||
(.setSecure (or (:secure cookie-content) false)) | ||
(.setVersion (or (:version cookie-content) 0)))) | ||
|
||
(defn decode-cookie | ||
"Decode the Set-Cookie string into a cookie seq." | ||
[set-cookie-str] | ||
(if-not (blank? set-cookie-str) | ||
(let [domain (lower-case (str (gensym))) ; I just want to parse a cookie without providing origin. How? | ||
origin (CookieOrigin. domain 80 "/" false) | ||
[cookie-name cookie-content] (to-cookie (first (.parse (cookie-spec) (BasicHeader. "set-cookie" set-cookie-str) origin)))] | ||
[cookie-name | ||
(if (= domain (:domain cookie-content)) | ||
(dissoc cookie-content :domain) cookie-content)]))) | ||
|
||
(defn decode-cookies | ||
"Converts a cookie string or seq of strings into a cookie map." | ||
[cookies] | ||
(reduce #(assoc %1 (first %2) (second %2)) {} | ||
(map decode-cookie (if (sequential? cookies) cookies [cookies])))) | ||
|
||
(defn decode-cookie-header | ||
"Decode the Set-Cookie header into the cookies key." | ||
[response] | ||
(if-let [cookies (get (:headers response) "set-cookie")] | ||
(assoc response | ||
:cookies (decode-cookies cookies) | ||
:headers (dissoc (:headers response) "set-cookie")) | ||
response)) | ||
|
||
(defn encode-cookie | ||
"Encode the cookie into a string used by the Cookie header." | ||
[cookie] | ||
(if-let [header (first (.formatCookies (cookie-spec) [(to-basic-client-cookie cookie)]))] | ||
(.getValue header))) | ||
|
||
(defn encode-cookies | ||
"Encode the cookie map into a string." | ||
[cookie-map] (join ";" (map encode-cookie (seq cookie-map)))) | ||
|
||
(defn encode-cookie-header | ||
"Encode the :cookies key of the request into a Cookie header." | ||
[request] | ||
(if (:cookies request) | ||
(-> request | ||
(assoc-in [:headers "Cookie"] (encode-cookies (:cookies request))) | ||
(dissoc :cookies)) | ||
request)) | ||
|
||
(defn wrap-cookies | ||
[client] | ||
(fn [request] | ||
(let [response (client (encode-cookie-header request))] | ||
(decode-cookie-header response)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
(ns clj-http.cookies-test | ||
(:import (org.apache.http.impl.cookie BasicClientCookie BasicClientCookie2)) | ||
(:use clj-http.cookies | ||
clj-http.util | ||
clojure.test)) | ||
|
||
(defn refer-private [ns] | ||
(doseq [[symbol var] (ns-interns ns)] | ||
(when (:private (meta var)) | ||
(intern *ns* symbol var)))) | ||
|
||
(refer-private 'clj-http.cookies) | ||
|
||
(def session "ltQGXSNp7cgNeFG6rPE06qzriaI+R8W7zJKFu4UOlX4=--lWgojFmZlDqSBnYJlUmwhqXL4OgBTkra5WXzi74v+nE=") | ||
|
||
(deftest test-compact-map | ||
(are [map expected] | ||
(is (= expected (compact-map map))) | ||
{:a nil :b 2 :c 3 :d nil} | ||
{:b 2 :c 3} | ||
{:comment nil :domain "example.com" :path "/" :ports [80 8080] :value 1} | ||
{:domain "example.com" :path "/" :ports [80 8080] :value 1})) | ||
|
||
(deftest test-decode-cookie | ||
(are [set-cookie-str expected] | ||
(is (= expected (decode-cookie set-cookie-str))) | ||
nil nil | ||
"" nil | ||
"example-cookie=example-value;Path=/" | ||
["example-cookie" {:discard true :path "/" :value "example-value" :version 0}] | ||
"example-cookie=example-value;Domain=.example.com;Path=/" | ||
["example-cookie" {:discard true :domain ".example.com" :path "/" :value "example-value" :version 0}])) | ||
|
||
(deftest test-decode-cookies-with-seq | ||
(let [cookies (decode-cookies [(str "ring-session=" (url-encode session))])] | ||
(is (map? cookies)) | ||
(is (= 1 (count cookies))) | ||
(let [cookie (get cookies "ring-session")] | ||
(is (= true (:discard cookie))) | ||
(is (nil? (:domain cookie))) | ||
(is (= "/" (:path cookie))) | ||
(is (= session (:value cookie))) | ||
(is (= 0 (:version cookie)))))) | ||
|
||
(deftest test-decode-cookies-with-string | ||
(let [cookies (decode-cookies (str "ring-session=" (url-encode session) ";Path=/"))] | ||
(is (map? cookies)) | ||
(is (= 1 (count cookies))) | ||
(let [cookie (get cookies "ring-session")] | ||
(is (= true (:discard cookie))) | ||
(is (nil? (:domain cookie))) | ||
(is (= "/" (:path cookie))) | ||
(is (= session (:value cookie))) | ||
(is (= 0 (:version cookie)))))) | ||
|
||
(deftest test-decode-cookie-header | ||
(are [response expected] | ||
(is (= expected (decode-cookie-header response))) | ||
{:headers {"set-cookie" "a=1"}} | ||
{:cookies {"a" {:discard true, :path "/", :value "1", :version 0}}, :headers {}} | ||
{:headers {"set-cookie" (str "ring-session=" (url-encode session) ";Path=/")}} | ||
{:cookies {"ring-session" {:discard true, :path "/", :value session, :version 0}}, :headers {}})) | ||
|
||
(deftest test-encode-cookie | ||
(are [cookie expected] | ||
(is (= expected (encode-cookie cookie))) | ||
[:a {:value "b"}] "a=b" | ||
["a" {:value "b"}] "a=b" | ||
["example-cookie" {:domain ".example.com" :path "/" :value "example-value"}] "example-cookie=example-value" | ||
["ring-session" {:value session}] (str "ring-session=" (url-encode session)))) | ||
|
||
(deftest test-encode-cookies | ||
(are [cookie expected] | ||
(is (= expected (encode-cookies cookie))) | ||
{:a {:value "b"} :c {:value "d"} :e {:value "f"}} | ||
"a=b;c=d;e=f" | ||
{"a" {:value "b"} "c" {:value "d"} "e" {:value "f"}} | ||
"a=b;c=d;e=f" | ||
{"example-cookie" {:domain ".example.com" :path "/" :value "example-value"}} | ||
"example-cookie=example-value" | ||
{"example-cookie" {:domain ".example.com" :path "/" :value "example-value" :discard true :version 0}} | ||
"example-cookie=example-value" | ||
{"ring-session" {:value session}} | ||
(str "ring-session=" (url-encode session)))) | ||
|
||
(deftest test-encode-cookie-header | ||
(are [request expected] | ||
(is (= expected (encode-cookie-header request))) | ||
{:cookies {"a" {:value "1"}}} | ||
{:headers {"Cookie" "a=1"}} | ||
{:cookies {"example-cookie" {:domain ".example.com" :path "/" :value "example-value"}}} | ||
{:headers {"Cookie" "example-cookie=example-value"}})) | ||
|
||
(deftest test-to-basic-client-cookie-with-simple-cookie | ||
(let [cookie (to-basic-client-cookie | ||
["ring-session" | ||
{:value session | ||
:path "/" | ||
:domain "example.com"}])] | ||
(is (= "ring-session" (.getName cookie))) | ||
(is (= (url-encode session) (.getValue cookie))) | ||
(is (= "/" (.getPath cookie))) | ||
(is (= "example.com" (.getDomain cookie))) | ||
(is (nil? (.getComment cookie))) | ||
(is (nil? (.getCommentURL cookie))) | ||
(is (not (.isPersistent cookie))) | ||
(is (nil? (.getExpiryDate cookie))) | ||
(is (nil? (seq (.getPorts cookie)))) | ||
(is (not (.isSecure cookie))) | ||
(is (= 0 (.getVersion cookie))))) | ||
|
||
(deftest test-to-basic-client-cookie-with-full-cookie | ||
(let [cookie (to-basic-client-cookie | ||
["ring-session" | ||
{:value session | ||
:path "/" | ||
:domain "example.com" | ||
:comment "Example Comment" | ||
:comment-url "http://example.com/cookies" | ||
:discard true | ||
:expires (java.util.Date. (long 0)) | ||
:ports [80 8080] | ||
:secure true | ||
:version 0}])] | ||
(is (= "ring-session" (.getName cookie))) | ||
(is (= (url-encode session) (.getValue cookie))) | ||
(is (= "/" (.getPath cookie))) | ||
(is (= "example.com" (.getDomain cookie))) | ||
(is (= "Example Comment" (.getComment cookie))) | ||
(is (= "http://example.com/cookies" (.getCommentURL cookie))) | ||
(is (not (.isPersistent cookie))) | ||
(is (= (java.util.Date. (long 0)) (.getExpiryDate cookie))) | ||
(is (= [80 8080] (seq (.getPorts cookie)))) | ||
(is (.isSecure cookie)) | ||
(is (= 0 (.getVersion cookie))))) | ||
|
||
(deftest test-to-basic-client-cookie-with-symbol-as-name | ||
(let [cookie (to-basic-client-cookie [:ring-session {:value session :path "/" :domain "example.com"}])] | ||
(is (= "ring-session" (.getName cookie))))) | ||
|
||
(deftest test-to-cookie-with-simple-cookie | ||
(let [[name content] | ||
(to-cookie | ||
(doto (BasicClientCookie. "example-cookie" "example-value") | ||
(.setDomain "example.com") | ||
(.setPath "/")))] | ||
(is (= "example-cookie" name)) | ||
(is (nil? (:comment content))) | ||
(is (nil? (:comment-url content))) | ||
(is (:discard content)) | ||
(is (= "example.com" (:domain content))) | ||
(is (nil? (:expires content))) | ||
(is (nil? (:ports content))) | ||
(is (not (:secure content))) | ||
(is (= 0 (:version content))) | ||
(is (= "example-value" (:value content))))) | ||
|
||
(deftest test-to-cookie-with-full-cookie | ||
(let [[name content] | ||
(to-cookie | ||
(doto (BasicClientCookie2. "example-cookie" "example-value") | ||
(.setComment "Example Comment") | ||
(.setCommentURL "http://example.com/cookies") | ||
(.setDiscard true) | ||
(.setDomain "example.com") | ||
(.setExpiryDate (java.util.Date. (long 0))) | ||
(.setPath "/") | ||
(.setPorts (int-array [80 8080])) | ||
(.setSecure true) | ||
(.setVersion 1)))] | ||
(is (= "example-cookie" name)) | ||
(is (= "Example Comment" (:comment content))) | ||
(is (= "http://example.com/cookies" (:comment-url content))) | ||
(is (= true (:discard content))) | ||
(is (= "example.com" (:domain content))) | ||
(is (= (java.util.Date. (long 0)) (:expires content))) | ||
(is (= [80 8080] (:ports content))) | ||
(is (= true (:secure content))) | ||
(is (= 1 (:version content))) | ||
(is (= "example-value" (:value content))))) | ||
|
||
(deftest test-wrap-cookies | ||
(is (= {:cookies {"example-cookie" {:discard true :domain ".example.com" :path "/" :value "example-value" :version 0}} :headers {}} | ||
((wrap-cookies | ||
(fn [request] | ||
(is (= (get (:headers request) "Cookie") "a=1;b=2")) | ||
{:headers {"set-cookie" "example-cookie=example-value;Domain=.example.com;Path=/"}})) | ||
{:cookies {:a {:value "1"} :b {:value "2"}}})))) | ||
|