Skip to content

Commit a8c9578

Browse files
committed
Ensure respond and raise functions don't throw
Fixes #535.
1 parent bdc8344 commit a8c9578

File tree

2 files changed

+60
-26
lines changed

2 files changed

+60
-26
lines changed

ring-jetty-adapter/src/ring/adapter/jetty.clj

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,19 +118,27 @@
118118
(upgrade-to-websocket request response response-map options)
119119
(servlet/update-servlet-response response response-map))
120120
(finally
121-
(.setHandled base-request true)))))))
121+
(.setHandled base-request true)
122+
(-> response .getOutputStream .close)))))))
122123

123124
(defn- async-jetty-raise [^AsyncContext context ^HttpServletResponse response]
124125
(fn [^Throwable exception]
125-
(.sendError response 500 (.getMessage exception))
126-
(.complete context)))
126+
(try
127+
(.sendError response 500 (.getMessage exception))
128+
(catch Exception _)
129+
(finally
130+
(.complete context)))))
127131

128132
(defn- async-jetty-respond [^AsyncContext context request response options]
129-
(fn [response-map]
130-
(if (ws/websocket-response? response-map)
131-
(do (upgrade-to-websocket request response response-map options)
132-
(.complete context))
133-
(servlet/update-servlet-response response context response-map))))
133+
(let [raise (async-jetty-raise context response)]
134+
(fn [response-map]
135+
(try
136+
(if (ws/websocket-response? response-map)
137+
(do (upgrade-to-websocket request response response-map options)
138+
(.complete context))
139+
(servlet/update-servlet-response response context response-map))
140+
(catch Exception ex
141+
(raise ex))))))
134142

135143
(defn- async-timeout-listener [request context response handler options]
136144
(reify AsyncListener
@@ -142,22 +150,13 @@
142150
(onError [_ _])
143151
(onStartAsync [_ _])))
144152

145-
(def ^:private empty-listener
146-
(reify AsyncListener
147-
(onTimeout [_ _])
148-
(onComplete [_ _])
149-
(onError [_ _])
150-
(onStartAsync [_ _])))
151-
152153
(defn- async-proxy-handler ^ServletHandler
153154
[handler {:keys [async-timeout async-timeout-handler]
154155
:or {async-timeout 0}
155156
:as options}]
156157
(proxy [ServletHandler] []
157158
(doHandle [_ ^Request base-request ^HttpServletRequest request response]
158159
(let [^AsyncContext context (.startAsync request)]
159-
;; Workaround for https://github.com/jetty/jetty.project/issues/13502
160-
(.addListener context empty-listener)
161160
(.setTimeout context async-timeout)
162161
(when async-timeout-handler
163162
(.addListener context

ring-jetty-adapter/test/ring/adapter/test/jetty.clj

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[ring.adapter.jetty :refer [run-jetty]]
44
[clj-http.client :as http]
55
[clojure.java.io :as io]
6+
[clojure.string :as str]
67
[hato.websocket :as hato]
78
[less.awful.ssl :as less-ssl]
89
[ring.core.protocols :as p]
@@ -474,7 +475,8 @@
474475
{:status 200
475476
:headers {"Transfer-Encoding" "chunked"}
476477
:body (SequenceInputStream.
477-
(ByteArrayInputStream. (.getBytes (str (range 100000)) "UTF-8"))
478+
(ByteArrayInputStream.
479+
(.getBytes (apply str (range 100000)) "UTF-8"))
478480
(proxy [InputStream] []
479481
(read
480482
([] (throw (IOException. "test error")))
@@ -493,21 +495,29 @@
493495
(response (chunked-lazy-seq-with-error request))))
494496

495497
(deftest streaming-with-error
496-
(testing "chunked stream without sending termination chunk on error"
498+
(testing "chunked stream interrupted by error"
497499
(with-server chunked-stream-with-error {:port test-port}
498-
(is (thrown? MalformedChunkCodingException (http/get test-url)))))
500+
(let [response (http/get test-url)]
501+
(is (= 200 (:status response)))
502+
(is (str/ends-with? (:body response) "99999")))))
499503

500-
(testing "chunked sequence without sending termination chunk on error"
504+
(testing "chunked sequence interrupted by error"
501505
(with-server chunked-lazy-seq-with-error {:port test-port}
502-
(is (thrown? MalformedChunkCodingException (http/get test-url)))))
506+
(let [response (http/get test-url)]
507+
(is (= 200 (:status response)))
508+
(is (str/ends-with? (:body response) "99999")))))
503509

504-
(testing "async chunked stream without sending termination chunk on error"
510+
(testing "async chunked stream interrupted by error"
505511
(with-server chunked-stream-with-error {:port test-port :async? true}
506-
(is (thrown? MalformedChunkCodingException (http/get test-url)))))
512+
(let [response (http/get test-url)]
513+
(is (= 200 (:status response)))
514+
(is (str/ends-with? (:body response) "99999")))))
507515

508-
(testing "async chunked sequence without sending termination chunk on error"
516+
(testing "async chunked sequence interrupted by error"
509517
(with-server chunked-lazy-seq-with-error {:port test-port :async? true}
510-
(is (thrown? MalformedChunkCodingException (http/get test-url))))))
518+
(let [response (http/get test-url)]
519+
(is (= 200 (:status response)))
520+
(is (str/ends-with? (:body response) "99999"))))))
511521

512522
(def thread-exceptions (atom []))
513523

@@ -985,3 +995,28 @@
985995
[:t "t: one"]
986996
[:t "b: two"]]
987997
@log)))))
998+
999+
(defn make-client-timeout-handler [ex-callback]
1000+
(fn [_ respond raise]
1001+
(let [response {:status 200
1002+
:body (reify p/StreamableResponseBody
1003+
(write-body-to-stream [_ _ os]
1004+
(with-open [os os]
1005+
(.write os (.getBytes "foo"))
1006+
(.flush os)
1007+
(Thread/sleep 100)
1008+
(.write os (.getBytes " bar"))
1009+
(.flush os))))}]
1010+
(try (respond response)
1011+
(catch Exception ex (ex-callback ex)))
1012+
(try (raise (ex-info "Test" {}))
1013+
(catch Exception ex (ex-callback ex)))
1014+
(ex-callback nil))))
1015+
1016+
(deftest test-callbacks-do-not-throw
1017+
(let [raised (promise)
1018+
handler (make-client-timeout-handler raised)]
1019+
(with-server handler {:port test-port, :async? true}
1020+
(try (http/get (str test-url "/") {:socket-timeout 50})
1021+
(catch java.net.SocketTimeoutException _))
1022+
(is (nil? (deref raised 200 :error))))))

0 commit comments

Comments
 (0)