* Remote Api: Add flag to enable cross domain requests

This commit is contained in:
Victor Vieux 2013-06-11 10:12:36 +00:00
commit 20bf0e00e8
5 changed files with 119 additions and 10 deletions

38
api.go
View file

@ -703,9 +703,18 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
return nil
}
func ListenAndServe(addr string, srv *Server, logging bool) error {
func optionsHandler(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
w.WriteHeader(http.StatusOK)
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")
w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
}
func createRouter(srv *Server, logging bool) (*mux.Router, error) {
r := mux.NewRouter()
log.Printf("Listening for HTTP on %s\n", addr)
m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
"GET": {
@ -745,6 +754,9 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
"/containers/{name:.*}": deleteContainers,
"/images/{name:.*}": deleteImages,
},
"OPTIONS": {
"": optionsHandler,
},
}
for method, routes := range m {
@ -769,6 +781,9 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
if err != nil {
version = APIVERSION
}
if srv.enableCors {
writeCorsHeaders(w, r)
}
if version == 0 || version > APIVERSION {
w.WriteHeader(http.StatusNotFound)
return
@ -777,9 +792,24 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
httpError(w, err)
}
}
r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
if localRoute == "" {
r.Methods(localMethod).HandlerFunc(f)
} else {
r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
}
}
}
return r, nil
}
func ListenAndServe(addr string, srv *Server, logging bool) error {
log.Printf("Listening for HTTP on %s\n", addr)
r, err := createRouter(srv, logging)
if err != nil {
return err
}
return http.ListenAndServe(addr, r)
}

View file

@ -1239,6 +1239,73 @@ func TestDeleteContainers(t *testing.T) {
}
}
func TestOptionsRoute(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
r := httptest.NewRecorder()
router, err := createRouter(srv, false)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("OPTIONS", "/", nil)
if err != nil {
t.Fatal(err)
}
router.ServeHTTP(r, req)
if r.Code != http.StatusOK {
t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
}
}
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()
router, err := createRouter(srv, false)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("GET", "/version", nil)
if err != nil {
t.Fatal(err)
}
router.ServeHTTP(r, req)
if r.Code != http.StatusOK {
t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
}
allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
allowMethods := r.Header().Get("Access-Control-Allow-Methods")
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)
}
if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
}
}
func TestDeleteImages(t *testing.T) {
//FIXME: Implement this test
t.Log("Test not implemented")

View file

@ -33,6 +33,7 @@ func main() {
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
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")
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
flag.Parse()
if *bridgeName != "" {
docker.NetworkBridgeIface = *bridgeName
@ -65,7 +66,7 @@ func main() {
flag.Usage()
return
}
if err := daemon(*pidfile, host, port, *flAutoRestart); err != nil {
if err := daemon(*pidfile, host, port, *flAutoRestart, *flEnableCors); err != nil {
log.Fatal(err)
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" {
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)
}()
server, err := docker.NewServer(autoRestart)
server, err := docker.NewServer(autoRestart, enableCors)
if err != nil {
return err
}

View file

@ -1057,6 +1057,14 @@ 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,
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
==================================
Docker Remote API Client Libraries
==================================
@ -1080,3 +1088,4 @@ and we will add the libraries here.
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui |
| **WebUI** | | |
+----------------------+----------------+--------------------------------------------+

View file

@ -879,7 +879,7 @@ func (srv *Server) ImageInspect(name string) (*Image, error) {
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" {
log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
}
@ -888,12 +888,14 @@ func NewServer(autoRestart bool) (*Server, error) {
return nil, err
}
srv := &Server{
runtime: runtime,
runtime: runtime,
enableCors: enableCors,
}
runtime.srv = srv
return srv, nil
}
type Server struct {
runtime *Runtime
runtime *Runtime
enableCors bool
}