From 2810c478a7f2497fad1300ce63c8476bb50a6ad0 Mon Sep 17 00:00:00 2001 From: Boaz Shuster Date: Wed, 2 Jun 2021 23:32:58 +0300 Subject: Add CORS support [NO TESTS NEEDED] Signed-off-by: Boaz Shuster --- cmd/podman/system/service.go | 11 +++++++---- cmd/podman/system/service_abi.go | 2 +- docs/source/markdown/podman-system-service.1.md | 4 ++++ pkg/api/server/handler_api.go | 6 ++++++ pkg/api/server/server.go | 21 +++++++++++++++++---- pkg/domain/entities/system.go | 7 ++++--- 6 files changed, 39 insertions(+), 12 deletions(-) diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go index 63f2de51e..a30f43839 100644 --- a/cmd/podman/system/service.go +++ b/cmd/podman/system/service.go @@ -39,7 +39,8 @@ Enable a listening service for API access to Podman commands. } srvArgs = struct { - Timeout int64 + Timeout int64 + CorsHeaders string }{} ) @@ -54,6 +55,8 @@ func init() { timeFlagName := "time" flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout") _ = srvCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone) + flags.StringVarP(&srvArgs.CorsHeaders, "cors", "", "", "Set CORS Headers") + _ = srvCmd.RegisterFlagCompletionFunc("cors", completion.AutocompleteNone) flags.SetNormalizeFunc(aliasTimeoutFlag) } @@ -71,7 +74,6 @@ func service(cmd *cobra.Command, args []string) error { return err } logrus.Infof("using API endpoint: '%s'", apiURI) - // Clean up any old existing unix domain socket if len(apiURI) > 0 { uri, err := url.Parse(apiURI) @@ -90,8 +92,9 @@ func service(cmd *cobra.Command, args []string) error { } opts := entities.ServiceOptions{ - URI: apiURI, - Command: cmd, + URI: apiURI, + Command: cmd, + CorsHeaders: srvArgs.CorsHeaders, } opts.Timeout = time.Duration(srvArgs.Timeout) * time.Second diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go index 364663323..d59a45564 100644 --- a/cmd/podman/system/service_abi.go +++ b/cmd/podman/system/service_abi.go @@ -72,7 +72,7 @@ func restService(opts entities.ServiceOptions, flags *pflag.FlagSet, cfg *entiti } infra.StartWatcher(rt) - server, err := api.NewServerWithSettings(rt, opts.Timeout, listener) + server, err := api.NewServerWithSettings(rt, listener, api.Options{Timeout: opts.Timeout, CorsHeaders: opts.CorsHeaders}) if err != nil { return err } diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md index 2c8be73c2..dfb026de1 100644 --- a/docs/source/markdown/podman-system-service.1.md +++ b/docs/source/markdown/podman-system-service.1.md @@ -30,6 +30,10 @@ Note: The default systemd unit files (system and user) change the log-level opti The time until the session expires in _seconds_. The default is 5 seconds. A value of `0` means no timeout, therefore the session will not expire. +#### **--cors** + +CORS headers to inject to the HTTP response. The default value is empty string which disables CORS headers. + #### **--help**, **-h** Print usage statement. diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go index 28b8706a8..becc674c0 100644 --- a/pkg/api/server/handler_api.go +++ b/pkg/api/server/handler_api.go @@ -63,6 +63,12 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc { w.Header().Set("Libpod-API-Version", lv) w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")") + if s.CorsHeaders != "" { + w.Header().Set("Access-Control-Allow-Origin", s.CorsHeaders) + w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth, Connection, Upgrade, X-Registry-Config") + w.Header().Set("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS") + } + h(w, r) logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String()) } diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go index 972541bc6..1e8faf8f5 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -34,10 +34,12 @@ type APIServer struct { context.CancelFunc // Stop APIServer idleTracker *idle.Tracker // Track connections to support idle shutdown pprof *http.Server // Sidecar http server for providing performance data + CorsHeaders string // Inject CORS headers to each request } // Number of seconds to wait for next request, if exceeded shutdown server const ( + DefaultCorsHeaders = "" DefaultServiceDuration = 300 * time.Second UnlimitedServiceDuration = 0 * time.Second ) @@ -45,17 +47,22 @@ const ( // shutdownOnce ensures Shutdown() may safely be called from several go routines var shutdownOnce sync.Once +type Options struct { + Timeout time.Duration + CorsHeaders string +} + // NewServer will create and configure a new API server with all defaults func NewServer(runtime *libpod.Runtime) (*APIServer, error) { - return newServer(runtime, DefaultServiceDuration, nil) + return newServer(runtime, DefaultServiceDuration, nil, DefaultCorsHeaders) } // NewServerWithSettings will create and configure a new API server using provided settings -func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) { - return newServer(runtime, duration, listener) +func NewServerWithSettings(runtime *libpod.Runtime, listener *net.Listener, opts Options) (*APIServer, error) { + return newServer(runtime, opts.Timeout, listener, opts.CorsHeaders) } -func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) { +func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener, corsHeaders string) (*APIServer, error) { // If listener not provided try socket activation protocol if listener == nil { if _, found := os.LookupEnv("LISTEN_PID"); !found { @@ -71,6 +78,11 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li } listener = &listeners[0] } + if corsHeaders == "" { + logrus.Debug("CORS Headers were not set") + } else { + logrus.Debugf("CORS Headers were set to %s", corsHeaders) + } logrus.Infof("API server listening on %q", (*listener).Addr()) router := mux.NewRouter().UseEncodedPath() @@ -88,6 +100,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li idleTracker: idle, Listener: *listener, Runtime: runtime, + CorsHeaders: corsHeaders, } router.NotFoundHandler = http.HandlerFunc( diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go index 31a6185dc..cca4bf44e 100644 --- a/pkg/domain/entities/system.go +++ b/pkg/domain/entities/system.go @@ -11,9 +11,10 @@ import ( // ServiceOptions provides the input for starting an API Service type ServiceOptions struct { - URI string // Path to unix domain socket service should listen on - Timeout time.Duration // duration of inactivity the service should wait before shutting down - Command *cobra.Command // CLI command provided. Used in V1 code + URI string // Path to unix domain socket service should listen on + Timeout time.Duration // duration of inactivity the service should wait before shutting down + Command *cobra.Command // CLI command provided. Used in V1 code + CorsHeaders string // CORS headers } // SystemPruneOptions provides options to prune system. -- cgit v1.2.3-54-g00ecf