// repoSelector retrieves the particular repo from a potentially partial string that uniquely // identifies the repo. func repoSelector(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { action := strings.ToLower(r.Method) if readonly && action != "get" && action != "head" { BadRequest(w, r, "Server in read-only mode and will only accept GET and HEAD requests") return } var err error var uuid dvid.UUID if uuid, c.Env["versionID"], err = datastore.MatchingUUID(c.URLParams["uuid"]); err != nil { BadRequest(w, r, err) return } c.Env["uuid"] = uuid // Make sure locked nodes can't use anything besides GET and HEAD locked, err := datastore.LockedUUID(uuid) if err != nil { BadRequest(w, r, err) return } branchRequest := (c.URLParams["action"] == "branch") mergeRequest := (c.URLParams["action"] == "merge") if locked && !branchRequest && !mergeRequest && action != "get" && action != "head" { BadRequest(w, r, "Cannot do %s on locked node %s", action, uuid) return } h.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func repoCommitStateHandler(c web.C, w http.ResponseWriter, r *http.Request) { uuid := c.Env["uuid"].(dvid.UUID) locked, err := datastore.LockedUUID(uuid) if err != nil { BadRequest(w, r, err) } else { w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"Locked":%t}`, locked) } }
// nodeSelector identifies a node, and imposes restrictions depending on read-only mode and locked nodes. func nodeSelector(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { uuid, ok := c.Env["uuid"].(dvid.UUID) if !ok { msg := fmt.Sprintf("Bad format for UUID %q\n", c.Env["uuid"]) BadRequest(w, r, msg) return } // Make sure locked nodes can't use anything besides GET and HEAD unless we are deleting whole repo. locked, err := datastore.LockedUUID(uuid) if err != nil { BadRequest(w, r, err) return } action := strings.ToLower(r.Method) branchRequest := (c.URLParams["action"] == "branch") if locked && !branchRequest && action != "get" && action != "head" { BadRequest(w, r, "Cannot do %s on locked node %s", action, uuid) return } h.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
// instanceSelector retrieves the data instance given its complete string name and // forwards the request to that instance's HTTP handler. func instanceSelector(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { if httpUnavailable(w) { return } var err error dataname := dvid.InstanceName(c.URLParams["dataname"]) uuid, ok := c.Env["uuid"].(dvid.UUID) if !ok { msg := fmt.Sprintf("Bad format for UUID %q\n", c.Env["uuid"]) BadRequest(w, r, msg) return } data, err := datastore.GetDataByUUIDName(uuid, dataname) if err != nil { BadRequest(w, r, err) return } v, err := datastore.VersionFromUUID(uuid) if err != nil { BadRequest(w, r, err) return } if data.Versioned() { // Make sure we aren't trying mutable methods on committed nodes. locked, err := datastore.LockedUUID(uuid) if err != nil { BadRequest(w, r, err) return } if locked && data.IsMutationRequest(r.Method, c.URLParams["keyword"]) { BadRequest(w, r, "Cannot do %s on endpoint %q of locked node %s", r.Method, c.URLParams["keyword"], uuid) return } } else { // Map everything to root version. v, err = datastore.GetRepoRootVersion(v) if err != nil { BadRequest(w, r, err) return } } ctx := datastore.NewVersionedCtx(data, v) // Also set the web request information in case logging needs it downstream. ctx.SetRequestID(middleware.GetReqID(*c)) // Handle DVID-wide query string commands like non-interactive call designations queryStrings := r.URL.Query() // All HTTP requests are interactive so let server tally request. interactive := queryStrings.Get("interactive") if interactive == "" || (interactive != "false" && interactive != "0") { GotInteractiveRequest() } // TODO: setup routing for data instances as well. if config != nil && config.AllowTiming() { w.Header().Set("Timing-Allow-Origin", "*") } data.ServeHTTP(uuid, ctx, w, r) } return http.HandlerFunc(fn) }