diff --git a/api/server/server.go b/api/server/server.go index 5d11da8584..65353c52f8 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -1229,8 +1229,9 @@ func optionsHandler(eng *engine.Engine, version version.Version, w http.Response w.WriteHeader(http.StatusOK) return nil } -func writeCorsHeaders(w http.ResponseWriter, r *http.Request) { - w.Header().Add("Access-Control-Allow-Origin", "*") +func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) { + log.Debugf("CORS header is enabled and set to: %s", corsHeaders) + w.Header().Add("Access-Control-Allow-Origin", corsHeaders) w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth") w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS") } @@ -1240,7 +1241,7 @@ func ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r return err } -func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc { +func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the request log.Debugf("Calling %s %s", localMethod, localRoute) @@ -1259,8 +1260,8 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local if version == "" { version = api.APIVERSION } - if enableCors { - writeCorsHeaders(w, r) + if corsHeaders != "" { + writeCorsHeaders(w, r, corsHeaders) } if version.GreaterThan(api.APIVERSION) { @@ -1302,7 +1303,8 @@ func AttachProfiler(router *mux.Router) { router.HandleFunc("/debug/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP) } -func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion string) *mux.Router { +// we keep enableCors just for legacy usage, need to be removed in the future +func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders string, dockerVersion string) *mux.Router { r := mux.NewRouter() if os.Getenv("DEBUG") != "" { AttachProfiler(r) @@ -1364,6 +1366,12 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st }, } + // If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*" + // otherwise, all head values will be passed to HTTP handler + if corsHeaders == "" && enableCors { + corsHeaders = "*" + } + for method, routes := range m { for route, fct := range routes { log.Debugf("Registering %s, %s", method, route) @@ -1373,7 +1381,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st localMethod := method // build the handler function - f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, enableCors, version.Version(dockerVersion)) + f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, corsHeaders, version.Version(dockerVersion)) // add the new route if localRoute == "" { @@ -1392,7 +1400,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st // FIXME: refactor this to be part of Server and not require re-creating a new // router each time. This requires first moving ListenAndServe into Server. func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) { - router := createRouter(eng, false, true, "") + router := createRouter(eng, false, true, "", "") // Insert APIVERSION into the request as a convenience req.URL.Path = fmt.Sprintf("/v%s%s", apiversion, req.URL.Path) router.ServeHTTP(w, req) @@ -1401,7 +1409,7 @@ func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.Respons // serveFd creates an http.Server and sets it up to serve given a socket activated // argument. func serveFd(addr string, job *engine.Job) error { - r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("CorsHeaders"), job.Getenv("Version")) ls, e := systemd.ListenFD(addr) if e != nil { @@ -1543,7 +1551,7 @@ func setupTcpHttp(addr string, job *engine.Job) (*HttpServer, error) { log.Infof("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") } - r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("CorsHeaders"), job.Getenv("Version")) l, err := newListener("tcp", addr, job.GetenvBool("BufferRequests")) if err != nil { diff --git a/api/server/server_linux.go b/api/server/server_linux.go index 7d312c685b..6cf2c3f185 100644 --- a/api/server/server_linux.go +++ b/api/server/server_linux.go @@ -27,7 +27,7 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) { } func setupUnixHttp(addr string, job *engine.Job) (*HttpServer, error) { - r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("CorsHeaders"), job.Getenv("Version")) if err := syscall.Unlink(addr); err != nil && !os.IsNotExist(err) { return nil, err diff --git a/daemon/config.go b/daemon/config.go index 68db93ccfd..94deb3424c 100644 --- a/daemon/config.go +++ b/daemon/config.go @@ -40,6 +40,7 @@ type Config struct { Mtu int SocketGroup string EnableCors bool + CorsHeaders string DisableNetwork bool EnableSelinuxSupport bool Context map[string][]string @@ -70,7 +71,8 @@ func (config *Config) InstallFlags() { flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support") flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU") flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket") - flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") + flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header") + flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API") opts.IPVar(&config.DefaultIp, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports") opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options") // FIXME: why the inconsistency between "hosts" and "sockets"? diff --git a/docker/daemon.go b/docker/daemon.go index b130f8b485..5f799a46a5 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -131,6 +131,7 @@ func mainDaemon() { job := eng.Job("serveapi", flHosts...) job.SetenvBool("Logging", true) job.SetenvBool("EnableCors", daemonCfg.EnableCors) + job.Setenv("CorsHeaders", daemonCfg.CorsHeaders) job.Setenv("Version", dockerversion.VERSION) job.Setenv("SocketGroup", daemonCfg.SocketGroup) diff --git a/docs/man/docker.1.md b/docs/man/docker.1.md index b547b1f693..4a6d0cf152 100644 --- a/docs/man/docker.1.md +++ b/docs/man/docker.1.md @@ -37,6 +37,9 @@ unix://[/path/to/socket] to use. **--api-enable-cors**=*true*|*false* Enable CORS headers in the remote API. Default is false. +**--api-cors-header**="" + Set CORS headers in the remote API. Default is cors disabled. Give urls like "http://foo, http://bar, ...". Give "*" to allow all. + **-b**="" Attach containers to a pre\-existing network bridge; use 'none' to disable container networking diff --git a/docs/sources/reference/api/docker_remote_api_v1.17.md b/docs/sources/reference/api/docker_remote_api_v1.17.md index b317351811..96887559c2 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.17.md +++ b/docs/sources/reference/api/docker_remote_api_v1.17.md @@ -1968,7 +1968,7 @@ This might change in the future. ## 3.3 CORS Requests -To enable cross origin requests to the remote api add the flag -"--api-enable-cors" when running docker in daemon mode. +To set cross origin requests to the remote api, please add flag "--api-enable-cors" +when running docker in daemon mode. - $ docker -d -H="192.168.1.9:2375" --api-enable-cors + $ docker -d -H="192.168.1.9:2375" --api-enable-cors diff --git a/docs/sources/reference/api/docker_remote_api_v1.18.md b/docs/sources/reference/api/docker_remote_api_v1.18.md index c0b06e2125..d5d39fb6f2 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.18.md +++ b/docs/sources/reference/api/docker_remote_api_v1.18.md @@ -1983,7 +1983,8 @@ This might change in the future. ## 3.3 CORS Requests -To enable cross origin requests to the remote api add the flag -"--api-enable-cors" when running docker in daemon mode. +To set cross origin requests to the remote api please give values to +"--api-cors-header" when running docker in daemon mode. Set * will allow all, +default or blank means CORS disabled - $ docker -d -H="192.168.1.9:2375" --api-enable-cors + $ docker -d -H="192.168.1.9:2375" --api-cors-header="http://foo.bar" diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 69f602b4f9..eb61872dae 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -75,6 +75,7 @@ expect an integer, and they can only be specified once. Options: --api-enable-cors=false Enable CORS headers in the remote API + --api-cors-header="" Set CORS headers in the remote API -b, --bridge="" Attach containers to a network bridge --bip="" Specify network bridge IP -D, --debug=false Enable debug mode