Skip to content

Commit de22ee3

Browse files
committed
Added support for InputStreams as request bodies.
Updated README with argument details.
1 parent e3e2d83 commit de22ee3

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

README.markdown

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ more towards interactions with REST-based APIs.
2626
{} {"user" user "password" password})
2727
(resourcefully/get "http://localhost:3000/my-secret-page))
2828

29+
The request function requires a URL and optionally accepts a method
30+
(GET by default), a map of headers, a map of cookies, and a request
31+
body. The resourcefully functions take a URL, an optional headers map,
32+
and an optional body.
33+
34+
Request bodies may be strings, maps, or InputStreams. Strings get sent
35+
verbatim. Maps get sent as application/x-www-form-urlencoded, and
36+
InputStreams get streamed to the server 1000 bytes at a time.
37+
2938
The functions in resourcefully are named after the HTTP verbs. Note
3039
that resourcefully must be required :as something since it defines a
3140
"get" function, which would interfere with core if it were fully
@@ -35,4 +44,8 @@ resourcefully inside a "with-cookies" block, cookies will
3544
automatically be saved in a *cookies* ref and sent out with each
3645
request.
3746

47+
TODO:
48+
* Connection pooling/keep-alive?
49+
* Anything else? Send a message via github or the Clojure mailing list.
50+
3851
Licensed under the same terms as Clojure.

src/clojure/http/client.clj

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[clojure.contrib.duck-streams :only [read-lines spit]]
44
[clojure.contrib.str-utils :only [str-join]])
55
(:import (java.net URL URLEncoder)
6-
(java.io StringReader)))
6+
(java.io StringReader InputStream)))
77

88
(def default-headers {"User-Agent" (str "Clojure/" (clojure-version)
99
" (+http://clojure.org)"),
@@ -15,13 +15,34 @@ representation of text."
1515
[text]
1616
(URLEncoder/encode text "UTF-8"))
1717

18-
(defn- encode-body
19-
"Turns a map into a URL-encoded string suitable for a request body,
20-
or just send it verbatim if it's a string."
18+
(defn- encode-body-map
19+
"Turns a map into a URL-encoded string suitable for a request body."
2120
[body]
22-
(if (string? body)
23-
body
24-
(str-join "&" (map #(str-join "=" (map url-encode %)) body))))
21+
(str-join "&" (map #(str-join "=" (map url-encode %)) body)))
22+
23+
(defn- send-body
24+
[body connection headers]
25+
(.setDoOutput connection true)
26+
;; this isn't perfect, since it doesn't account for
27+
;; different capitalization etc
28+
(when (and (map? body)
29+
(not (contains? headers "Content-Type")))
30+
(.setRequestProperty connection
31+
"Content-Type"
32+
"application/x-www-form-urlencoded"))
33+
34+
(.connect connection)
35+
36+
(let [out (.getOutputStream connection)]
37+
(cond
38+
(string? body) (spit out body)
39+
(map? body) (spit out (encode-body-map body))
40+
(instance? InputStream body) (let [bytes (make-array Byte/TYPE 1000)]
41+
(loop [bytes-read (.read body bytes)]
42+
(when (pos? bytes-read)
43+
(.write out bytes 0 bytes-read)
44+
(recur (.read body bytes))))))
45+
(.close out)))
2546

2647
(defn url
2748
"If u is an instance of java.net.URL then returns it without
@@ -90,17 +111,7 @@ by a server."
90111
"Cookie"
91112
(create-cookie-string cookies)))
92113
(if body
93-
(do
94-
(.setDoOutput connection true)
95-
;; this isn't perfect, since it doesn't account for
96-
;; different capitalization etc
97-
(when-not (contains? headers "Content-Type")
98-
(.setRequestProperty connection
99-
"Content-Type"
100-
"application/x-www-form-urlencoded"))
101-
(.connect connection)
102-
(spit (.getOutputStream connection)
103-
(encode-body body)))
114+
(send-body body connection headers)
104115
(.connect connection))
105116

106117
(let [headers (parse-headers connection)]

0 commit comments

Comments
 (0)