Skip to content

Commit af36abd

Browse files
committed
Fix HTTP client response body coercion for error status responses
When using the HTTP client's response body coercion middleware (via the `:as` request parameter) in combination with `:throw-exceptions? true` (the default), one would run into an error when the coercion result is not a manifold stream or byte array. Specifically, the commonly used `:as :string` would result in such an error because the error status handler would assume a manifold stream as the default case. This patch fixes this by turning manifold streams into a special case and passing all other response body types through untouched. A basic dedicated test case for the response body coercion middleware is included (there was none so far) while the offending interaction with `:throw-exceptions? true` is covered by `test-client-throw-error-responses-as-exceptions`.
1 parent 90b562c commit af36abd

3 files changed

Lines changed: 26 additions & 7 deletions

File tree

src/aleph/http/client_middleware.clj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,15 +278,15 @@
278278
(error-status-deferred
279279
(assoc rsp :body (ByteArrayInputStream. body)))))
280280

281-
(nil? body)
282-
(error-status-deferred rsp)
283-
284-
:else
281+
(s/stream? body)
285282
(d/chain'
286283
(s/reduce conj [] body)
287284
(fn [body]
288285
(error-status-deferred
289-
(assoc rsp :body (s/->source body))))))))
286+
(assoc rsp :body (s/->source body)))))
287+
288+
:else
289+
(error-status-deferred rsp))))
290290

291291
(defn wrap-method
292292
"Middleware converting the :method option into the :request-method option"

test/aleph/http/client_middleware_test.clj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@
5353
:form-params {:foo :bar}})
5454
(middleware/coerce-form-params {:form-params {:foo :bar}}))))
5555

56+
(deftest test-coerce-response-body
57+
(is (= "foo" (:body (middleware/coerce-response-body
58+
{:as :string}
59+
{:body (s/->source ["f" "o" "o"])}))))
60+
(is (= {:foo "bar"} (:body (middleware/coerce-response-body
61+
{:as :clojure}
62+
{:body "{:foo \"bar\"}"})))))
63+
5664
(deftest test-nested-query-params
5765
(let [req {:request-method :get
5866
:query-params {:foo {:bar "baz"}}}
@@ -246,6 +254,16 @@
246254
(is (instance? ExceptionInfo e))
247255
(is (= 400 (:status (ex-data e))))
248256
(is (nil? (-> e ex-data :body))))))
257+
(testing "response body is string (e.g. via `:as :string`)"
258+
(try
259+
(let [rsp (handle-error-status {:throw-exceptions? true}
260+
{:status 400
261+
:body "hello"})]
262+
(is (= ::thrown? rsp) "should have thrown"))
263+
(catch Exception e
264+
(is (instance? ExceptionInfo e))
265+
(is (= 400 (:status (ex-data e))))
266+
(is (= "hello" (-> e ex-data :body))))))
249267
(testing "error status but :throw-exceptions is false"
250268
(let [rsp (handle-error-status {:throw-exceptions? false}
251269
{:status 400})]

test/aleph/http_test.clj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,12 +1224,13 @@
12241224
{:status 429
12251225
:body "nope"}) {}
12261226
(try
1227-
(-> (http-get "/" {:throw-exceptions? true})
1227+
(-> (http-get "/" {:throw-exceptions? true :as :string})
12281228
(d/timeout! 1e3)
12291229
deref)
12301230
(is (= false true) "should have thrown an exception")
12311231
(catch Exception e
1232-
(is (= 429 (:status (ex-data e))))))))
1232+
(is (= 429 (:status (ex-data e))))
1233+
(is (= "nope" (:body (ex-data e))))))))
12331234

12341235
(deftest test-client-errors-handling
12351236
(testing "writing invalid request message"

0 commit comments

Comments
 (0)