@@ -25,27 +25,39 @@ var (
25
25
DefaultDialer = websocket .DefaultDialer
26
26
)
27
27
28
- // WebsocketProxy is an HTTP Handler that takes an incoming WebSocket
29
- // connection and proxies it to another server.
30
- type WebsocketProxy struct {
31
- // Director, if non-nil, is a function that may copy additional request
32
- // headers from the incoming WebSocket connection into the output headers
33
- // which will be forwarded to another server.
34
- Director func (incoming * http.Request , out http.Header )
35
-
36
- // Backend returns the backend URL which the proxy uses to reverse proxy
37
- // the incoming WebSocket connection. Request is the initial incoming and
38
- // unmodified request.
39
- Backend func (* http.Request ) * url.URL
40
-
41
- // Upgrader specifies the parameters for upgrading a incoming HTTP
42
- // connection to a WebSocket connection. If nil, DefaultUpgrader is used.
43
- Upgrader * websocket.Upgrader
44
-
45
- // Dialer contains options for connecting to the backend WebSocket server.
46
- // If nil, DefaultDialer is used.
47
- Dialer * websocket.Dialer
48
- }
28
+ type (
29
+ // WebsocketProxy is an HTTP Handler that takes an incoming WebSocket
30
+ // connection and proxies it to another server.
31
+ WebsocketProxy struct {
32
+ // Director, if non-nil, is a function that may copy additional request
33
+ // headers from the incoming WebSocket connection into the output headers
34
+ // which will be forwarded to another server.
35
+ Director func (incoming * http.Request , out http.Header )
36
+
37
+ // Backend returns the backend URL which the proxy uses to reverse proxy
38
+ // the incoming WebSocket connection. Request is the initial incoming and
39
+ // unmodified request.
40
+ Backend func (* http.Request ) * url.URL
41
+
42
+ // Upgrader specifies the parameters for upgrading a incoming HTTP
43
+ // connection to a WebSocket connection. If nil, DefaultUpgrader is used.
44
+ Upgrader * websocket.Upgrader
45
+
46
+ // Dialer contains options for connecting to the backend WebSocket server.
47
+ // If nil, DefaultDialer is used.
48
+ Dialer * websocket.Dialer
49
+
50
+ // Done specifies a channel for which all proxied websocket connections
51
+ // can be closed on demand by closing the channel.
52
+ Done chan struct {}
53
+ }
54
+
55
+ websocketMsg struct {
56
+ msgType int
57
+ msg []byte
58
+ err error
59
+ }
60
+ )
49
61
50
62
// ProxyHandler returns a new http.Handler interface that reverse proxies the
51
63
// request to the given target.
@@ -174,41 +186,55 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
174
186
175
187
errClient := make (chan error , 1 )
176
188
errBackend := make (chan error , 1 )
189
+
177
190
replicateWebsocketConn := func (dst , src * websocket.Conn , errc chan error ) {
178
- for {
191
+ websocketMsgRcverC := make (chan websocketMsg , 1 )
192
+ websocketMsgRcver := func () <- chan websocketMsg {
179
193
msgType , msg , err := src .ReadMessage ()
180
- if err != nil {
181
- m := websocket .FormatCloseMessage (websocket .CloseNormalClosure , fmt .Sprintf ("%v" , err ))
182
- if e , ok := err .(* websocket.CloseError ); ok {
183
- if e .Code != websocket .CloseNoStatusReceived {
184
- m = websocket .FormatCloseMessage (e .Code , e .Text )
194
+ websocketMsgRcverC <- websocketMsg {msgType , msg , err }
195
+ return websocketMsgRcverC
196
+ }
197
+
198
+ for {
199
+ select {
200
+ case websocketMsgRcv := <- websocketMsgRcver ():
201
+ if websocketMsgRcv .err != nil {
202
+ m := websocket .FormatCloseMessage (websocket .CloseNormalClosure , fmt .Sprintf ("%v" , websocketMsgRcv .err ))
203
+ if e , ok := websocketMsgRcv .err .(* websocket.CloseError ); ok {
204
+ if e .Code != websocket .CloseNoStatusReceived {
205
+ m = websocket .FormatCloseMessage (e .Code , e .Text )
206
+ }
185
207
}
208
+ errc <- websocketMsgRcv .err
209
+ dst .WriteMessage (websocket .CloseMessage , m )
210
+ break
186
211
}
187
- errc <- err
212
+ err = dst .WriteMessage (websocketMsgRcv .msgType , websocketMsgRcv .msg )
213
+ if err != nil {
214
+ errc <- err
215
+ break
216
+ }
217
+ case <- w .Done :
218
+ m := websocket .FormatCloseMessage (websocket .CloseGoingAway , "websocketproxy: closing connection" )
188
219
dst .WriteMessage (websocket .CloseMessage , m )
189
220
break
190
221
}
191
- err = dst .WriteMessage (msgType , msg )
192
- if err != nil {
193
- errc <- err
194
- break
195
- }
196
222
}
197
223
}
198
224
199
225
go replicateWebsocketConn (connPub , connBackend , errClient )
200
226
go replicateWebsocketConn (connBackend , connPub , errBackend )
201
227
202
- var message string
203
228
select {
204
229
case err = <- errClient :
205
- message = "websocketproxy: Error when copying from backend to client: %v"
230
+ if e , ok := err .(* websocket.CloseError ); ! ok || e .Code == websocket .CloseAbnormalClosure {
231
+ log .Printf ("websocketproxy: Error when copying from backend to client: %v" , err )
232
+ }
206
233
case err = <- errBackend :
207
- message = "websocketproxy: Error when copying from client to backend: %v"
208
-
209
- }
210
- if e , ok := err .(* websocket.CloseError ); ! ok || e .Code == websocket .CloseAbnormalClosure {
211
- log .Printf (message , err )
234
+ if e , ok := err .(* websocket.CloseError ); ! ok || e .Code == websocket .CloseAbnormalClosure {
235
+ log .Printf ("websocketproxy: Error when copying from client to backend: %v" , err )
236
+ }
237
+ case <- w .Done :
212
238
}
213
239
}
214
240
0 commit comments