package api import ( "bufio" "bytes" "net" "net/http" "net/http/httptest" "testing" "time" ) func TestWebSocketReaderRejectsClientDataAndReservedOpcodes(t *testing.T) { for _, opcode := range []byte{0x0, 0x1, 0x2, 0x3, 0xB, 0xF} { frame := append([]byte{0x80 | opcode, 0x80, 0, 0, 0, 0}, nil...) if _, _, err := readWebSocketFrame(bufio.NewReader(bytes.NewReader(frame))); err == nil { t.Fatalf("opcode 0x%x was accepted", opcode) } } } func TestWebSocketReaderRejectsOversizedControlFrame(t *testing.T) { frame := append([]byte{0x89, 0xFE, 0, 126, 0, 0, 0, 0}, bytes.Repeat([]byte{0}, 126)...) if _, _, err := readWebSocketFrame(bufio.NewReader(bytes.NewReader(frame))); err == nil { t.Fatal("oversized ping control frame was accepted") } } func TestWebSocketWriterDoesNotBlockForeverOnSlowClient(t *testing.T) { sender, receiver := net.Pipe() defer sender.Close() defer receiver.Close() done := make(chan error, 1) go func() { done <- writeWebSocketFrameWithDeadline(sender, 0x1, bytes.Repeat([]byte{'x'}, maxWebSocketFrame), 20*time.Millisecond) }() select { case err := <-done: if err == nil { t.Fatal("write to a non-reading client unexpectedly succeeded") } case <-time.After(time.Second): t.Fatal("write to a non-reading client blocked past its deadline") } } func TestWebSocketHandshakeRequiresRFC6455Version(t *testing.T) { service := &Service{} request := httptest.NewRequest(http.MethodGet, "/v1/events", nil) request.Header.Set("Upgrade", "websocket") request.Header.Set("Connection", "Upgrade") request.Header.Set("Sec-WebSocket-Version", "12") request.Header.Set("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==") recorder := httptest.NewRecorder() service.controlPlaneEvent(recorder, request) if recorder.Code != http.StatusBadRequest { t.Fatalf("version 12 status = %d, want 400", recorder.Code) } } func TestWebSocketMessageBudgetIsBoundedAndResets(t *testing.T) { start := time.Unix(1000, 0) window := start count := 0 for i := 0; i < webSocketMessageLimit; i++ { if !allowWebSocketMessage(start, &window, &count) { t.Fatalf("message %d was rejected within the budget", i) } } if allowWebSocketMessage(start, &window, &count) { t.Fatal("message over the WebSocket budget was accepted") } if !allowWebSocketMessage(start.Add(webSocketMessageWindow), &window, &count) { t.Fatal("WebSocket message budget did not reset") } }