78 lines
2.6 KiB
Go
78 lines
2.6 KiB
Go
package server
|
||
|
||
import (
|
||
"net/http"
|
||
"net/http/httputil"
|
||
"net/url"
|
||
"strings"
|
||
)
|
||
|
||
// srsProxyHandler 反向代理 SRS HTTP API(WHIP/WHEP 在 /rtc/v1/)。
|
||
// 信令可反代,媒体由浏览器直连 SRS :8000。推流可按需校验服务端下发的 JWT。
|
||
func (s *Server) srsProxyHandler() http.Handler {
|
||
target, err := url.Parse(s.cfg.SRSBaseURL)
|
||
if err != nil {
|
||
target, _ = url.Parse("http://localhost:1985")
|
||
}
|
||
rp := httputil.NewSingleHostReverseProxy(target)
|
||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
if s.cfg.TokenRequired && strings.HasPrefix(r.URL.Path, "/rtc/v1/whip/") {
|
||
room := r.URL.Query().Get("stream")
|
||
tok := r.URL.Query().Get("token")
|
||
claims, verr := verifyStreamToken(s.cfg.TokenSecret, tok)
|
||
if verr != nil || claims.Room != room || claims.Role != "publish" {
|
||
http.Error(w, "forbidden: valid publish token required", http.StatusForbidden)
|
||
return
|
||
}
|
||
}
|
||
rp.ServeHTTP(w, r)
|
||
})
|
||
}
|
||
|
||
// srsHlsProxyHandler 反向代理 SRS http_server 的 HLS/FLV 静态资源(8080)。
|
||
// 浏览器通过 Go 网关拉 HLS,避免直连 8080 的跨域和端口暴露问题。
|
||
// 支持 /live/*.m3u8 /live/*.ts /live/*.flv
|
||
func (s *Server) srsHlsProxyHandler() http.Handler {
|
||
target, err := url.Parse(s.cfg.SRSHttpURL)
|
||
if err != nil {
|
||
target, _ = url.Parse("http://localhost:8080")
|
||
}
|
||
rp := httputil.NewSingleHostReverseProxy(target)
|
||
origDirector := rp.Director
|
||
rp.Director = func(r *http.Request) {
|
||
origDirector(r)
|
||
}
|
||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||
w.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS")
|
||
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||
if r.Method == http.MethodOptions {
|
||
w.WriteHeader(http.StatusNoContent)
|
||
return
|
||
}
|
||
rp.ServeHTTP(w, r)
|
||
})
|
||
}
|
||
|
||
// cfProxyHandler 反向代理 Cloudflare Realtime REST,注入 AppSecret。
|
||
// 浏览器只交换 SDP(tracks/new),凭证不出服务端。
|
||
func (s *Server) cfProxyHandler() http.Handler {
|
||
base := strings.TrimRight(s.cfg.CFBaseURL, "/") + "/apps/" + s.cfg.CFAppID
|
||
target, err := url.Parse(base)
|
||
if err != nil {
|
||
target, _ = url.Parse("https://rtc.live.cloudflare.com/v1/apps/" + s.cfg.CFAppID)
|
||
}
|
||
rp := httputil.NewSingleHostReverseProxy(target)
|
||
rp.Director = func(r *http.Request) {
|
||
rest := strings.TrimPrefix(r.URL.Path, "/api/cf")
|
||
r.URL.Path = target.Path + rest
|
||
r.URL.Scheme = target.Scheme
|
||
r.URL.Host = target.Host
|
||
r.Host = target.Host
|
||
if s.cfg.CFAppSecret != "" {
|
||
r.Header.Set("Authorization", "Bearer "+s.cfg.CFAppSecret)
|
||
}
|
||
}
|
||
return rp
|
||
}
|