From f907e19b0812fd6e4ca49df118137caa6f60fa85 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Tue, 10 Feb 2026 15:17:15 +0100 Subject: [PATCH] hls: in client, support storing and sending cookies (#5444) --- internal/staticsources/hls/source.go | 4 ++ internal/staticsources/hls/source_test.go | 82 +++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/internal/staticsources/hls/source.go b/internal/staticsources/hls/source.go index 6b4d642d..cde35ab9 100644 --- a/internal/staticsources/hls/source.go +++ b/internal/staticsources/hls/source.go @@ -3,6 +3,7 @@ package hls import ( "net/http" + "net/http/cookiejar" "net/url" "time" @@ -68,12 +69,15 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error { } defer tr.CloseIdleConnections() + jar, _ := cookiejar.New(nil) + var c *gohlslib.Client c = &gohlslib.Client{ URI: params.ResolvedSource, HTTPClient: &http.Client{ Timeout: time.Duration(s.ReadTimeout), Transport: tr, + Jar: jar, }, OnDownloadPrimaryPlaylist: func(u string) { s.Log(logger.Debug, "downloading primary playlist %v", u) diff --git a/internal/staticsources/hls/source_test.go b/internal/staticsources/hls/source_test.go index 8d167c88..22d9876b 100644 --- a/internal/staticsources/hls/source_test.go +++ b/internal/staticsources/hls/source_test.go @@ -120,3 +120,85 @@ func TestSource(t *testing.T) { // the source must be listening on ReloadConf reloadConf <- nil } + +func TestSourceCookie(t *testing.T) { + track1 := &mpegts.Track{ + Codec: &tscodecs.H264{}, + } + + tracks := []*mpegts.Track{track1} + + s := &http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodGet && r.URL.Path == "/stream.m3u8": + w.Header().Set("Set-Cookie", "testcookie=123456; Path=/; Max-Age=3600") + w.Header().Set("Content-Type", `application/vnd.apple.mpegurl`) + w.Write([]byte("#EXTM3U\n" + + "#EXT-X-VERSION:3\n" + + "#EXT-X-ALLOW-CACHE:NO\n" + + "#EXT-X-TARGETDURATION:2\n" + + "#EXT-X-MEDIA-SEQUENCE:0\n" + + "#EXTINF:2,\n" + + "segment1.ts\n" + + "#EXTINF:2,\n" + + "segment2.ts\n" + + "#EXTINF:2,\n" + + "segment2.ts\n" + + "#EXT-X-ENDLIST\n")) + + case r.Method == http.MethodGet && r.URL.Path == "/segment1.ts": + require.Equal(t, "testcookie=123456", r.Header.Get("Cookie")) + w.Header().Set("Content-Type", `video/MP2T`) + + w := &mpegts.Writer{W: w, Tracks: tracks} + err := w.Initialize() + require.NoError(t, err) + + err = w.WriteH264(track1, 2*90000, 2*90000, [][]byte{ + {7, 1, 2, 3}, // SPS + {8}, // PPS + }) + require.NoError(t, err) + + case r.Method == http.MethodGet && r.URL.Path == "/segment2.ts": + w.Header().Set("Content-Type", `video/MP2T`) + + w := &mpegts.Writer{W: w, Tracks: tracks} + err := w.Initialize() + require.NoError(t, err) + } + }), + } + + ln, err := net.Listen("tcp", "localhost:5780") + require.NoError(t, err) + + go s.Serve(ln) + defer s.Shutdown(context.Background()) + + p := &test.StaticSourceParent{} + p.Initialize() + defer p.Close() + + so := &Source{ + Parent: p, + } + + done := make(chan struct{}) + defer func() { <-done }() + + ctx, ctxCancel := context.WithCancel(context.Background()) + defer ctxCancel() + + go func() { + so.Run(defs.StaticSourceRunParams{ //nolint:errcheck + Context: ctx, + ResolvedSource: "http://localhost:5780/stream.m3u8", + Conf: &conf.Path{}, + }) + close(done) + }() + + <-p.Unit +}