Skip to content

Commit 448aff6

Browse files
committed
Add websocket tuning options to Jetty adapter
Add the options: :ws-idle-timeout :ws-max-text-size :ws-max-binary-size To the Jetty adapter to allow for tuning of WebSocket timeouts and limits. Fixes #513.
1 parent 45d4c62 commit 448aff6

File tree

2 files changed

+91
-21
lines changed

2 files changed

+91
-21
lines changed

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

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
[ring.websocket :as ws]
88
[ring.websocket.protocols :as wsp])
99
(:import [java.nio ByteBuffer]
10+
[java.time Duration]
1011
[org.eclipse.jetty.server
1112
Request
1213
Server
@@ -96,20 +97,25 @@
9697
(.setAcceptedSubProtocol resp protocol))
9798
(websocket-listener listener))))
9899

99-
(defn- upgrade-to-websocket [^HttpServletRequest request response response-map]
100+
(defn- upgrade-to-websocket
101+
[^HttpServletRequest request response response-map options]
100102
(let [context (.getServletContext request)
101103
container (JettyWebSocketServerContainer/getContainer context)
102104
creator (websocket-creator response-map)]
105+
(doto container
106+
(.setIdleTimeout (Duration/ofMillis (:ws-idle-timeout options 30000)))
107+
(.setMaxTextMessageSize (:ws-max-text-size options 65536))
108+
(.setMaxBinaryMessageSize (:ws-max-binary-size options 65536)))
103109
(.upgrade container creator request response)))
104110

105-
(defn- proxy-handler ^ServletHandler [handler]
111+
(defn- proxy-handler ^ServletHandler [handler options]
106112
(proxy [ServletHandler] []
107113
(doHandle [_ ^Request base-request request response]
108114
(let [request-map (servlet/build-request-map request)
109115
response-map (handler request-map)]
110116
(try
111117
(if (ws/websocket-response? response-map)
112-
(upgrade-to-websocket request response response-map)
118+
(upgrade-to-websocket request response response-map options)
113119
(servlet/update-servlet-response response response-map))
114120
(finally
115121
(.setHandled base-request true)))))))
@@ -119,36 +125,39 @@
119125
(.sendError response 500 (.getMessage exception))
120126
(.complete context)))
121127

122-
(defn- async-jetty-respond [^AsyncContext context request response]
128+
(defn- async-jetty-respond [^AsyncContext context request response options]
123129
(fn [response-map]
124130
(if (ws/websocket-response? response-map)
125-
(do (upgrade-to-websocket request response response-map)
131+
(do (upgrade-to-websocket request response response-map options)
126132
(.complete context))
127133
(servlet/update-servlet-response response context response-map))))
128134

129-
(defn- async-timeout-listener [request context response handler]
135+
(defn- async-timeout-listener [request context response handler options]
130136
(proxy [AsyncListener] []
131137
(onTimeout [^AsyncEvent _]
132138
(handler (servlet/build-request-map request)
133-
(async-jetty-respond context request response)
139+
(async-jetty-respond context request response options)
134140
(async-jetty-raise context response)))
135141
(onComplete [^AsyncEvent _])
136142
(onError [^AsyncEvent _])
137143
(onStartAsync [^AsyncEvent _])))
138144

139-
(defn- async-proxy-handler ^ServletHandler [handler timeout timeout-handler]
145+
(defn- async-proxy-handler ^ServletHandler
146+
[handler {:keys [async-timeout async-timeout-handler]
147+
:or {async-timeout 0}
148+
:as options}]
140149
(proxy [ServletHandler] []
141150
(doHandle [_ ^Request base-request ^HttpServletRequest request response]
142151
(let [^AsyncContext context (.startAsync request)]
143-
(.setTimeout context timeout)
144-
(when timeout-handler
145-
(.addListener
146-
context
147-
(async-timeout-listener request context response timeout-handler)))
152+
(.setTimeout context async-timeout)
153+
(when async-timeout-handler
154+
(.addListener context
155+
(async-timeout-listener request context response
156+
async-timeout-handler options)))
148157
(try
149158
(handler
150159
(servlet/build-request-map request)
151-
(async-jetty-respond context request response)
160+
(async-jetty-respond context request response options)
152161
(async-jetty-raise context response))
153162
(finally
154163
(.setHandled base-request true)))))))
@@ -163,7 +172,8 @@
163172
(ServerConnector. server #^"[Lorg.eclipse.jetty.server.ConnectionFactory;"
164173
(into-array ConnectionFactory factories)))
165174

166-
(defn- unix-domain-server-connector ^UnixDomainServerConnector [^Server server & factories]
175+
(defn- unix-domain-server-connector ^UnixDomainServerConnector
176+
[^Server server & factories]
167177
(UnixDomainServerConnector. server #^"[Lorg.eclipse.jetty.server.ConnectionFactory;"
168178
(into-array ConnectionFactory factories)))
169179

@@ -323,14 +333,18 @@
323333
:output-buffer-size - the response body buffer size (default 32768)
324334
:request-header-size - the maximum size of a request header (default 8192)
325335
:response-header-size - the maximum size of a response header (default 8192)
326-
:send-server-version? - add Server header to HTTP response (default true)"
336+
:send-server-version? - add Server header to HTTP response (default true)
337+
:ws-idle-timeout - the idle timeout for WebSockets in milliseconds
338+
(default 30000)
339+
:ws-max-binary-size - the maximum allowed size in bytes for a WebSocket
340+
binary message (default 65536)
341+
:ws-max-text-size - the maximum allowed size in bytes for a WebSocket
342+
text message (default 65536)"
327343
^Server [handler options]
328344
(let [server (create-server (dissoc options :configurator))
329345
proxy (if (:async? options)
330-
(async-proxy-handler handler
331-
(:async-timeout options 0)
332-
(:async-timeout-handler options))
333-
(proxy-handler handler))]
346+
(async-proxy-handler handler options)
347+
(proxy-handler handler options))]
334348
(.setHandler server (context-handler proxy))
335349
(when-let [configurator (:configurator options)]
336350
(configurator server))

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

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,63 @@
849849
(Thread/sleep 100)
850850
@(hato/close! ws)
851851
(Thread/sleep 100)))
852-
(is (= ["Hello" "World"] @log)))))
852+
(is (= ["Hello" "World"] @log))))
853+
854+
(testing "testing idle timeout"
855+
(let [closer (promise)
856+
handler (constantly
857+
{::ws/listener
858+
(reify wsp/Listener
859+
(on-open [_ _])
860+
(on-message [_ _ _])
861+
(on-pong [_ _ _])
862+
(on-error [_ _ _])
863+
(on-close [_ _ _ _]))})]
864+
(with-server handler {:port test-port, :ws-idle-timeout 100}
865+
@(hato/websocket test-websocket-url
866+
{:on-close (fn [_ status reason]
867+
(closer [status reason]))})
868+
(Thread/sleep 150)
869+
(is (realized? closer))
870+
(is (= @closer [1001 "Connection Idle Timeout"])))))
871+
872+
(testing "max text message size"
873+
(let [closer (promise)
874+
handler (constantly
875+
{::ws/listener
876+
(reify wsp/Listener
877+
(on-open [_ _])
878+
(on-message [_ _ _])
879+
(on-pong [_ _ _])
880+
(on-error [_ _ _])
881+
(on-close [_ _ _ _]))})]
882+
(with-server handler {:port test-port, :ws-max-text-size 5}
883+
(let [ws @(hato/websocket test-websocket-url
884+
{:on-close (fn [_ status reason]
885+
(closer [status reason]))})]
886+
@(hato/send! ws "123456")
887+
(Thread/sleep 50)
888+
(is (realized? closer))
889+
(is (= @closer [1009 "Text message too large: 6 > 5"]))))))
890+
891+
(testing "max text message size"
892+
(let [closer (promise)
893+
handler (constantly
894+
{::ws/listener
895+
(reify wsp/Listener
896+
(on-open [_ _])
897+
(on-message [_ _ _])
898+
(on-pong [_ _ _])
899+
(on-error [_ _ _])
900+
(on-close [_ _ _ _]))})]
901+
(with-server handler {:port test-port, :ws-max-binary-size 5}
902+
(let [ws @(hato/websocket test-websocket-url
903+
{:on-close (fn [_ status reason]
904+
(closer [status reason]))})]
905+
@(hato/send! ws (ByteBuffer/wrap (.getBytes "123456")))
906+
(Thread/sleep 50)
907+
(is (realized? closer))
908+
(is (= @closer [1009 "Binary message too large: 6 > 5"])))))))
853909

854910
(deftest run-jetty-async-websocket-test
855911
(testing "ping/pong"

0 commit comments

Comments
 (0)