Skip to content

Commit 5bd4335

Browse files
Egor Gorbunovnhooyr
Egor Gorbunov
authored andcommitted
Do not lower header tokens in headerTokens() (#273)
HTTP header values, as opposed to header keys, are case sensitive, but implementation of headerTokens() before this patch would return lowered values always. This old behavior could lead to chromium (v87) WebSocket rejecting connnection because negotiated subprotocol, returned in Sec-WebSocket-Protocol header (lowered be headerToken() function) would not match one sent by client, in case client specified value with capital letters.
1 parent aa9fc35 commit 5bd4335

File tree

3 files changed

+12
-9
lines changed

3 files changed

+12
-9
lines changed

accept.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,13 @@ func verifyClientRequest(w http.ResponseWriter, r *http.Request) (errCode int, _
163163
return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: handshake request must be at least HTTP/1.1: %q", r.Proto)
164164
}
165165

166-
if !headerContainsToken(r.Header, "Connection", "Upgrade") {
166+
if !headerContainsTokenIgnoreCase(r.Header, "Connection", "Upgrade") {
167167
w.Header().Set("Connection", "Upgrade")
168168
w.Header().Set("Upgrade", "websocket")
169169
return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", r.Header.Get("Connection"))
170170
}
171171

172-
if !headerContainsToken(r.Header, "Upgrade", "websocket") {
172+
if !headerContainsTokenIgnoreCase(r.Header, "Upgrade", "websocket") {
173173
w.Header().Set("Connection", "Upgrade")
174174
w.Header().Set("Upgrade", "websocket")
175175
return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", r.Header.Get("Upgrade"))
@@ -313,11 +313,9 @@ func acceptWebkitDeflate(w http.ResponseWriter, ext websocketExtension, mode Com
313313
return copts, nil
314314
}
315315

316-
func headerContainsToken(h http.Header, key, token string) bool {
317-
token = strings.ToLower(token)
318-
316+
func headerContainsTokenIgnoreCase(h http.Header, key, token string) bool {
319317
for _, t := range headerTokens(h, key) {
320-
if t == token {
318+
if strings.EqualFold(t, token) {
321319
return true
322320
}
323321
}
@@ -358,7 +356,6 @@ func headerTokens(h http.Header, key string) []string {
358356
for _, v := range h[key] {
359357
v = strings.TrimSpace(v)
360358
for _, t := range strings.Split(v, ",") {
361-
t = strings.ToLower(t)
362359
t = strings.TrimSpace(t)
363360
tokens = append(tokens, t)
364361
}

accept_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ func Test_selectSubprotocol(t *testing.T) {
226226
serverProtocols: []string{"echo2", "echo3"},
227227
negotiated: "echo3",
228228
},
229+
{
230+
name: "clientCasePresered",
231+
clientProtocols: []string{"Echo1"},
232+
serverProtocols: []string{"echo1"},
233+
negotiated: "Echo1",
234+
},
229235
}
230236

231237
for _, tc := range testCases {

dial.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,11 @@ func verifyServerResponse(opts *DialOptions, copts *compressionOptions, secWebSo
197197
return nil, fmt.Errorf("expected handshake response status code %v but got %v", http.StatusSwitchingProtocols, resp.StatusCode)
198198
}
199199

200-
if !headerContainsToken(resp.Header, "Connection", "Upgrade") {
200+
if !headerContainsTokenIgnoreCase(resp.Header, "Connection", "Upgrade") {
201201
return nil, fmt.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", resp.Header.Get("Connection"))
202202
}
203203

204-
if !headerContainsToken(resp.Header, "Upgrade", "WebSocket") {
204+
if !headerContainsTokenIgnoreCase(resp.Header, "Upgrade", "WebSocket") {
205205
return nil, fmt.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", resp.Header.Get("Upgrade"))
206206
}
207207

0 commit comments

Comments
 (0)