Fix: HEAD requests may keep a stream active forever.

This commit is contained in:
Yifu Yu 2024-03-01 17:34:41 +08:00
parent 04d4e0fc6a
commit 4bb97ee43a
1 changed files with 11 additions and 7 deletions

18
main.go
View File

@ -93,10 +93,9 @@ func NewClientChannel(name string) *ClientChannel {
ctx.newChanLock.Lock() ctx.newChanLock.Lock()
ctx.newClientsChanList.PushBack(ch) ctx.newClientsChanList.PushBack(ch)
ctx.newChanLock.Unlock() ctx.newChanLock.Unlock()
if atomic.AddInt64(&ctx.viewer, 1) == 1 { cntViewer := atomic.AddInt64(&ctx.viewer, 1)
ctx.viewerCond.Broadcast() ctx.viewerCond.Broadcast()
} fmt.Printf("Current viewers for stream %s: %d\n", name, cntViewer)
fmt.Printf("Current viewers for stream %s: %d\n", name, ctx.viewer)
return ch return ch
} }
@ -166,6 +165,7 @@ func broadcastFiber(name string) {
chunk := <-ctx.upstreamChan chunk := <-ctx.upstreamChan
// Send to all existing clients // Send to all existing clients
e := ctx.clientsChanList.Front() e := ctx.clientsChanList.Front()
enumerate_client:
for e != nil { for e != nil {
ch := e.Value.(*ClientChannel) ch := e.Value.(*ClientChannel)
// Note: select in Golang is not ordered! // Note: select in Golang is not ordered!
@ -176,7 +176,7 @@ func broadcastFiber(name string) {
next := e.Next() next := e.Next()
ctx.clientsChanList.Remove(e) ctx.clientsChanList.Remove(e)
e = next e = next
break continue enumerate_client
default: default:
} }
select { select {
@ -200,13 +200,17 @@ func clientHandler(w http.ResponseWriter, r *http.Request) {
remote = r.Header.Get("X-Remote-Addr") remote = r.Header.Get("X-Remote-Addr")
} }
fmt.Printf("Client connection from %s accepted.\n", remote) fmt.Printf("Client connection from %s accepted.\n", remote)
w.Header().Add("Content-Type", "video/MP2T")
w.WriteHeader(200)
name := r.URL.Path name := r.URL.Path
if _, ok := upstreams[name]; !ok { if _, ok := upstreams[name]; !ok {
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
w.Header().Add("Content-Type", "video/MP2T")
w.WriteHeader(200)
if r.Method == http.MethodHead {
// Fuck you golang, you should never eat write but fail
return
}
ch := NewClientChannel(name) ch := NewClientChannel(name)
defer ch.Close() defer ch.Close()
for { for {