Implemented better testing and fixed skipepd frames
This commit is contained in:
@@ -122,10 +122,48 @@ func (c *wsClient) readPump() {
|
||||
|
||||
// ─── Hub ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
// allowedOrigins is the set of Origin values (scheme://host[:port]) that are
|
||||
// accepted for WebSocket upgrades. If empty, same-origin is enforced by
|
||||
// comparing the Origin's host to the HTTP Host header.
|
||||
var allowedOrigins []string
|
||||
|
||||
// SetAllowedOrigins configures the WebSocket Origin allowlist. Pass an empty
|
||||
// slice to enforce same-origin only (the default).
|
||||
func SetAllowedOrigins(origins []string) {
|
||||
allowedOrigins = origins
|
||||
}
|
||||
|
||||
// checkOrigin validates the Origin header against the allowlist, falling back
|
||||
// to a same-origin check (Origin host == Host header) when no allowlist is
|
||||
// configured. Requests with no Origin header (non-browser clients) are allowed.
|
||||
func checkOrigin(r *http.Request) bool {
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
return true // non-browser client
|
||||
}
|
||||
// Check explicit allowlist first.
|
||||
for _, allowed := range allowedOrigins {
|
||||
if origin == allowed {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Fall back to same-origin: compare the Origin's host to the Host header.
|
||||
// Origin format: "scheme://host[:port]" — strip scheme.
|
||||
host := origin
|
||||
if idx := strings.Index(host, "://"); idx >= 0 {
|
||||
host = host[idx+3:]
|
||||
}
|
||||
// Strip path if present.
|
||||
if idx := strings.Index(host, "/"); idx >= 0 {
|
||||
host = host[:idx]
|
||||
}
|
||||
return host == r.Host
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 4096,
|
||||
WriteBufferSize: 64 * 1024,
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
CheckOrigin: checkOrigin,
|
||||
}
|
||||
|
||||
// sourceHubState holds all data for one active data source.
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package wshub
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestCheckOrigin_NoOriginHeader — non-browser clients (no Origin) are allowed.
|
||||
func TestCheckOrigin_NoOriginHeader(t *testing.T) {
|
||||
r := &http.Request{Header: http.Header{}}
|
||||
if !checkOrigin(r) {
|
||||
t.Fatal("non-browser client (no Origin header) should be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckOrigin_SameOrigin — Origin host matching Host header is allowed.
|
||||
func TestCheckOrigin_SameOrigin(t *testing.T) {
|
||||
r := &http.Request{
|
||||
Header: http.Header{
|
||||
"Origin": []string{"http://localhost:8090"},
|
||||
},
|
||||
Host: "localhost:8090",
|
||||
}
|
||||
if !checkOrigin(r) {
|
||||
t.Fatal("same-origin request should be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckOrigin_CrossOriginBlocked — different Origin host is rejected.
|
||||
func TestCheckOrigin_CrossOriginBlocked(t *testing.T) {
|
||||
r := &http.Request{
|
||||
Header: http.Header{
|
||||
"Origin": []string{"http://evil.example.com:8090"},
|
||||
},
|
||||
Host: "localhost:8090",
|
||||
}
|
||||
if checkOrigin(r) {
|
||||
t.Fatal("cross-origin request should be blocked")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckOrigin_Allowlist — explicitly allowed origins pass even if cross-origin.
|
||||
func TestCheckOrigin_Allowlist(t *testing.T) {
|
||||
SetAllowedOrigins([]string{"http://evil.example.com:8090"})
|
||||
defer SetAllowedOrigins(nil) // reset
|
||||
|
||||
r := &http.Request{
|
||||
Header: http.Header{
|
||||
"Origin": []string{"http://evil.example.com:8090"},
|
||||
},
|
||||
Host: "localhost:8090",
|
||||
}
|
||||
if !checkOrigin(r) {
|
||||
t.Fatal("allowlisted origin should be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckOrigin_AllowlistDoesNotMatch — non-allowlisted cross-origin is blocked.
|
||||
func TestCheckOrigin_AllowlistDoesNotMatch(t *testing.T) {
|
||||
SetAllowedOrigins([]string{"http://good.example.com"})
|
||||
defer SetAllowedOrigins(nil)
|
||||
|
||||
r := &http.Request{
|
||||
Header: http.Header{
|
||||
"Origin": []string{"http://evil.example.com"},
|
||||
},
|
||||
Host: "localhost:8090",
|
||||
}
|
||||
if checkOrigin(r) {
|
||||
t.Fatal("non-allowlisted cross-origin should be blocked")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user