Skip to content

Commit 1093278

Browse files
author
Allenx2018
committed
Feature:#480 Upgrade documentation:#404
1 parent 79f944b commit 1093278

File tree

4 files changed

+118
-6
lines changed

4 files changed

+118
-6
lines changed

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/gorilla/websocket
22

33
go 1.12
4+
5+
require golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb

go.sum

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
2+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
3+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
4+
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
5+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
6+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
7+
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
8+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
9+
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
10+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
11+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
12+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
13+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
14+
golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb h1:/7SQoPdMxZ0c/Zu9tBJgMbRE/BmK6i9QXflNJXKAmw0=
15+
golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
16+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
17+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
18+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

server.go

+25-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package websocket
77
import (
88
"bufio"
99
"errors"
10+
"fmt"
1011
"io"
1112
"net/http"
1213
"net/url"
@@ -44,6 +45,7 @@ type Upgrader struct {
4445
// WriteBufferSize.
4546
WriteBufferPool BufferPool
4647

48+
// Subprotocols have lower priority than NegotiateSuprotocol.
4749
// Subprotocols specifies the server's supported protocols in order of
4850
// preference. If this field is not nil, then the Upgrade method negotiates a
4951
// subprotocol by selecting the first match in this list with a protocol
@@ -70,6 +72,13 @@ type Upgrader struct {
7072
// guarantee that compression will be supported. Currently only "no context
7173
// takeover" modes are supported.
7274
EnableCompression bool
75+
// NegotiateSubprotocol has higher priority than Subprotocols.
76+
// NegotiateSubprotocol returns the negotiated subprotocol for the handshake
77+
// request. If the returned string is "", then the the Sec-Websocket-Protocol header
78+
// is not included in the handshake response. If the function returns an error, then
79+
// Upgrade responds to the client with http.StatusBadRequest.
80+
// If this function is not nil, then the Upgrader.Subportocols field is ignored.
81+
NegotiateSubprotocol func(r *http.Request) (string, error)
7382
}
7483

7584
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
@@ -96,7 +105,7 @@ func checkSameOrigin(r *http.Request) bool {
96105
return equalASCIIFold(u.Host, r.Host)
97106
}
98107

99-
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
108+
func (u *Upgrader) selectSubprotocol(r *http.Request) string {
100109
if u.Subprotocols != nil {
101110
clientProtocols := Subprotocols(r)
102111
for _, serverProtocol := range u.Subprotocols {
@@ -106,20 +115,21 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header
106115
}
107116
}
108117
}
109-
} else if responseHeader != nil {
110-
return responseHeader.Get("Sec-Websocket-Protocol")
111118
}
112119
return ""
113120
}
114121

115122
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
116123
//
117124
// The responseHeader is included in the response to the client's upgrade
118-
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
119-
// application negotiated subprotocol (Sec-WebSocket-Protocol).
125+
// request. Use the responseHeader to specify cookies (Set-Cookie).
120126
//
121127
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
122128
// response.
129+
//
130+
// The responseHeader does not support negotiated subprotocol(Sec-Websocket-Protocol)
131+
// IF necessary,please use Upgrader.NegotiateSubprotocol and Upgrader.Subprotocols
132+
// Use the method to view the Upgrader struct.
123133
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
124134
const badHandshake = "websocket: the client is not using the websocket protocol: "
125135

@@ -156,7 +166,16 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
156166
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank")
157167
}
158168

159-
subprotocol := u.selectSubprotocol(r, responseHeader)
169+
subprotocol := ""
170+
if u.NegotiateSubprotocol != nil {
171+
str, err := u.NegotiateSubprotocol(r)
172+
if err != nil {
173+
return u.returnError(w, r, http.StatusBadRequest, fmt.Sprintf("websocket:handshake negotiation protocol error:%s", err))
174+
}
175+
subprotocol = str
176+
} else {
177+
subprotocol = u.selectSubprotocol(r)
178+
}
160179

161180
// Negotiate PMCE
162181
var compress bool

server_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ package websocket
77
import (
88
"bufio"
99
"bytes"
10+
"errors"
1011
"net"
1112
"net/http"
13+
"net/http/httptest"
1214
"reflect"
1315
"strings"
1416
"testing"
@@ -117,3 +119,74 @@ func TestBufioReuse(t *testing.T) {
117119
}
118120
}
119121
}
122+
123+
var negotiateSubprotocolTests = []struct {
124+
*Upgrader
125+
match bool
126+
shouldErr bool
127+
}{
128+
{
129+
&Upgrader{
130+
NegotiateSubprotocol: func(r *http.Request) (s string, err error) { return "json", nil },
131+
}, true, false,
132+
},
133+
{
134+
&Upgrader{
135+
Subprotocols: []string{"json"},
136+
}, true, false,
137+
},
138+
{
139+
&Upgrader{
140+
Subprotocols: []string{"not-match"},
141+
}, false, false,
142+
},
143+
{
144+
&Upgrader{
145+
NegotiateSubprotocol: func(r *http.Request) (s string, err error) { return "", errors.New("not-match") },
146+
}, false, true,
147+
},
148+
}
149+
150+
func TestNegotiateSubprotocol(t *testing.T) {
151+
for i := range negotiateSubprotocolTests {
152+
upgrade := negotiateSubprotocolTests[i].Upgrader
153+
154+
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
155+
upgrade.Upgrade(w, r, nil)
156+
}))
157+
158+
req, err := http.NewRequest("GET", s.URL, strings.NewReader(""))
159+
if err != nil {
160+
t.Fatalf("NewRequest retuened error %v", err)
161+
}
162+
163+
req.Header.Set("Connection", "upgrade")
164+
req.Header.Set("Upgrade", "websocket")
165+
req.Header.Set("Sec-Websocket-Version", "13")
166+
req.Header.Set("Sec-Websocket-Protocol", "json")
167+
req.Header.Set("Sec-Websocket-key", "dGhlIHNhbXBsZSBub25jZQ==")
168+
169+
resp, err := http.DefaultClient.Do(req)
170+
if err != nil {
171+
t.Fatalf("Do returned error %v", err)
172+
}
173+
174+
if negotiateSubprotocolTests[i].shouldErr && resp.StatusCode != http.StatusBadRequest {
175+
t.Errorf("The expecred status code is %d,actual status code is %d", http.StatusBadRequest, resp.StatusCode)
176+
} else {
177+
if negotiateSubprotocolTests[i].match {
178+
protocol := resp.Header.Get("Sec-Websocket-Protocol")
179+
if protocol != "json" {
180+
t.Errorf("Negotiation protocol failed,request protocol is json,reponese protocol is %s", protocol)
181+
}
182+
} else {
183+
if _, ok := resp.Header["Sec-Websocket-Protocol"]; ok {
184+
t.Errorf("Negotiation protocol failed,Sec-Websocket-Protocol field should be empty")
185+
}
186+
}
187+
}
188+
s.Close()
189+
resp.Body.Close()
190+
}
191+
192+
}

0 commit comments

Comments
 (0)