|
|
// Copyright 2021, Chef. All rights reserved.
|
|
|
// https://github.com/q191201771/lal
|
|
|
//
|
|
|
// Use of this source code is governed by a MIT-style license
|
|
|
// that can be found in the License file.
|
|
|
//
|
|
|
// Author: Chef (191201771@qq.com)
|
|
|
|
|
|
package logic
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
"net/http"
|
|
|
"strings"
|
|
|
|
|
|
"github.com/q191201771/lal/pkg/base"
|
|
|
"github.com/q191201771/lal/pkg/httpflv"
|
|
|
"github.com/q191201771/lal/pkg/httpts"
|
|
|
"github.com/q191201771/naza/pkg/nazalog"
|
|
|
)
|
|
|
|
|
|
type HttpServerHandlerObserver interface {
|
|
|
// 通知上层有新的拉流者
|
|
|
// 返回值: true则允许拉流,false则关闭连接
|
|
|
OnNewHttpflvSubSession(session *httpflv.SubSession) bool
|
|
|
|
|
|
OnDelHttpflvSubSession(session *httpflv.SubSession)
|
|
|
|
|
|
OnNewHttptsSubSession(session *httpts.SubSession) bool
|
|
|
OnDelHttptsSubSession(session *httpts.SubSession)
|
|
|
}
|
|
|
|
|
|
type HttpServerHandler struct {
|
|
|
observer HttpServerHandlerObserver
|
|
|
}
|
|
|
|
|
|
func NewHttpServerHandler(observer HttpServerHandlerObserver) *HttpServerHandler {
|
|
|
return &HttpServerHandler{
|
|
|
observer: observer,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (h *HttpServerHandler) ServeSubSession(writer http.ResponseWriter, req *http.Request) {
|
|
|
var (
|
|
|
isHttps bool
|
|
|
scheme string
|
|
|
)
|
|
|
// TODO(chef) 这里scheme直接使用http和https,没有考虑ws和wss,注意,后续的逻辑可能会依赖此处
|
|
|
if req.TLS == nil {
|
|
|
isHttps = false
|
|
|
scheme = "http"
|
|
|
} else {
|
|
|
isHttps = true
|
|
|
scheme = "https"
|
|
|
}
|
|
|
rawUrl := fmt.Sprintf("%s://%s%s", scheme, req.Host, req.RequestURI)
|
|
|
|
|
|
conn, bio, err := writer.(http.Hijacker).Hijack()
|
|
|
if err != nil {
|
|
|
nazalog.Errorf("hijack failed. err=%+v", err)
|
|
|
return
|
|
|
}
|
|
|
if bio.Reader.Buffered() != 0 || bio.Writer.Buffered() != 0 {
|
|
|
nazalog.Errorf("hijack but buffer not empty. rb=%d, wb=%d", bio.Reader.Buffered(), bio.Writer.Buffered())
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
isWebSocket bool
|
|
|
webSocketKey string
|
|
|
)
|
|
|
if req.Header.Get("Connection") == "Upgrade" && req.Header.Get("Upgrade") == "websocket" {
|
|
|
isWebSocket = true
|
|
|
webSocketKey = req.Header.Get("Sec-WebSocket-Key")
|
|
|
}
|
|
|
|
|
|
if strings.HasSuffix(rawUrl, ".flv") {
|
|
|
urlCtx, err := base.ParseHttpUrl(rawUrl, isHttps, ".flv")
|
|
|
if err != nil {
|
|
|
nazalog.Errorf("parse http url failed. err=%+v", err)
|
|
|
_ = conn.Close()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
session := httpflv.NewSubSession(conn, urlCtx, isWebSocket, webSocketKey)
|
|
|
nazalog.Debugf("[%s] < read http request. url=%s", session.UniqueKey(), session.Url())
|
|
|
if !h.observer.OnNewHttpflvSubSession(session) {
|
|
|
session.Dispose()
|
|
|
}
|
|
|
err = session.RunLoop()
|
|
|
nazalog.Debugf("[%s] httpflv sub session loop done. err=%v", session.UniqueKey(), err)
|
|
|
h.observer.OnDelHttpflvSubSession(session)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if strings.HasSuffix(rawUrl, ".ts") {
|
|
|
urlCtx, err := base.ParseHttpUrl(rawUrl, isHttps, ".ts")
|
|
|
if err != nil {
|
|
|
nazalog.Errorf("parse http url failed. err=%+v", err)
|
|
|
_ = conn.Close()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
session := httpts.NewSubSession(conn, urlCtx, isWebSocket, webSocketKey)
|
|
|
nazalog.Debugf("[%s] < read http request. url=%s", session.UniqueKey(), session.Url())
|
|
|
if !h.observer.OnNewHttptsSubSession(session) {
|
|
|
session.Dispose()
|
|
|
}
|
|
|
err = session.RunLoop()
|
|
|
nazalog.Debugf("[%s] httpts sub session loop done. err=%v", session.UniqueKey(), err)
|
|
|
h.observer.OnDelHttptsSubSession(session)
|
|
|
return
|
|
|
}
|
|
|
}
|