From d0c76d778c02091b804c106ecdc601d05363a45e Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat, 29 May 2021 16:05:44 +0200 Subject: [PATCH] HLS: support paths with slashes (#381) --- internal/hlsconverter/converter.go | 18 +++++++++--------- internal/hlsserver/server.go | 29 +++++++++++++++++++---------- main_hlsreader_test.go | 4 ++-- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/internal/hlsconverter/converter.go b/internal/hlsconverter/converter.go index c4ddc2cd..9075f46c 100644 --- a/internal/hlsconverter/converter.go +++ b/internal/hlsconverter/converter.go @@ -103,11 +103,11 @@ func ipEqualOrInRange(ip net.IP, ips []interface{}) bool { // Request is an HTTP request received by an HLS server. type Request struct { - Path string - Subpath string - Req *http.Request - W http.ResponseWriter - Res chan io.Reader + Path string + FileName string + Req *http.Request + W http.ResponseWriter + Res chan io.Reader } type trackIDPayloadPair struct { @@ -559,7 +559,7 @@ func (c *Converter) runRequestHandler(terminate chan struct{}, done chan struct{ } switch { - case req.Subpath == "stream.m3u8": + case req.FileName == "stream.m3u8": func() { c.tsMutex.Lock() defer c.tsMutex.Unlock() @@ -582,8 +582,8 @@ func (c *Converter) runRequestHandler(terminate chan struct{}, done chan struct{ req.Res <- bytes.NewReader([]byte(cnt)) }() - case strings.HasSuffix(req.Subpath, ".ts"): - base := strings.TrimSuffix(req.Subpath, ".ts") + case strings.HasSuffix(req.FileName, ".ts"): + base := strings.TrimSuffix(req.FileName, ".ts") c.tsMutex.Lock() f, ok := c.tsByName[base] @@ -597,7 +597,7 @@ func (c *Converter) runRequestHandler(terminate chan struct{}, done chan struct{ req.Res <- f.buf.NewReader() - case req.Subpath == "": + case req.FileName == "": req.W.Header().Add("Access-Control-Allow-Origin", "*") req.Res <- bytes.NewReader([]byte(index)) diff --git a/internal/hlsserver/server.go b/internal/hlsserver/server.go index e603feba..586a414f 100644 --- a/internal/hlsserver/server.go +++ b/internal/hlsserver/server.go @@ -5,6 +5,7 @@ import ( "io" "net" "net/http" + "path" "strings" "sync" "time" @@ -143,27 +144,35 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.Log(logger.Info, "[conn %v] %s %s", r.RemoteAddr, r.Method, r.URL.Path) // remove leading prefix - path := r.URL.Path[1:] + pa := r.URL.Path[1:] - if path == "" || path == "favicon.ico" { + if pa == "" || pa == "favicon.ico" { w.WriteHeader(http.StatusNotFound) return } - parts := strings.SplitN(path, "/", 2) - if len(parts) < 2 { - w.Header().Add("Location", parts[0]+"/") + pa, fname := func() (string, string) { + if strings.HasSuffix(pa, ".ts") || strings.HasSuffix(pa, ".m3u8") { + return path.Dir(pa), path.Base(pa) + } + return pa, "" + }() + + if fname == "" && !strings.HasSuffix(pa, "/") { + w.Header().Add("Location", "/"+pa+"/") w.WriteHeader(http.StatusMovedPermanently) return } + pa = strings.TrimSuffix(pa, "/") + cres := make(chan io.Reader) hreq := hlsconverter.Request{ - Path: parts[0], - Subpath: parts[1], - Req: r, - W: w, - Res: cres, + Path: pa, + FileName: fname, + Req: r, + W: w, + Res: cres, } select { diff --git a/main_hlsreader_test.go b/main_hlsreader_test.go index 6fba6c12..a86503a8 100644 --- a/main_hlsreader_test.go +++ b/main_hlsreader_test.go @@ -18,7 +18,7 @@ func TestClientHLSRead(t *testing.T) { "-i", "emptyvideo.mkv", "-c", "copy", "-f", "rtsp", - "rtsp://" + ownDockerIP + ":8554/teststream", + "rtsp://" + ownDockerIP + ":8554/test/stream", }) require.NoError(t, err) defer cnt1.close() @@ -26,7 +26,7 @@ func TestClientHLSRead(t *testing.T) { time.Sleep(1 * time.Second) cnt2, err := newContainer("ffmpeg", "dest", []string{ - "-i", "http://" + ownDockerIP + ":8888/teststream/stream.m3u8", + "-i", "http://" + ownDockerIP + ":8888/test/stream/stream.m3u8", "-vframes", "1", "-f", "image2", "-y", "/dev/null",