func newV2RegistryRouter() *mux.Router { router := mux.NewRouter() v2Router := router.PathPrefix("/v2/").Subrouter() // Version Info v2Router.Path("/version").Name("version") // Image Manifests v2Router.Path("/manifest/{imagename:[a-z0-9-._/]+}/{tagname:[a-zA-Z0-9-._]+}").Name("manifests") // List Image Tags v2Router.Path("/tags/{imagename:[a-z0-9-._/]+}").Name("tags") // Download a blob v2Router.Path("/blob/{imagename:[a-z0-9-._/]+}/{sumtype:[a-z0-9._+-]+}/{sum:[a-fA-F0-9]{4,}}").Name("downloadBlob") // Upload a blob v2Router.Path("/blob/{imagename:[a-z0-9-._/]+}/{sumtype:[a-z0-9._+-]+}").Name("uploadBlob") // Mounting a blob in an image v2Router.Path("/mountblob/{imagename:[a-z0-9-._/]+}/{sumtype:[a-z0-9._+-]+}/{sum:[a-fA-F0-9]{4,}}").Name("mountBlob") return router }
// RouterWithPrefix builds a gorilla router with a configured prefix // on all routes. func RouterWithPrefix(prefix string) *mux.Router { rootRouter := mux.NewRouter() router := rootRouter if prefix != "" { router = router.PathPrefix(prefix).Subrouter() } router.StrictSlash(true) for _, descriptor := range routeDescriptors { router.Path(descriptor.Path).Name(descriptor.Name) } return rootRouter }
func init() { r := mux.NewRouter() // /v1/ r.HandleFunc("/v1/_ping", handlerGetPing).Methods("GET") r.HandleFunc("/v1/images/{image_id:[^/]+}/{action:json|layer|ancestry}", handlerGetImage).Methods("GET") r.HandleFunc("/v1/images/{image_id:[^/]+}/{action:json|layer|checksum}", handlerPutImage).Methods("PUT") r.HandleFunc("/v1/repositories/{repository:.+}/tags", handlerGetDeleteTags).Methods("GET", "DELETE") r.HandleFunc("/v1/repositories/{repository:.+}/tags/{tag:.+}", handlerGetTag).Methods("GET") r.HandleFunc("/v1/repositories/{repository:.+}/tags/{tag:.+}", handlerPutTag).Methods("PUT") r.HandleFunc("/v1/users{null:.*}", handlerUsers).Methods("GET", "POST", "PUT") r.HandleFunc("/v1/repositories/{repository:.+}{action:/images|/}", handlerImages).Methods("GET", "PUT", "DELETE") r.HandleFunc("/v1/repositories/{repository:.+}/auth", handlerAuth).Methods("PUT") r.HandleFunc("/v1/search", handlerSearch).Methods("GET") // /v2/ r.HandleFunc("/v2/version", handlerGetPing).Methods("GET") testHTTPServer = httptest.NewServer(handlerAccessLog(r)) URL, err := url.Parse(testHTTPServer.URL) if err != nil { panic(err) } insecureRegistries = []string{URL.Host} // override net.LookupIP lookupIP = func(host string) ([]net.IP, error) { if host == "127.0.0.1" { // I believe in future Go versions this will fail, so let's fix it later return net.LookupIP(host) } for h, addrs := range mockHosts { if host == h { return addrs, nil } for _, addr := range addrs { if addr.String() == host { return []net.IP{addr}, nil } } } return nil, errors.New("lookup: no such host") } }
// Router builds a gorilla router with named routes for the various API // methods. This can be used directly by both server implementations and // clients. func Router() *mux.Router { router := mux.NewRouter(). StrictSlash(true) // GET /v2/ Check Check that the registry implements API version 2(.1) router. Path("/v2/"). Name(RouteNameBase) // GET /v2/<name>/manifest/<reference> Image Manifest Fetch the image manifest identified by name and reference where reference can be a tag or digest. // PUT /v2/<name>/manifest/<reference> Image Manifest Upload the image manifest identified by name and reference where reference can be a tag or digest. // DELETE /v2/<name>/manifest/<reference> Image Manifest Delete the image identified by name and reference where reference can be a tag or digest. router. Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/manifests/{reference:" + TagNameRegexp.String() + "|" + DigestRegexp.String() + "}"). Name(RouteNameManifest) // GET /v2/<name>/tags/list Tags Fetch the tags under the repository identified by name. router. Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/tags/list"). Name(RouteNameTags) // GET /v2/<name>/blob/<digest> Layer Fetch the blob identified by digest. router. Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/{digest:[a-zA-Z0-9-_+.]+:[a-zA-Z0-9-_+.=]+}"). Name(RouteNameBlob) // POST /v2/<name>/blob/upload/ Layer Upload Initiate an upload of the layer identified by tarsum. router. Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/"). Name(RouteNameBlobUpload) // GET /v2/<name>/blob/upload/<uuid> Layer Upload Get the status of the upload identified by tarsum and uuid. // PUT /v2/<name>/blob/upload/<uuid> Layer Upload Upload all or a chunk of the upload identified by tarsum and uuid. // DELETE /v2/<name>/blob/upload/<uuid> Layer Upload Cancel the upload identified by layer and uuid router. Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/{uuid}"). Name(RouteNameBlobUploadChunk) return router }
func (s *DockerServer) buildMuxer() { s.mux = mux.NewRouter() s.mux.Path("/commit").Methods("POST").HandlerFunc(s.handlerWrapper(s.commitContainer)) s.mux.Path("/containers/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.listContainers)) s.mux.Path("/containers/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.createContainer)) s.mux.Path("/containers/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectContainer)) s.mux.Path("/containers/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startContainer)) s.mux.Path("/containers/{id:.*}/stop").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer)) s.mux.Path("/containers/{id:.*}/pause").Methods("POST").HandlerFunc(s.handlerWrapper(s.pauseContainer)) s.mux.Path("/containers/{id:.*}/unpause").Methods("POST").HandlerFunc(s.handlerWrapper(s.unpauseContainer)) s.mux.Path("/containers/{id:.*}/wait").Methods("POST").HandlerFunc(s.handlerWrapper(s.waitContainer)) s.mux.Path("/containers/{id:.*}/attach").Methods("POST").HandlerFunc(s.handlerWrapper(s.attachContainer)) s.mux.Path("/containers/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeContainer)) s.mux.Path("/images/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.pullImage)) s.mux.Path("/build").Methods("POST").HandlerFunc(s.handlerWrapper(s.buildImage)) s.mux.Path("/images/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.listImages)) s.mux.Path("/images/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeImage)) s.mux.Path("/images/{name:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectImage)) s.mux.Path("/images/{name:.*}/push").Methods("POST").HandlerFunc(s.handlerWrapper(s.pushImage)) s.mux.Path("/events").Methods("GET").HandlerFunc(s.listEvents) s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker)) }
// 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) } m := map[string]map[string]HttpApiFunc{ "GET": { "/_ping": ping, "/events": getEvents, "/info": getInfo, "/version": getVersion, "/images/json": getImagesJSON, "/images/viz": getImagesViz, "/images/search": getImagesSearch, "/images/get": getImagesGet, "/images/{name:.*}/get": getImagesGet, "/images/{name:.*}/history": getImagesHistory, "/images/{name:.*}/json": getImagesByName, "/containers/ps": getContainersJSON, "/containers/json": getContainersJSON, "/containers/{name:.*}/export": getContainersExport, "/containers/{name:.*}/changes": getContainersChanges, "/containers/{name:.*}/json": getContainersByName, "/containers/{name:.*}/top": getContainersTop, "/containers/{name:.*}/logs": getContainersLogs, "/containers/{name:.*}/stats": getContainersStats, "/containers/{name:.*}/attach/ws": wsContainersAttach, "/exec/{id:.*}/json": getExecByID, }, "POST": { "/auth": postAuth, "/commit": postCommit, "/build": postBuild, "/images/create": postImagesCreate, "/images/load": postImagesLoad, "/images/{name:.*}/push": postImagesPush, "/images/{name:.*}/tag": postImagesTag, "/containers/create": postContainersCreate, "/containers/{name:.*}/kill": postContainersKill, "/containers/{name:.*}/pause": postContainersPause, "/containers/{name:.*}/unpause": postContainersUnpause, "/containers/{name:.*}/restart": postContainersRestart, "/containers/{name:.*}/start": postContainersStart, "/containers/{name:.*}/stop": postContainersStop, "/containers/{name:.*}/wait": postContainersWait, "/containers/{name:.*}/resize": postContainersResize, "/containers/{name:.*}/attach": postContainersAttach, "/containers/{name:.*}/copy": postContainersCopy, "/containers/{name:.*}/exec": postContainerExecCreate, "/exec/{name:.*}/start": postContainerExecStart, "/exec/{name:.*}/resize": postContainerExecResize, "/containers/{name:.*}/rename": postContainerRename, }, "DELETE": { "/containers/{name:.*}": deleteContainers, "/images/{name:.*}": deleteImages, }, "OPTIONS": { "": optionsHandler, }, } // 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) // NOTE: scope issue, make sure the variables are local and won't be changed localRoute := route localFct := fct localMethod := method // build the handler function f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, corsHeaders, version.Version(dockerVersion)) // add the new route 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 }