aboutsummaryrefslogtreecommitdiff
path: root/internal/net/web_test.go
blob: d16b31a1324eca1fbc6209a9dc037843f818b98a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package net

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/gorilla/websocket"
)

// The browser transport previously had no tests. CheckOrigin is the security
// boundary for the /ws upgrade; test it directly with a non-loopback peer so
// the loopback bypass does not mask a hostile Origin.
func TestWebSocketCheckOrigin(t *testing.T) {
	cases := []struct {
		name       string
		origin     string
		host       string
		remoteAddr string
		want       bool
	}{
		{"no origin", "", "mud.example:4000", "203.0.113.5:1234", true},
		{"same host", "http://mud.example:4000", "mud.example:4000", "203.0.113.5:1234", true},
		{"same host https", "https://mud.example:4000", "mud.example:4000", "203.0.113.5:1234", true},
		{"same hostname no port", "http://mud.example", "mud.example:4000", "203.0.113.5:1234", true},
		{"hostile origin", "http://evil.example", "mud.example:4000", "203.0.113.5:1234", false},
		{"loopback bypass", "http://evil.example", "mud.example:4000", "127.0.0.1:1234", true},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			req := &http.Request{Header: http.Header{}, Host: tc.host, RemoteAddr: tc.remoteAddr}
			if tc.origin != "" {
				req.Header.Set("Origin", tc.origin)
			}
			if got := upgrader.CheckOrigin(req); got != tc.want {
				t.Fatalf("CheckOrigin(%q, host %q, peer %q) = %v, want %v", tc.origin, tc.host, tc.remoteAddr, got, tc.want)
			}
		})
	}
}

// The /ws upgrade wires a live session and writer. Drive it end-to-end over a
// real HTTP test server (loopback, so the origin check passes).
func TestWebSocketUpgradeAccepted(t *testing.T) {
	s := &Server{hub: NewHub()}
	done := make(chan struct{})
	s.handler = func(*Session, string) { <-done }
	srv := httptest.NewServer(newHTTPMux(s))
	defer srv.Close()
	defer close(done)

	wsURL := "ws" + strings.TrimPrefix(srv.URL, "http") + "/ws"
	conn, resp, err := websocket.DefaultDialer.Dial(wsURL, nil)
	if err != nil {
		t.Fatalf("upgrade rejected: %v (resp %v)", err, resp)
	}
	conn.Close()
}