Skip to content

Commit be8e100

Browse files
committed
Allow setting headers from a websocket handshake [IMMUTANT-580]
1 parent 3f45354 commit be8e100

File tree

6 files changed

+51
-29
lines changed

6 files changed

+51
-29
lines changed

project.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
core.memoize "0.5.6"
8484
io.pedestal "0.3.1"
8585
http.async.client "0.5.2"
86-
gniazdo "0.4.1a"
86+
gniazdo "0.4.1b"
8787
compojure "1.3.4"
8888
org.clojure/java.jdbc "0.3.6"
8989
h2 "1.3.176"
@@ -94,7 +94,7 @@
9494
environ "1.0.0"
9595

9696
;; org.projectodd.wunderboss "0.9.0"
97-
org.projectodd.wunderboss "1.x.incremental.296"
97+
org.projectodd.wunderboss "1.x.incremental.297"
9898
;; org.projectodd.wunderboss "0.9.1-SNAPSHOT"
9999

100100
org.immutant :version

web/dev-resources/testing/app.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
:on-error (fn [ch err]
8686
(println "Error on websocket")
8787
(.printStackTrace err))})
88+
:headers {"ham" "biscuit"}
8889
:session (assoc (:session request) :ham :sandwich)))
8990

9091
(def client-defined-handler (atom (fn [_] (throw (Exception. "no handler given")))))

web/src/immutant/web/async.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@
284284
milliseconds.
285285
286286
When the ring handler is called during a WebSocket upgrade request,
287-
any headers returned in the response map are ignored, but any changes to
288-
the session are applied.
287+
any changes to the session in the response map are applied, and any
288+
headers from the response map are included in the upgrade response.
289289
290290
Returns a ring response map, at least the :body of which *must* be
291291
returned in the response map from the calling ring handler."

web/src/immutant/web/internal/servlet.clj

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
WebsocketChannel WebsocketChannel$OnMessage]
2727
[javax.servlet.http HttpServlet HttpServletRequest HttpServletResponse HttpSession]
2828
[javax.servlet Servlet ServletConfig ServletContext]
29-
[javax.websocket Session Endpoint EndpointConfig MessageHandler$Whole CloseReason]
29+
[javax.websocket Session
30+
Endpoint EndpointConfig HandshakeResponse MessageHandler$Whole CloseReason]
3031
[javax.websocket.server ServerContainer
3132
ServerEndpointConfig ServerEndpointConfig$Builder ServerEndpointConfig$Configurator]))
3233

@@ -104,6 +105,17 @@
104105
(defn ^ServerContainer server-container [^ServletContext context]
105106
(.getAttribute context "javax.websocket.server.ServerContainer"))
106107

108+
(extend-type HandshakeResponse
109+
hdr/Headers
110+
(set-header [response ^String key value] (-> response .getHeaders (.put key [value])))
111+
(add-header [response ^String key value]
112+
(let [headers (.getHeaders response)
113+
curr (.get headers key)]
114+
(.put headers key
115+
(if curr
116+
(conj (vec curr) value)
117+
[value])))))
118+
107119
(defn add-endpoint-with-handler
108120
[^Servlet servlet ^ServletConfig config handler]
109121
(let [servlet-context (.getServletContext config)
@@ -118,15 +130,16 @@
118130
(create DelegatingJavaxEndpoint path)
119131
(configurator (proxy [ServerEndpointConfig$Configurator] []
120132
(getEndpointInstance [_] (DelegatingJavaxEndpoint.))
121-
(modifyHandshake [_ _ _]
133+
(modifyHandshake [_ _ ^HandshakeResponse response]
122134
(let [request (.get WebSocketHelpyHelpertonFilter/requestTL)
123-
body (:body (handler (ring/ring-request-map request
124-
[:handler-type :servlet]
125-
[:servlet-request request]
126-
[:websocket? true])))]
135+
{:keys [body headers]} (handler (ring/ring-request-map request
136+
[:handler-type :servlet]
137+
[:servlet-request request]
138+
[:websocket? true]))]
139+
(hdr/set-headers response headers)
127140
(when (instance? WebsocketChannel body)
128-
(DelegatingJavaxEndpoint/setCurrentDelegate
129-
(.endpoint ^WebsocketChannel body)))))))
141+
(DelegatingJavaxEndpoint/setCurrentDelegate
142+
(.endpoint ^WebsocketChannel body)))))))
130143
build))))
131144

132145
(defn add-endpoint

web/src/immutant/web/internal/undertow.clj

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@
1414

1515
(ns ^{:no-doc true} immutant.web.internal.undertow
1616
(:require [immutant.web.async :as async]
17-
[immutant.web.internal.ring :as ring]
1817
[immutant.web.internal.headers :as hdr]
18+
[immutant.web.internal.ring :as ring]
1919
[ring.middleware.session :as ring-session])
20-
(:import java.net.URI
21-
[io.undertow.server HttpHandler HttpServerExchange]
20+
(:import [io.undertow.server HttpHandler HttpServerExchange]
2221
[io.undertow.server.session Session SessionConfig SessionCookieConfig]
2322
[io.undertow.util HeaderMap Headers HttpString Sessions]
2423
[io.undertow.websockets.core CloseMessage WebSocketChannel]
25-
[io.undertow.websockets.spi WebSocketHttpExchange]
24+
java.net.URI
2625
[org.projectodd.wunderboss.web.async Channel
2726
Channel$OnOpen Channel$OnClose Channel$OnError]
2827
[org.projectodd.wunderboss.web.async.websocket WebsocketChannel
@@ -180,20 +179,18 @@
180179
(on-message ch message))))))
181180

182181
(defn ^:internal create-websocket-init-handler [handler-fn request-map-fn]
183-
(let [http-exchange-tl (ThreadLocal.)
184-
downstream-handler (create-http-handler handler-fn)]
182+
(let [downstream-handler (create-http-handler handler-fn)]
185183
(UndertowWebsocket/createHandler
186-
http-exchange-tl
187184
(reify WebsocketInitHandler
188185
(shouldConnect [_ exchange endpoint-wrapper]
189-
(let [http-exchange (.get http-exchange-tl)]
190-
(boolean
191-
(let [body (:body (handler-fn (request-map-fn http-exchange
192-
[:websocket? true]
193-
[:server-exchange http-exchange]
194-
[:handler-type :undertow])))]
195-
(when (instance? WebsocketChannel body)
196-
(.setEndpoint endpoint-wrapper
197-
(.endpoint ^WebsocketChannel body))
198-
true))))))
186+
(boolean
187+
(let [{:keys [body headers] :as r} (handler-fn (request-map-fn exchange
188+
[:websocket? true]
189+
[:server-exchange exchange]
190+
[:handler-type :undertow]))]
191+
(hdr/set-headers (.getResponseHeaders exchange) headers)
192+
(when (instance? WebsocketChannel body)
193+
(.setEndpoint endpoint-wrapper
194+
(.endpoint ^WebsocketChannel body))
195+
true)))))
199196
downstream-handler)))

web/test-integration/immutant/web/integ_test.clj

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,17 @@
207207
(is (= "HELLO" (deref result 5000 :failure)))
208208
(is (= {:count 1 :ham :sandwich} (decode (get-body (str (url) "session"))))))))
209209

210+
(marktest websocket-upgrade-request-can-set-headers
211+
(let [result (promise)]
212+
(with-open [socket (ws/connect (str (url "ws") "ws")
213+
:on-receive (fn [m] (deliver result m))
214+
:cookies @cookies)
215+
session (ws/session socket)]
216+
(ws/send-msg socket "hello")
217+
(is (= "HELLO" (deref result 5000 :failure)))
218+
(let [headers (into {} (-> session .getUpgradeResponse .getHeaders))]
219+
(is (= "biscuit" (first (headers "ham"))))))))
220+
210221
(marktest nested-ws-routes
211222
(doseq [path ["" "foo" "foo/bar"]]
212223
(let [result (promise)]

0 commit comments

Comments
 (0)