Permalink
Browse files

Fix issue #69 with empty response body

* Fixes issue where deref'ing empty response body in handler causes
  thread to hang
* Also causes closing of client to hang
* Add new wrapper fn for asynchronous closing of client
* Add unit tests to validate changes
  • Loading branch information...
Paul Bostrom
Paul Bostrom committed Nov 20, 2015
1 parent 98a2251 commit 5f8768a9aae70c0e725dfb18900832704e8e995a
Showing with 33 additions and 3 deletions.
  1. +8 −0 src/clj/http/async/client.clj
  2. +5 −3 src/clj/http/async/client/request.clj
  3. +20 −0 test/http/async/client/test.clj
@@ -335,8 +335,16 @@
(log/debug "Closed client: " client)
result)))

(defn close-async
"Asynchronously closes the underlying AsyncHttpProvider by spawning
a thread and avoid blocking AsyncHttpClient. Does not support
websocket clients."
[^AsyncHttpClient client]
(.closeAsynchronously client))

(defn open?
"Checks if client is open."
[client]
(when (satisfies? IClosable client)
(-open? client)))

@@ -20,7 +20,8 @@
[headers :refer :all]
[util :refer :all]
[part :refer :all]]
[clojure.string :refer [join]])
[clojure.string :refer [join]]
[clojure.tools.logging :as log])
(:import (com.ning.http.client AsyncHttpClient AsyncHttpClientConfig$Builder
AsyncHandler
FluentCaseInsensitiveStringsMap
@@ -249,11 +250,12 @@
(^{:tag Object}
onCompleted [this]
(do
(when-not (realized? (:body resp))
(log/debug "Response contains empty body")
(deliver (:body resp) nil))
((or completed
(:completed *default-callbacks*))
resp)
(when-not (realized? (:body resp))
(deliver (:body resp) nil))
(deliver (:done resp) true)))
(^{:tag void}
onThrowable [this #^Throwable t]
@@ -813,6 +813,26 @@
(is (true? (failed? resp)))
(is (instance? ConnectException (error resp))))))

(deftest test-close-empty-body
(let [closed (promise)
client (create-client)
resp (execute-request client (prepare-request :get "http://localhost:8123/empty")
:completed (fn [response]
@(:body response)))
_ (future (Thread/sleep 300) (close client) (deliver closed true))]
(Thread/sleep 600)
(is (realized? closed))))

(deftest test-close-async-slow-callback
(let [closed (promise)
client (create-client)
resp (execute-request client (prepare-request :get "http://localhost:8123/empty")
:completed (fn [response]
(Thread/sleep 1000)))
_ (future (Thread/sleep 300) (close-async client) (deliver closed true))]
(Thread/sleep 600)
(is (realized? closed))))

(deftest closing-client
(let [client (create-client)]
(await (GET client "http://localhost:8123/"))

0 comments on commit 5f8768a

Please sign in to comment.