mirror of
https://github.com/zap-proto/zip.git
synced 2026-10-19 15:38:57 +00:00
A plain request to a WebSocket address is answered 426, not handed to the upgrader as a server fault
Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -67,6 +67,15 @@ func Upgrade(fn Handler, opts ...Config) zip.Handler {
|
||||
// of a server that tries to upgrade every request it receives.
|
||||
return zip.Terminal("wsx.Upgrade", func(c *zip.Ctx) error {
|
||||
rc := c.Fiber().RequestCtx()
|
||||
// A plain request to a WebSocket address is the client's mistake — a
|
||||
// crawler, a health probe, a browser tab opened on the URL. Answered 426
|
||||
// (RFC 9110 §15.5.22) with the protocol to switch to, as a client error,
|
||||
// rather than handed to the upgrader, whose handshake error is reported
|
||||
// as a server fault.
|
||||
if !websocket.FastHTTPIsWebSocketUpgrade(rc) {
|
||||
c.SetHeader("Upgrade", "websocket")
|
||||
return zip.Errorf(fasthttp.StatusUpgradeRequired, "this address speaks WebSocket: connect with an Upgrade: websocket request")
|
||||
}
|
||||
return up.Upgrade(rc, func(ws *Conn) {
|
||||
_ = fn(ws)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package wsx_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/zap-proto/zip"
|
||||
"github.com/zap-proto/zip/wsx"
|
||||
)
|
||||
|
||||
// A plain GET to a WebSocket address — a crawler, a probe, a tab opened on the
|
||||
// URL — is the client's mistake: 426 with the protocol to switch to, never the
|
||||
// upgrader's handshake error surfacing as a server fault.
|
||||
func TestAPlainRequestIsTold426(t *testing.T) {
|
||||
app := zip.New(zip.Config{AppName: "wsx", DisableStartupMessage: true})
|
||||
reached := false
|
||||
app.Raw(http.MethodGet, "/ws", wsx.Upgrade(func(*wsx.Conn) error {
|
||||
reached = true
|
||||
return nil
|
||||
}))
|
||||
if err := app.Build(); err != nil {
|
||||
t.Fatalf("Build: %v", err)
|
||||
}
|
||||
resp, err := app.Fiber().Test(httptest.NewRequest(http.MethodGet, "/ws", nil))
|
||||
if err != nil {
|
||||
t.Fatalf("GET: %v", err)
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode != http.StatusUpgradeRequired {
|
||||
t.Fatalf("status = %d (%s), want 426", resp.StatusCode, body)
|
||||
}
|
||||
if got := resp.Header.Get("Upgrade"); got != "websocket" {
|
||||
t.Fatalf("Upgrade header = %q, want websocket", got)
|
||||
}
|
||||
if !strings.Contains(string(body), "WebSocket") {
|
||||
t.Fatalf("body does not say what to do: %s", body)
|
||||
}
|
||||
if reached {
|
||||
t.Fatal("the handler ran for a request that never upgraded")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user