浏览代码

Add flag to enable cross domain requests in Api

Add the -api-enable-cors flag when running docker
in daemon mode to allow CORS requests to be made to
the Remote Api.  The default value is false for this
flag to not allow cross origin request to be made.

Also added a handler for OPTIONS requests the standard
for cross domain requests is to initially make an
OPTIONS request to the api.
Michael Crosby 12 年之前
父节点
当前提交
6d5bdff394
共有 5 个文件被更改,包括 56 次插入6 次删除
  1. 13 0
      api.go
  2. 26 0
      api_test.go
  3. 4 3
      docker/docker.go
  4. 8 0
      docs/sources/api/docker_remote_api.rst
  5. 5 3
      server.go

+ 13 - 0
api.go

@@ -703,6 +703,11 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
 	return nil
 	return nil
 }
 }
 
 
+func writeCorsHeaders(w http.ResponseWriter, r *http.Request) {
+	w.Header().Add("Access-Control-Allow-Origin", "*")
+	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
+}
+
 func ListenAndServe(addr string, srv *Server, logging bool) error {
 func ListenAndServe(addr string, srv *Server, logging bool) error {
 	r := mux.NewRouter()
 	r := mux.NewRouter()
 	log.Printf("Listening for HTTP on %s\n", addr)
 	log.Printf("Listening for HTTP on %s\n", addr)
@@ -773,12 +778,20 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
 					w.WriteHeader(http.StatusNotFound)
 					w.WriteHeader(http.StatusNotFound)
 					return
 					return
 				}
 				}
+				if srv.enableCors {
+					writeCorsHeaders(w, r)
+				}
 				if err := localFct(srv, version, w, r, mux.Vars(r)); err != nil {
 				if err := localFct(srv, version, w, r, mux.Vars(r)); err != nil {
 					httpError(w, err)
 					httpError(w, err)
 				}
 				}
 			}
 			}
 			r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
 			r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
 			r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
 			r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
+			r.Methods("OPTIONS").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				if srv.enableCors {
+					writeCorsHeaders(w, r)
+				}
+			})
 		}
 		}
 	}
 	}
 	return http.ListenAndServe(addr, r)
 	return http.ListenAndServe(addr, r)

+ 26 - 0
api_test.go

@@ -1239,6 +1239,32 @@ func TestDeleteContainers(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestGetEnabledCors(t *testing.T) {
+	runtime, err := newTestRuntime()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(runtime)
+
+	srv := &Server{runtime: runtime, enableCors: true}
+
+	r := httptest.NewRecorder()
+
+	if err := getVersion(srv, API_VERSION, r, nil, nil); err != nil {
+		t.Fatal(err)
+	}
+
+	allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
+	allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
+
+	if allowOrigin != "*" {
+		t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
+	}
+	if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept" {
+		t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept\", %s found.", allowHeaders)
+	}
+}
+
 func TestDeleteImages(t *testing.T) {
 func TestDeleteImages(t *testing.T) {
 	//FIXME: Implement this test
 	//FIXME: Implement this test
 	t.Log("Test not implemented")
 	t.Log("Test not implemented")

+ 4 - 3
docker/docker.go

@@ -33,6 +33,7 @@ func main() {
 	bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
 	bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
 	pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
 	pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
 	flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to")
 	flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to")
+	flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
 	flag.Parse()
 	flag.Parse()
 	if *bridgeName != "" {
 	if *bridgeName != "" {
 		docker.NetworkBridgeIface = *bridgeName
 		docker.NetworkBridgeIface = *bridgeName
@@ -65,7 +66,7 @@ func main() {
 			flag.Usage()
 			flag.Usage()
 			return
 			return
 		}
 		}
-		if err := daemon(*pidfile, host, port, *flAutoRestart); err != nil {
+		if err := daemon(*pidfile, host, port, *flAutoRestart, *flEnableCors); err != nil {
 			log.Fatal(err)
 			log.Fatal(err)
 			os.Exit(-1)
 			os.Exit(-1)
 		}
 		}
@@ -104,7 +105,7 @@ func removePidFile(pidfile string) {
 	}
 	}
 }
 }
 
 
-func daemon(pidfile, addr string, port int, autoRestart bool) error {
+func daemon(pidfile, addr string, port int, autoRestart, enableCors bool) error {
 	if addr != "127.0.0.1" {
 	if addr != "127.0.0.1" {
 		log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
 		log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
 	}
 	}
@@ -122,7 +123,7 @@ func daemon(pidfile, addr string, port int, autoRestart bool) error {
 		os.Exit(0)
 		os.Exit(0)
 	}()
 	}()
 
 
-	server, err := docker.NewServer(autoRestart)
+	server, err := docker.NewServer(autoRestart, enableCors)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 8 - 0
docs/sources/api/docker_remote_api.rst

@@ -1056,3 +1056,11 @@ Here are the steps of 'docker run' :
 
 
 In this first version of the API, some of the endpoints, like /attach, /pull or /push uses hijacking to transport stdin,
 In this first version of the API, some of the endpoints, like /attach, /pull or /push uses hijacking to transport stdin,
 stdout and stderr on the same socket. This might change in the future.
 stdout and stderr on the same socket. 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.
+    
+    docker -d -H="192.168.1.9:4243" -api-enable-cors

+ 5 - 3
server.go

@@ -870,7 +870,7 @@ func (srv *Server) ImageInspect(name string) (*Image, error) {
 	return nil, fmt.Errorf("No such image: %s", name)
 	return nil, fmt.Errorf("No such image: %s", name)
 }
 }
 
 
-func NewServer(autoRestart bool) (*Server, error) {
+func NewServer(autoRestart, enableCors bool) (*Server, error) {
 	if runtime.GOARCH != "amd64" {
 	if runtime.GOARCH != "amd64" {
 		log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
 		log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
 	}
 	}
@@ -879,12 +879,14 @@ func NewServer(autoRestart bool) (*Server, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 	srv := &Server{
 	srv := &Server{
-		runtime: runtime,
+		runtime:    runtime,
+		enableCors: enableCors,
 	}
 	}
 	runtime.srv = srv
 	runtime.srv = srv
 	return srv, nil
 	return srv, nil
 }
 }
 
 
 type Server struct {
 type Server struct {
-	runtime *Runtime
+	runtime    *Runtime
+	enableCors bool
 }
 }