* Remote Api: Add flag to enable cross domain requests
This commit is contained in:
commit
20bf0e00e8
5 changed files with 119 additions and 10 deletions
38
api.go
38
api.go
|
@ -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)
|
||||
}
|
||||
|
|
67
api_test.go
67
api_test.go
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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** | | |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue