Fix case problem for websocket upgrade

This commit is contained in:
Julien Salleyron 2024-11-06 09:56:04 +01:00 committed by GitHub
parent 7f4ff359a2
commit f70949e3fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 3 deletions

View file

@ -171,7 +171,7 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if reqUpType != "" { if reqUpType != "" {
outReq.Header.Set("Connection", "Upgrade") outReq.Header.Set("Connection", "Upgrade")
outReq.Header.Set("Upgrade", reqUpType) outReq.Header.Set("Upgrade", reqUpType)
if reqUpType == "websocket" { if strings.EqualFold(reqUpType, "websocket") {
cleanWebSocketHeaders(&outReq.Header) cleanWebSocketHeaders(&outReq.Header)
} }
} }
@ -353,6 +353,7 @@ type fasthttpHeader interface {
SetBytesV(key string, value []byte) SetBytesV(key string, value []byte)
DelBytes(key []byte) DelBytes(key []byte)
Del(key string) Del(key string)
ConnectionUpgrade() bool
} }
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h. // removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.

View file

@ -2,7 +2,9 @@ package fast
import ( import (
"bufio" "bufio"
"crypto/sha1"
"crypto/tls" "crypto/tls"
"encoding/base64"
"errors" "errors"
"fmt" "fmt"
"net" "net"
@ -19,6 +21,34 @@ import (
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
func TestWebSocketUpgradeCase(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
challengeKey := r.Header.Get("Sec-Websocket-Key")
hijacker, ok := w.(http.Hijacker)
require.True(t, ok)
c, _, err := hijacker.Hijack()
require.NoError(t, err)
// Force answer with "Connection: upgrade" in lowercase.
_, err = c.Write([]byte("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: upgrade\r\nSec-WebSocket-Accept: " + computeAcceptKey(challengeKey) + "\r\n\n"))
require.NoError(t, err)
}))
defer srv.Close()
proxy := createProxyWithForwarder(t, srv.URL, createConnectionPool(srv.URL, nil))
proxyAddr := proxy.Listener.Addr().String()
_, conn, err := newWebsocketRequest(
withServer(proxyAddr),
withPath("/ws"),
).open()
require.NoError(t, err)
conn.Close()
}
func TestWebSocketTCPClose(t *testing.T) { func TestWebSocketTCPClose(t *testing.T) {
errChan := make(chan error, 1) errChan := make(chan error, 1)
upgrader := gorillawebsocket.Upgrader{} upgrader := gorillawebsocket.Upgrader{}
@ -691,3 +721,10 @@ func createProxyWithForwarder(t *testing.T, uri string, pool *connPool) *httptes
return srv return srv
} }
func computeAcceptKey(challengeKey string) string {
h := sha1.New() // #nosec G401 -- (CWE-326) https://datatracker.ietf.org/doc/html/rfc6455#page-54
h.Write([]byte(challengeKey))
h.Write([]byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

View file

@ -1,7 +1,6 @@
package fast package fast
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
@ -100,7 +99,7 @@ func upgradeType(h http.Header) string {
} }
func upgradeTypeFastHTTP(h fasthttpHeader) string { func upgradeTypeFastHTTP(h fasthttpHeader) string {
if !bytes.Contains(h.Peek("Connection"), []byte("Upgrade")) { if !h.ConnectionUpgrade() {
return "" return ""
} }