|
|
|
@ -93,12 +93,17 @@ window.addEventListener('DOMContentLoaded', create); |
|
|
|
</html> |
|
|
|
</html> |
|
|
|
` |
|
|
|
` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type hlsMuxerResponse struct { |
|
|
|
|
|
|
|
Status int |
|
|
|
|
|
|
|
Header map[string]string |
|
|
|
|
|
|
|
Body io.Reader |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type hlsMuxerRequest struct { |
|
|
|
type hlsMuxerRequest struct { |
|
|
|
Dir string |
|
|
|
Dir string |
|
|
|
File string |
|
|
|
File string |
|
|
|
Req *http.Request |
|
|
|
Req *http.Request |
|
|
|
W http.ResponseWriter |
|
|
|
Res chan hlsMuxerResponse |
|
|
|
Res chan io.Reader |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type hlsMuxerTrackIDPayloadPair struct { |
|
|
|
type hlsMuxerTrackIDPayloadPair struct { |
|
|
|
@ -211,7 +216,7 @@ outer: |
|
|
|
|
|
|
|
|
|
|
|
case req := <-r.request: |
|
|
|
case req := <-r.request: |
|
|
|
if isReady { |
|
|
|
if isReady { |
|
|
|
r.handleRequest(req) |
|
|
|
req.Res <- r.handleRequest(req) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
r.requests = append(r.requests, req) |
|
|
|
r.requests = append(r.requests, req) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -219,7 +224,7 @@ outer: |
|
|
|
case <-innerReady: |
|
|
|
case <-innerReady: |
|
|
|
isReady = true |
|
|
|
isReady = true |
|
|
|
for _, req := range r.requests { |
|
|
|
for _, req := range r.requests { |
|
|
|
r.handleRequest(req) |
|
|
|
req.Res <- r.handleRequest(req) |
|
|
|
} |
|
|
|
} |
|
|
|
r.requests = nil |
|
|
|
r.requests = nil |
|
|
|
|
|
|
|
|
|
|
|
@ -235,8 +240,7 @@ outer: |
|
|
|
r.ctxCancel() |
|
|
|
r.ctxCancel() |
|
|
|
|
|
|
|
|
|
|
|
for _, req := range r.requests { |
|
|
|
for _, req := range r.requests { |
|
|
|
req.W.WriteHeader(http.StatusNotFound) |
|
|
|
req.Res <- hlsMuxerResponse{Status: http.StatusNotFound} |
|
|
|
req.Res <- nil |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
r.parent.OnMuxerClose(r) |
|
|
|
r.parent.OnMuxerClose(r) |
|
|
|
@ -397,7 +401,7 @@ func (r *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (r *hlsMuxer) handleRequest(req hlsMuxerRequest) { |
|
|
|
func (r *hlsMuxer) handleRequest(req hlsMuxerRequest) hlsMuxerResponse { |
|
|
|
atomic.StoreInt64(r.lastRequestTime, time.Now().Unix()) |
|
|
|
atomic.StoreInt64(r.lastRequestTime, time.Now().Unix()) |
|
|
|
|
|
|
|
|
|
|
|
conf := r.path.Conf() |
|
|
|
conf := r.path.Conf() |
|
|
|
@ -407,48 +411,66 @@ func (r *hlsMuxer) handleRequest(req hlsMuxerRequest) { |
|
|
|
ip := net.ParseIP(tmp) |
|
|
|
ip := net.ParseIP(tmp) |
|
|
|
if !ipEqualOrInRange(ip, conf.ReadIPs) { |
|
|
|
if !ipEqualOrInRange(ip, conf.ReadIPs) { |
|
|
|
r.log(logger.Info, "ERR: ip '%s' not allowed", ip) |
|
|
|
r.log(logger.Info, "ERR: ip '%s' not allowed", ip) |
|
|
|
req.W.WriteHeader(http.StatusUnauthorized) |
|
|
|
return hlsMuxerResponse{Status: http.StatusUnauthorized} |
|
|
|
req.Res <- nil |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if conf.ReadUser != "" { |
|
|
|
if conf.ReadUser != "" { |
|
|
|
user, pass, ok := req.Req.BasicAuth() |
|
|
|
user, pass, ok := req.Req.BasicAuth() |
|
|
|
if !ok || user != string(conf.ReadUser) || pass != string(conf.ReadPass) { |
|
|
|
if !ok || user != string(conf.ReadUser) || pass != string(conf.ReadPass) { |
|
|
|
req.W.Header().Set("WWW-Authenticate", `Basic realm="rtsp-simple-server"`) |
|
|
|
return hlsMuxerResponse{ |
|
|
|
req.W.WriteHeader(http.StatusUnauthorized) |
|
|
|
Status: http.StatusUnauthorized, |
|
|
|
req.Res <- nil |
|
|
|
Header: map[string]string{ |
|
|
|
return |
|
|
|
"WWW-Authenticate": `Basic realm="rtsp-simple-server"`, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch { |
|
|
|
switch { |
|
|
|
case req.File == "index.m3u8": |
|
|
|
case req.File == "index.m3u8": |
|
|
|
req.W.Header().Set("Content-Type", `application/x-mpegURL`) |
|
|
|
return hlsMuxerResponse{ |
|
|
|
req.Res <- r.muxer.PrimaryPlaylist() |
|
|
|
Status: http.StatusOK, |
|
|
|
|
|
|
|
Header: map[string]string{ |
|
|
|
|
|
|
|
"Content-Type": `application/x-mpegURL`, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Body: r.muxer.PrimaryPlaylist(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case req.File == "stream.m3u8": |
|
|
|
case req.File == "stream.m3u8": |
|
|
|
req.W.Header().Set("Content-Type", `application/x-mpegURL`) |
|
|
|
return hlsMuxerResponse{ |
|
|
|
req.Res <- r.muxer.StreamPlaylist() |
|
|
|
Status: http.StatusOK, |
|
|
|
|
|
|
|
Header: map[string]string{ |
|
|
|
|
|
|
|
"Content-Type": `application/x-mpegURL`, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Body: r.muxer.StreamPlaylist(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case strings.HasSuffix(req.File, ".ts"): |
|
|
|
case strings.HasSuffix(req.File, ".ts"): |
|
|
|
r := r.muxer.Segment(req.File) |
|
|
|
r := r.muxer.Segment(req.File) |
|
|
|
if r == nil { |
|
|
|
if r == nil { |
|
|
|
req.W.WriteHeader(http.StatusNotFound) |
|
|
|
return hlsMuxerResponse{Status: http.StatusNotFound} |
|
|
|
req.Res <- nil |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
req.W.Header().Set("Content-Type", `video/MP2T`) |
|
|
|
return hlsMuxerResponse{ |
|
|
|
req.Res <- r |
|
|
|
Status: http.StatusOK, |
|
|
|
|
|
|
|
Header: map[string]string{ |
|
|
|
|
|
|
|
"Content-Type": `video/MP2T`, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Body: r, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case req.File == "": |
|
|
|
case req.File == "": |
|
|
|
req.Res <- bytes.NewReader([]byte(index)) |
|
|
|
return hlsMuxerResponse{ |
|
|
|
|
|
|
|
Status: http.StatusOK, |
|
|
|
|
|
|
|
Header: map[string]string{ |
|
|
|
|
|
|
|
"Content-Type": `text/html`, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Body: bytes.NewReader([]byte(index)), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|
req.W.WriteHeader(http.StatusNotFound) |
|
|
|
return hlsMuxerResponse{Status: http.StatusNotFound} |
|
|
|
req.Res <- nil |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -457,8 +479,7 @@ func (r *hlsMuxer) OnRequest(req hlsMuxerRequest) { |
|
|
|
select { |
|
|
|
select { |
|
|
|
case r.request <- req: |
|
|
|
case r.request <- req: |
|
|
|
case <-r.ctx.Done(): |
|
|
|
case <-r.ctx.Done(): |
|
|
|
req.W.WriteHeader(http.StatusNotFound) |
|
|
|
req.Res <- hlsMuxerResponse{Status: http.StatusNotFound} |
|
|
|
req.Res <- nil |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|