Skip to content

Commit

Permalink
muxer: add Cache-Control header to all responses
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed Aug 5, 2023
1 parent 9577da1 commit 3a98743
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 48 deletions.
58 changes: 40 additions & 18 deletions muxer_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ func videoHasParameters(videoTrack *Track) bool {
return false
}

func parseMSNPart(msn string, part string) (uint64, uint64, error) {
var msnint uint64
if msn != "" {
var err error
msnint, err = strconv.ParseUint(msn, 10, 64)
if err != nil {
return 0, 0, err
}
}

var partint uint64
if part != "" {
var err error
partint, err = strconv.ParseUint(part, 10, 64)
if err != nil {
return 0, 0, err
}
}

return (msnint), (partint), nil
}

type muxerServer struct {
variant MuxerVariant
segmentCount int
Expand Down Expand Up @@ -303,6 +325,10 @@ func (s *muxerServer) handleMultistreamPlaylist(w http.ResponseWriter) {
}()

if byts != nil {
// allow caching but use a small period in order to
// allow a stream to change tracks or bitrate
w.Header().Set("Cache-Control", "max-age=30")

w.Header().Set("Content-Type", `application/vnd.apple.mpegurl`)
w.WriteHeader(http.StatusOK)
w.Write(byts)
Expand All @@ -315,24 +341,10 @@ func (s *muxerServer) handleMediaPlaylist(msn string, part string, skip string,
if s.variant == MuxerVariantLowLatency {
isDeltaUpdate = skip == "YES" || skip == "v2"

var msnint uint64
if msn != "" {
var err error
msnint, err = strconv.ParseUint(msn, 10, 64)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
}

var partint uint64
if part != "" {
var err error
partint, err = strconv.ParseUint(part, 10, 64)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
msnint, partint, err := parseMSNPart(msn, part)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}

if msn != "" {
Expand Down Expand Up @@ -363,6 +375,7 @@ func (s *muxerServer) handleMediaPlaylist(msn string, part string, skip string,
}()

if byts != nil {
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Content-Type", `application/vnd.apple.mpegurl`)
w.WriteHeader(http.StatusOK)
w.Write(byts)
Expand Down Expand Up @@ -394,6 +407,7 @@ func (s *muxerServer) handleMediaPlaylist(msn string, part string, skip string,
}()

if byts != nil {
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Content-Type", `application/vnd.apple.mpegurl`)
w.WriteHeader(http.StatusOK)
w.Write(byts)
Expand Down Expand Up @@ -561,6 +575,10 @@ func (s *muxerServer) handleInitFile(w http.ResponseWriter) {
}
defer r.Close()

// allow caching but use a small period in order to
// allow a stream to change tracks
w.Header().Set("Cache-Control", "max-age=30")

w.Header().Set("Content-Type", "video/mp4")
w.WriteHeader(http.StatusOK)
io.Copy(w, r)
Expand All @@ -586,6 +604,8 @@ func (s *muxerServer) handleSegmentOrPart(fname string, w http.ResponseWriter) {
}
defer r.Close()

w.Header().Set("Cache-Control", "max-age=3600")

w.Header().Set(
"Content-Type",
func() string {
Expand Down Expand Up @@ -630,6 +650,8 @@ func (s *muxerServer) handleSegmentOrPart(fname string, w http.ResponseWriter) {
}
defer r.Close()

w.Header().Set("Cache-Control", "max-age=3600")

w.Header().Set("Content-Type", "video/mp4")
w.WriteHeader(http.StatusOK)
io.Copy(w, r)
Expand Down
72 changes: 42 additions & 30 deletions muxer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,22 @@ var testAudioTrack = &Track{
},
}

type fakeResponseWriter struct {
type dummyResponseWriter struct {
bytes.Buffer
h http.Header
statusCode int
}

func (w *fakeResponseWriter) Header() http.Header {
func (w *dummyResponseWriter) Header() http.Header {
return w.h
}

func (w *fakeResponseWriter) WriteHeader(statusCode int) {
func (w *dummyResponseWriter) WriteHeader(statusCode int) {
w.statusCode = statusCode
}

func readPath(m *Muxer, path, msn, part, skip string) ([]byte, error) {
w := &fakeResponseWriter{
func doRequest(m *Muxer, path, msn, part, skip string) ([]byte, http.Header, error) {
w := &dummyResponseWriter{
h: make(http.Header),
}

Expand All @@ -78,10 +78,10 @@ func readPath(m *Muxer, path, msn, part, skip string) ([]byte, error) {
m.Handle(w, r)

if w.statusCode != http.StatusOK {
return nil, fmt.Errorf("bad status code: %v", w.statusCode)
return nil, nil, fmt.Errorf("bad status code: %v", w.statusCode)
}

return w.Bytes(), nil
return w.Bytes(), w.h, nil
}

func TestMuxerVideoAudio(t *testing.T) {
Expand Down Expand Up @@ -175,8 +175,10 @@ func TestMuxerVideoAudio(t *testing.T) {
})
require.NoError(t, err)

byts, err := readPath(m, "/index.m3u8", "", "", "")
byts, h, err := doRequest(m, "/index.m3u8", "", "", "")
require.NoError(t, err)
require.Equal(t, "application/vnd.apple.mpegurl", h.Get("Content-Type"))
require.Equal(t, "max-age=30", h.Get("Cache-Control"))

switch ca {
case "mpegts":
Expand Down Expand Up @@ -207,8 +209,10 @@ func TestMuxerVideoAudio(t *testing.T) {
"stream.m3u8\n", string(byts))
}

byts, err = readPath(m, "stream.m3u8", "", "", "")
byts, h, err = doRequest(m, "stream.m3u8", "", "", "")
require.NoError(t, err)
require.Equal(t, "application/vnd.apple.mpegurl", h.Get("Content-Type"))
require.Equal(t, "no-cache", h.Get("Cache-Control"))

switch ca {
case "mpegts":
Expand All @@ -226,8 +230,10 @@ func TestMuxerVideoAudio(t *testing.T) {
ma := re.FindStringSubmatch(string(byts))
require.NotEqual(t, 0, len(ma))

_, err := readPath(m, ma[2], "", "", "")
_, h, err := doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
require.Equal(t, "video/MP2T", h.Get("Content-Type"))
require.Equal(t, "max-age=3600", h.Get("Cache-Control"))

case "fmp4":
re := regexp.MustCompile(`^#EXTM3U\n` +
Expand All @@ -244,11 +250,15 @@ func TestMuxerVideoAudio(t *testing.T) {
ma := re.FindStringSubmatch(string(byts))
require.NotEqual(t, 0, len(ma))

_, err := readPath(m, "init.mp4", "", "", "")
_, h, err := doRequest(m, "init.mp4", "", "", "")
require.NoError(t, err)
require.Equal(t, "video/mp4", h.Get("Content-Type"))
require.Equal(t, "max-age=30", h.Get("Cache-Control"))

_, err = readPath(m, ma[2], "", "", "")
_, h, err = doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
require.Equal(t, "video/mp4", h.Get("Content-Type"))
require.Equal(t, "max-age=3600", h.Get("Cache-Control"))

case "lowLatency":
require.Equal(t,
Expand Down Expand Up @@ -285,13 +295,15 @@ func TestMuxerVideoAudio(t *testing.T) {
"seg8.mp4\n"+
"#EXT-X-PRELOAD-HINT:TYPE=PART,URI=\"part4.mp4\"\n", string(byts))

_, err := readPath(m, "part3.mp4", "", "", "")
_, h, err := doRequest(m, "part3.mp4", "", "", "")
require.NoError(t, err)
require.Equal(t, "video/mp4", h.Get("Content-Type"))
require.Equal(t, "max-age=3600", h.Get("Cache-Control"))

recv := make(chan struct{})

go func() {
_, err := readPath(m, "part4.mp4", "", "", "")
_, _, err := doRequest(m, "part4.mp4", "", "", "")
require.NoError(t, err)
close(recv)
}()
Expand Down Expand Up @@ -355,7 +367,7 @@ func TestMuxerVideoOnly(t *testing.T) {
})
require.NoError(t, err)

byts, err := readPath(m, "index.m3u8", "", "", "")
byts, _, err := doRequest(m, "index.m3u8", "", "", "")
require.NoError(t, err)

if ca == "mpegts" {
Expand All @@ -376,7 +388,7 @@ func TestMuxerVideoOnly(t *testing.T) {
"stream.m3u8\n", string(byts))
}

byts, err = readPath(m, "stream.m3u8", "", "", "")
byts, _, err = doRequest(m, "stream.m3u8", "", "", "")
require.NoError(t, err)

var ma []string
Expand Down Expand Up @@ -410,13 +422,13 @@ func TestMuxerVideoOnly(t *testing.T) {
require.NotEqual(t, 0, len(ma))

if ca == "mpegts" {
_, err := readPath(m, ma[2], "", "", "")
_, _, err := doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
} else {
_, err := readPath(m, "init.mp4", "", "", "")
_, _, err := doRequest(m, "init.mp4", "", "", "")
require.NoError(t, err)

_, err = readPath(m, ma[2], "", "", "")
_, _, err = doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
}
})
Expand Down Expand Up @@ -467,7 +479,7 @@ func TestMuxerAudioOnly(t *testing.T) {
}})
require.NoError(t, err)

byts, err := readPath(m, "index.m3u8", "", "", "")
byts, _, err := doRequest(m, "index.m3u8", "", "", "")
require.NoError(t, err)

if ca == "mpegts" {
Expand All @@ -486,7 +498,7 @@ func TestMuxerAudioOnly(t *testing.T) {
"stream.m3u8\n", string(byts))
}

byts, err = readPath(m, "stream.m3u8", "", "", "")
byts, _, err = doRequest(m, "stream.m3u8", "", "", "")
require.NoError(t, err)

var ma []string
Expand Down Expand Up @@ -517,13 +529,13 @@ func TestMuxerAudioOnly(t *testing.T) {
require.NotEqual(t, 0, len(ma))

if ca == "mpegts" {
_, err := readPath(m, ma[2], "", "", "")
_, _, err := doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
} else {
_, err := readPath(m, "init.mp4", "", "", "")
_, _, err := doRequest(m, "init.mp4", "", "", "")
require.NoError(t, err)

_, err = readPath(m, ma[2], "", "", "")
_, _, err = doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
}
})
Expand Down Expand Up @@ -551,7 +563,7 @@ func TestMuxerCloseBeforeFirstSegment(t *testing.T) {

m.Close()

b, _ := readPath(m, "stream.m3u8", "", "", "")
b, _, _ := doRequest(m, "stream.m3u8", "", "", "")
require.Equal(t, []byte(nil), b)
}

Expand Down Expand Up @@ -600,7 +612,7 @@ func TestMuxerDoubleRead(t *testing.T) {
})
require.NoError(t, err)

byts, err := readPath(m, "stream.m3u8", "", "", "")
byts, _, err := doRequest(m, "stream.m3u8", "", "", "")
require.NoError(t, err)

re := regexp.MustCompile(`^#EXTM3U\n` +
Expand All @@ -614,10 +626,10 @@ func TestMuxerDoubleRead(t *testing.T) {
ma := re.FindStringSubmatch(string(byts))
require.NotEqual(t, 0, len(ma))

byts1, err := readPath(m, ma[2], "", "", "")
byts1, _, err := doRequest(m, ma[2], "", "", "")
require.NoError(t, err)

byts2, err := readPath(m, ma[2], "", "", "")
byts2, _, err := doRequest(m, ma[2], "", "", "")
require.NoError(t, err)
require.Equal(t, byts1, byts2)
}
Expand Down Expand Up @@ -744,7 +756,7 @@ func TestMuxerUpdateParams(t *testing.T) {
})
require.NoError(t, err)

bu, err := readPath(m, "index.m3u8", "", "", "")
bu, _, err := doRequest(m, "index.m3u8", "", "", "")
require.NoError(t, err)
require.Equal(t, "#EXTM3U\n"+
"#EXT-X-VERSION:9\n"+
Expand All @@ -766,7 +778,7 @@ func TestMuxerUpdateParams(t *testing.T) {
})
require.NoError(t, err)

bu, err = readPath(m, "index.m3u8", "", "", "")
bu, _, err = doRequest(m, "index.m3u8", "", "", "")
require.NoError(t, err)
require.Equal(t, "#EXTM3U\n"+
"#EXT-X-VERSION:9\n"+
Expand Down

0 comments on commit 3a98743

Please sign in to comment.