22 (:use [clojure.contrib.java-utils :only [as-str]]
33 [clojure.contrib.duck-streams :only [read-lines spit]]
44 [clojure.contrib.str-utils :only [str-join]])
5- (:import (java.net URL URLEncoder)
5+ (:import (java.net URL
6+ URLEncoder
7+ HttpURLConnection)
68 (java.io StringReader InputStream)))
79
810(def default-headers {" User-Agent" (str " Clojure/" *clojure-version*
@@ -28,10 +30,10 @@ representation of argument, either a string or map."
2830 (URLEncoder/encode (as-str arg) " UTF-8" )))
2931
3032(defn- send-body
31- [body connection headers]
33+ [body #^HttpURLConnection connection headers]
3234 (.setDoOutput connection true )
33- ; ; this isn't perfect, since it doesn't account for
34- ; ; different capitalization etc
35+ ; ; This isn't perfect, since it doesn't account for
36+ ; ; different capitalization etc.
3537 (when (and (map? body)
3638 (not (contains? headers " Content-Type" )))
3739 (.setRequestProperty connection
@@ -44,14 +46,16 @@ representation of argument, either a string or map."
4446 (cond
4547 (string? body) (spit out body)
4648 (map? body) (spit out (url-encode body))
47- (instance? InputStream body) (let [bytes (make-array Byte/TYPE 1000 )]
48- (loop [bytes-read (.read body bytes)]
49- (when (pos? bytes-read)
50- (.write out bytes 0 bytes-read)
51- (recur (.read body bytes))))))
49+ (instance? InputStream body)
50+ (let [bytes (make-array Byte/TYPE 1000 )]
51+ (loop [#^InputStream stream body
52+ bytes-read (.read stream bytes)]
53+ (when (pos? bytes-read)
54+ (.write out bytes 0 bytes-read)
55+ (recur stream (.read stream bytes))))))
5256 (.close out)))
5357
54- (defn url
58+ (defn #^URL url
5559 " If u is an instance of java.net.URL then returns it without
5660modification, otherwise tries to instantiate a java.net.URL with
5761url as its sole argument."
@@ -63,44 +67,49 @@ url as its sole argument."
6367(defn- body-seq
6468 " Returns a lazy-seq of lines from either the input stream
6569or the error stream of connection, whichever is appropriate."
66- [connection]
70+ [#^HttpURLConnection connection]
6771 (read-lines (or (if (>= (.getResponseCode connection) 400 )
6872 (.getErrorStream connection)
6973 (.getInputStream connection))
7074 (StringReader. " " ))))
7175
7276(defn- parse-headers
7377 " Returns a map of the response headers from connection."
74- [connection]
78+ [#^HttpURLConnection connection]
7579 (let [hs (.getHeaderFields connection)]
7680 (into {} (for [[k v] hs :when k] [k (first v)]))))
7781
7882(defn- parse-cookies
7983 " Returns a map of cookies when given the Set-Cookie string sent
8084by a server."
81- [cookie-string]
85+ [#^String cookie-string]
8286 (when cookie-string
8387 (into {}
84- (for [cookie (.split cookie-string " ;" )]
85- (let [keyval (map # (.trim % ) (.split cookie " =" ))]
88+ (for [#^String cookie (.split cookie-string " ;" )]
89+ (let [keyval (map ( fn [#^String x] (.trim x) ) (.split cookie " =" ))]
8690 [(first keyval) (second keyval)])))))
8791
8892(defn- create-cookie-string
8993 " Returns a string suitable for sending to the server in the
9094\" Cookie\" header when given a clojure map of cookies."
9195 [cookie-map]
9296 (str-join " ; " (map (fn [cookie]
93- (str (as-str (key cookie))
97+ (str #^String (as-str (key cookie))
9498 " ="
95- (as-str (val cookie))))
99+ #^String (as-str (val cookie))))
96100 cookie-map)))
97101
98102(defn request
99- " Perform an HTTP request on url u. "
103+ " Perform an HTTP request on URL u."
100104 [u & [method headers cookies body]]
101- (let [connection (.openConnection (url u))
102- method (.toUpperCase (as-str (or method
103- " GET" )))]
105+
106+ ; ; This function *should* throw an exception on non-HTTP URLs.
107+ ; ; This will happen if the cast fails.
108+ (let [#^HttpURLConnection connection
109+ (cast HttpURLConnection (.openConnection (url u)))
110+
111+ method (.toUpperCase #^String (as-str (or method
112+ " GET" )))]
104113 (.setRequestMethod connection method)
105114
106115 (doseq [header (conj default-headers (or headers {}))]
@@ -112,6 +121,7 @@ by a server."
112121 (.setRequestProperty connection
113122 " Cookie"
114123 (create-cookie-string cookies)))
124+
115125 (if body
116126 (send-body body connection headers)
117127 (.connect connection))
@@ -123,6 +133,6 @@ by a server."
123133 :method method
124134 :headers (dissoc headers " Set-Cookie" )
125135 ; ; This correctly implements case-insensitive lookup.
126- :get-header #(.getHeaderField connection (as-str %))
136+ :get-header #(.getHeaderField connection #^String (as-str %))
127137 :cookies (parse-cookies (headers " Set-Cookie" ))
128138 :url (str (.getURL connection))})))
0 commit comments