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) }) } // 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 }