Introduces the HTTP surface the browser (or OBS WebRTC clients) target when subscribing to a process's egress: POST /whep/:id -> answer SDP + Location header DELETE /whep/:id/:resource -> tear down a specific peer The handler looks up the per-process stream pair via the Subsystem, validates SDP offer shape, and delegates peer creation to the core PeerFactory's CreatePeerFromSources (two-source forwarding). WHEP routes are left unauthenticated in M2 — browsers and OBS don't carry the Core JWT, and per-process signed-URL tokens are an M3 enhancement. Deployments should place the endpoint behind an authenticated reverse-proxy for now. Tests cover: - 404 for POSTs against unregistered streams - 400 for empty/invalid SDP offers once a stream is registered - 404 for DELETE against unknown resource ids
89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package webrtc
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"github.com/datarhei/core/v16/config"
|
|
)
|
|
|
|
func newTestSubsystem(t *testing.T) *Subsystem {
|
|
t.Helper()
|
|
s, err := New(config.DataWebRTC{Enable: true}, nil)
|
|
if err != nil {
|
|
t.Fatalf("New: %v", err)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// TestHandler_Subscribe_404WhenStreamMissing verifies the WHEP POST
|
|
// returns 404 when no process has registered a stream for that id.
|
|
func TestHandler_Subscribe_404WhenStreamMissing(t *testing.T) {
|
|
h := NewHandler(newTestSubsystem(t), 0)
|
|
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodPost, "/whep/ghost", strings.NewReader("v=0\r\n"))
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
c.SetParamNames("id")
|
|
c.SetParamValues("ghost")
|
|
|
|
if err := h.Subscribe(c); err != nil {
|
|
t.Fatalf("Subscribe returned error: %v", err)
|
|
}
|
|
|
|
if rec.Code != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestHandler_Subscribe_400OnEmptyBody verifies invalid SDP offers
|
|
// short-circuit before any peer is created. Requires a registered
|
|
// stream so lookup doesn't 404 first.
|
|
func TestHandler_Subscribe_400OnEmptyBody(t *testing.T) {
|
|
sub := newTestSubsystem(t)
|
|
// Register a dummy stream so the handler reaches body validation.
|
|
sub.mu.Lock()
|
|
sub.streams["probe"] = &processStream{id: "probe"} // video/audio nil is fine here — we never get past body parse
|
|
sub.mu.Unlock()
|
|
|
|
h := NewHandler(sub, 0)
|
|
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodPost, "/whep/probe", strings.NewReader(""))
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
c.SetParamNames("id")
|
|
c.SetParamValues("probe")
|
|
|
|
if err := h.Subscribe(c); err != nil {
|
|
t.Fatalf("Subscribe returned error: %v", err)
|
|
}
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestHandler_Unsubscribe_404WhenUnknown verifies a DELETE with an
|
|
// unknown resource id returns 404 and no state mutation.
|
|
func TestHandler_Unsubscribe_404WhenUnknown(t *testing.T) {
|
|
h := NewHandler(newTestSubsystem(t), 0)
|
|
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodDelete, "/whep/id/unknown", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
c.SetParamNames("id", "resource")
|
|
c.SetParamValues("id", "unknown")
|
|
|
|
if err := h.Unsubscribe(c); err != nil {
|
|
t.Fatalf("Unsubscribe returned error: %v", err)
|
|
}
|
|
if rec.Code != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", rec.Code)
|
|
}
|
|
}
|