Skip to content

Commit e4c3b0f

Browse files
author
Egor Gorbunov
authored
Do not lower header tokens in headerTokens() (coder#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 c9f314a commit e4c3b0f

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
@@ -159,13 +159,13 @@ func verifyClientRequest(w http.ResponseWriter, r *http.Request) (errCode int, _
159159
return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: handshake request must be at least HTTP/1.1: %q", r.Proto)
160160
}
161161

162-
if !headerContainsToken(r.Header, "Connection", "Upgrade") {
162+
if !headerContainsTokenIgnoreCase(r.Header, "Connection", "Upgrade") {
163163
w.Header().Set("Connection", "Upgrade")
164164
w.Header().Set("Upgrade", "websocket")
165165
return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", r.Header.Get("Connection"))
166166
}
167167

168-
if !headerContainsToken(r.Header, "Upgrade", "websocket") {
168+
if !headerContainsTokenIgnoreCase(r.Header, "Upgrade", "websocket") {
169169
w.Header().Set("Connection", "Upgrade")
170170
w.Header().Set("Upgrade", "websocket")
171171
return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", r.Header.Get("Upgrade"))
@@ -309,11 +309,9 @@ func acceptWebkitDeflate(w http.ResponseWriter, ext websocketExtension, mode Com
309309
return copts, nil
310310
}
311311

312-
func headerContainsToken(h http.Header, key, token string) bool {
313-
token = strings.ToLower(token)
314-
312+
func headerContainsTokenIgnoreCase(h http.Header, key, token string) bool {
315313
for _, t := range headerTokens(h, key) {
316-
if t == token {
314+
if strings.EqualFold(t, token) {
317315
return true
318316
}
319317
}
@@ -354,7 +352,6 @@ func headerTokens(h http.Header, key string) []string {
354352
for _, v := range h[key] {
355353
v = strings.TrimSpace(v)
356354
for _, t := range strings.Split(v, ",") {
357-
t = strings.ToLower(t)
358355
t = strings.TrimSpace(t)
359356
tokens = append(tokens, t)
360357
}

accept_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,12 @@ func Test_selectSubprotocol(t *testing.T) {
224224
serverProtocols: []string{"echo2", "echo3"},
225225
negotiated: "echo3",
226226
},
227+
{
228+
name: "clientCasePresered",
229+
clientProtocols: []string{"Echo1"},
230+
serverProtocols: []string{"echo1"},
231+
negotiated: "Echo1",
232+
},
227233
}
228234

229235
for _, tc := range testCases {

dial.go

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

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

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

0 commit comments

Comments
 (0)