@@ -153,15 +153,20 @@ func TestReverseProxy(t *testing.T) {
153
153
func TestReverseProxyStripHeadersPresentInConnection (t * testing.T ) {
154
154
const fakeConnectionToken = "X-Fake-Connection-Token"
155
155
const backendResponse = "I am the backend"
156
+
157
+ // someConnHeader is some arbitrary header to be declared as a hop-by-hop header
158
+ // in the Request's Connection header.
159
+ const someConnHeader = "X-Some-Conn-Header"
160
+
156
161
backend := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
157
162
if c := r .Header .Get (fakeConnectionToken ); c != "" {
158
163
t .Errorf ("handler got header %q = %q; want empty" , fakeConnectionToken , c )
159
164
}
160
- if c := r .Header .Get ("Upgrade" ); c != "" {
161
- t .Errorf ("handler got header %q = %q; want empty" , "Upgrade" , c )
165
+ if c := r .Header .Get (someConnHeader ); c != "" {
166
+ t .Errorf ("handler got header %q = %q; want empty" , someConnHeader , c )
162
167
}
163
- w .Header ().Set ("Connection" , "Upgrade , "+ fakeConnectionToken )
164
- w .Header ().Set ("Upgrade" , "should be deleted" )
168
+ w .Header ().Set ("Connection" , someConnHeader + " , "+ fakeConnectionToken )
169
+ w .Header ().Set (someConnHeader , "should be deleted" )
165
170
w .Header ().Set (fakeConnectionToken , "should be deleted" )
166
171
io .WriteString (w , backendResponse )
167
172
}))
@@ -173,15 +178,15 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
173
178
proxyHandler := NewSingleHostReverseProxy (backendURL )
174
179
frontend := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
175
180
proxyHandler .ServeHTTP (w , r )
176
- if c := r .Header .Get ("Upgrade" ); c != "original value" {
177
- t .Errorf ("handler modified header %q = %q; want %q" , "Upgrade" , c , "original value" )
181
+ if c := r .Header .Get (someConnHeader ); c != "original value" {
182
+ t .Errorf ("handler modified header %q = %q; want %q" , someConnHeader , c , "original value" )
178
183
}
179
184
}))
180
185
defer frontend .Close ()
181
186
182
187
getReq , _ := http .NewRequest ("GET" , frontend .URL , nil )
183
- getReq .Header .Set ("Connection" , "Upgrade , "+ fakeConnectionToken )
184
- getReq .Header .Set ("Upgrade" , "original value" )
188
+ getReq .Header .Set ("Connection" , someConnHeader + " , "+ fakeConnectionToken )
189
+ getReq .Header .Set (someConnHeader , "original value" )
185
190
getReq .Header .Set (fakeConnectionToken , "should be deleted" )
186
191
res , err := frontend .Client ().Do (getReq )
187
192
if err != nil {
@@ -195,8 +200,8 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
195
200
if got , want := string (bodyBytes ), backendResponse ; got != want {
196
201
t .Errorf ("got body %q; want %q" , got , want )
197
202
}
198
- if c := res .Header .Get ("Upgrade" ); c != "" {
199
- t .Errorf ("handler got header %q = %q; want empty" , "Upgrade" , c )
203
+ if c := res .Header .Get (someConnHeader ); c != "" {
204
+ t .Errorf ("handler got header %q = %q; want empty" , someConnHeader , c )
200
205
}
201
206
if c := res .Header .Get (fakeConnectionToken ); c != "" {
202
207
t .Errorf ("handler got header %q = %q; want empty" , fakeConnectionToken , c )
@@ -980,3 +985,66 @@ func TestSelectFlushInterval(t *testing.T) {
980
985
})
981
986
}
982
987
}
988
+
989
+ func TestReverseProxyWebSocket (t * testing.T ) {
990
+ backendServer := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
991
+ if upgradeType (r .Header ) != "websocket" {
992
+ t .Error ("unexpected backend request" )
993
+ http .Error (w , "unexpected request" , 400 )
994
+ return
995
+ }
996
+ c , _ , err := w .(http.Hijacker ).Hijack ()
997
+ if err != nil {
998
+ t .Error (err )
999
+ return
1000
+ }
1001
+ defer c .Close ()
1002
+ io .WriteString (c , "HTTP/1.1 101 Switching Protocols\r \n Connection: upgrade\r \n Upgrade: WebSocket\r \n \r \n " )
1003
+ bs := bufio .NewScanner (c )
1004
+ if ! bs .Scan () {
1005
+ t .Errorf ("backend failed to read line from client: %v" , bs .Err ())
1006
+ return
1007
+ }
1008
+ fmt .Fprintf (c , "backend got %q\n " , bs .Text ())
1009
+ }))
1010
+ defer backendServer .Close ()
1011
+
1012
+ backURL , _ := url .Parse (backendServer .URL )
1013
+ rproxy := NewSingleHostReverseProxy (backURL )
1014
+ rproxy .ErrorLog = log .New (ioutil .Discard , "" , 0 ) // quiet for tests
1015
+
1016
+ frontendProxy := httptest .NewServer (rproxy )
1017
+ defer frontendProxy .Close ()
1018
+
1019
+ req , _ := http .NewRequest ("GET" , frontendProxy .URL , nil )
1020
+ req .Header .Set ("Connection" , "Upgrade" )
1021
+ req .Header .Set ("Upgrade" , "websocket" )
1022
+
1023
+ c := frontendProxy .Client ()
1024
+ res , err := c .Do (req )
1025
+ if err != nil {
1026
+ t .Fatal (err )
1027
+ }
1028
+ if res .StatusCode != 101 {
1029
+ t .Fatalf ("status = %v; want 101" , res .Status )
1030
+ }
1031
+ if upgradeType (res .Header ) != "websocket" {
1032
+ t .Fatalf ("not websocket upgrade; got %#v" , res .Header )
1033
+ }
1034
+ rwc , ok := res .Body .(io.ReadWriteCloser )
1035
+ if ! ok {
1036
+ t .Fatalf ("response body is of type %T; does not implement ReadWriteCloser" , res .Body )
1037
+ }
1038
+ defer rwc .Close ()
1039
+
1040
+ io .WriteString (rwc , "Hello\n " )
1041
+ bs := bufio .NewScanner (rwc )
1042
+ if ! bs .Scan () {
1043
+ t .Fatalf ("Scan: %v" , bs .Err ())
1044
+ }
1045
+ got := bs .Text ()
1046
+ want := `backend got "Hello"`
1047
+ if got != want {
1048
+ t .Errorf ("got %#q, want %#q" , got , want )
1049
+ }
1050
+ }
0 commit comments