From 760bd95f3ec915637f0d770cac4c1c60e174ff44 Mon Sep 17 00:00:00 2001 From: Natalie Bridgers Date: Tue, 1 Sep 2026 13:36:46 -0500 Subject: [PATCH] fix(api): guard LL-HLS master during presentation init --- pkg/api/playback_llhls.go | 5 +++++ pkg/api/playback_llhls_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/pkg/api/playback_llhls.go b/pkg/api/playback_llhls.go index bf6cf71c..0a308dd8 100644 --- a/pkg/api/playback_llhls.go +++ b/pkg/api/playback_llhls.go @@ -41,6 +41,11 @@ func (a *StreamplaceAPI) HandleLLHLSMaster(ctx context.Context) httprouter.Handl return } presentation := window.Presentation() + if presentation == "" { + w.Header().Set("Cache-Control", "no-store") + http.Redirect(w, r, "/xrpc/place.stream.playback.getLivePlaylist?streamer="+url.QueryEscape(p.ByName("user")), http.StatusTemporaryRedirect) + return + } base := fmt.Sprintf("/api/playback/%s/llhls/%s", url.PathEscape(did), url.PathEscape(presentation)) body := renderLLHLSMaster(base, window.VideoConfig()) writeLLHLSPlaylist(w, body) diff --git a/pkg/api/playback_llhls_test.go b/pkg/api/playback_llhls_test.go index 98f06598..62c4256e 100644 --- a/pkg/api/playback_llhls_test.go +++ b/pkg/api/playback_llhls_test.go @@ -5,6 +5,7 @@ import ( "context" "net/http" "net/http/httptest" + "net/url" "reflect" "strings" "testing" @@ -80,6 +81,29 @@ func TestLLHLSMasterOmitsIndependentSegments(t *testing.T) { } } +func TestLLHLSMasterRedirectsWhilePresentationIsInitializing(t *testing.T) { + const user = "did:key:z6MkPreInitTest" + manager := &media.MediaManager{} + setLLWindowsForTest(manager, map[string]*llhls.Window{user: llhls.NewWindow()}) + api := &StreamplaceAPI{MediaManager: manager, Aliases: map[string]string{}} + handler := api.HandleLLHLSMaster(context.Background()) + + recorder := httptest.NewRecorder() + request := httptest.NewRequest(http.MethodGet, "/master.m3u8", nil) + handler(recorder, request, httprouter.Params{{Key: "user", Value: user}}) + + if recorder.Code != http.StatusTemporaryRedirect { + t.Fatalf("pre-init master status = %d, want %d", recorder.Code, http.StatusTemporaryRedirect) + } + wantLocation := "/xrpc/place.stream.playback.getLivePlaylist?streamer=" + url.QueryEscape(user) + if got := recorder.Header().Get("Location"); got != wantLocation { + t.Fatalf("pre-init master location = %q, want %q", got, wantLocation) + } + if got := recorder.Header().Get("Cache-Control"); got != "no-store" { + t.Fatalf("pre-init master cache policy = %q, want no-store", got) + } +} + func TestLLHLSPartHandlerKeepsExactURIIdentity(t *testing.T) { const ( user = "did:key:z6MkTest" -- 2.51.2