diff --git a/README.md b/README.md index e7a39768..c5c31e60 100644 --- a/README.md +++ b/README.md @@ -313,9 +313,10 @@ The HTTP API is the main part for interacting with the application. Default addr ```yaml api: - listen: ":1984" # HTTP API port ("" - disabled) - base_path: "" # API prefix for serve on suburl - static_dir: "" # folder for static files (custom web interface) + listen: ":1984" # HTTP API port ("" - disabled) + base_path: "/rtc" # API prefix for serve on suburl (/api => /rtc/api) + static_dir: "www" # folder for static files (custom web interface) + origin: "*" # allow CORS requests (only * supported) ``` **PS. go2rtc** doesn't provide HTTPS or password protection. Use [Nginx](https://nginx.org/) or [Ngrok](#module-ngrok) or [Home Assistant Add-on](#go2rtc-home-assistant-add-on) for this tasks. diff --git a/cmd/api/api.go b/cmd/api/api.go index e73353f5..3158c128 100644 --- a/cmd/api/api.go +++ b/cmd/api/api.go @@ -17,6 +17,7 @@ func Init() { Listen string `yaml:"listen"` BasePath string `yaml:"base_path"` StaticDir string `yaml:"static_dir"` + Origin string `yaml:"origin"` } `yaml:"api"` } @@ -34,7 +35,7 @@ func Init() { log = app.GetLogger("api") initStatic(cfg.Mod.StaticDir) - initWS() + initWS(cfg.Mod.Origin) HandleFunc("api/streams", streamsHandler) HandleFunc("api/ws", apiWS) @@ -48,16 +49,18 @@ func Init() { log.Info().Str("addr", cfg.Mod.Listen).Msg("[api] listen") + s := http.Server{} + s.Handler = http.DefaultServeMux + + if log.Trace().Enabled() { + s.Handler = middlewareLog(s.Handler) + } + + if cfg.Mod.Origin == "*" { + s.Handler = middlewareCORS(s.Handler) + } + go func() { - s := http.Server{} - - if log.Trace().Enabled() { - s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Trace().Stringer("url", r.URL).Msgf("[api] %s", r.Method) - http.DefaultServeMux.ServeHTTP(w, r) - }) - } - if err = s.Serve(listener); err != nil { log.Fatal().Err(err).Msg("[api] serve") } @@ -83,10 +86,25 @@ var basePath string var log zerolog.Logger var wsHandlers = make(map[string]WSHandler) +func middlewareLog(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Trace().Msgf("[api] %s %s", r.Method, r.URL) + next.ServeHTTP(w, r) + }) +} + +func middlewareCORS(next http.Handler) http.Handler { + 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, POST, PUT, DELETE, OPTIONS") + next.ServeHTTP(w, r) + }) +} + func streamsHandler(w http.ResponseWriter, r *http.Request) { src := r.URL.Query().Get("src") name := r.URL.Query().Get("name") - + if name == "" { name = src } diff --git a/cmd/api/ws.go b/cmd/api/ws.go index 0c8ab228..09d90190 100644 --- a/cmd/api/ws.go +++ b/cmd/api/ws.go @@ -4,35 +4,19 @@ import ( "github.com/AlexxIT/go2rtc/pkg/streamer" "github.com/gorilla/websocket" "net/http" - "net/url" - "strings" "sync" ) -func initWS() { +func initWS(origin string) { wsUp = &websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 512000, } - wsUp.CheckOrigin = func(r *http.Request) bool { - origin := r.Header["Origin"] - if len(origin) == 0 { + + if origin == "*" { + wsUp.CheckOrigin = func(r *http.Request) bool { return true } - o, err := url.Parse(origin[0]) - if err != nil { - return false - } - if o.Host == r.Host { - return true - } - log.Trace().Msgf("[api.ws] origin: %s, host: %s", o.Host, r.Host) - // some users change Nginx external port using Docker port - // so origin will be with a port and host without - if i := strings.IndexByte(o.Host, ':'); i > 0 { - return o.Host[:i] == r.Host - } - return false } }