// where prefix is like "/" or "/s3/" for e.g. "/camli/" or "/s3/camli/*" func makeCamliHandler(prefix, baseURL string, storage blobserver.Storage, hf blobserver.FindHandlerByTyper) http.Handler { if !strings.HasSuffix(prefix, "/") { panic("expected prefix to end in slash") } baseURL = strings.TrimRight(baseURL, "/") canLongPoll := true // TODO(bradfitz): set to false if this is App Engine, or provide some way to disable storageConfig := &storageAndConfig{ storage, &blobserver.Config{ Writable: true, Readable: true, IsQueue: false, URLBase: baseURL + prefix[:len(prefix)-1], CanLongPoll: canLongPoll, HandlerFinder: hf, }, } return http.HandlerFunc(func(conn http.ResponseWriter, req *http.Request) { action, err := parseCamliPath(req.URL.Path[len(prefix)-1:]) if err != nil { log.Printf("Invalid request for method %q, path %q", req.Method, req.URL.Path) unsupportedHandler(conn, req) return } handler := auth.RequireAuth(camliHandlerUsingStorage(req, action, storageConfig)) handler(conn, req) }) }
func handleCamliUsingStorage(conn http.ResponseWriter, req *http.Request, action string, storage blobserver.StorageConfiger) { handler := unsupportedHandler switch req.Method { case "GET": switch action { case "enumerate-blobs": handler = auth.RequireAuth(handlers.CreateEnumerateHandler(storage)) case "stat": handler = auth.RequireAuth(handlers.CreateStatHandler(storage)) default: handler = handlers.CreateGetHandler(storage) } case "POST": switch action { case "stat": handler = auth.RequireAuth(handlers.CreateStatHandler(storage)) case "upload": handler = auth.RequireAuth(handlers.CreateUploadHandler(storage)) case "remove": handler = auth.RequireAuth(handlers.CreateRemoveHandler(storage)) } case "PUT": // no longer part of spec handler = auth.RequireAuth(handlers.CreateNonStandardPutHandler(storage)) } handler(conn, req) }
func handleCamliUsingStorage(conn http.ResponseWriter, req *http.Request, action string, storage blobserver.StorageConfiger) { handler := unsupportedHandler switch req.Method { case "GET": switch action { case "enumerate-blobs": handler = auth.RequireAuth(handlers.CreateEnumerateHandler(storage), auth.OpGet) case "stat": handler = auth.RequireAuth(handlers.CreateStatHandler(storage), auth.OpAll) default: handler = gethandler.CreateGetHandler(storage) } case "POST": switch action { case "stat": handler = auth.RequireAuth(handlers.CreateStatHandler(storage), auth.OpStat) case "upload": handler = auth.RequireAuth(handlers.CreateUploadHandler(storage), auth.OpUpload) case "remove": handler = auth.RequireAuth(handlers.CreateRemoveHandler(storage), auth.OpAll) } // TODO: delete. Replaced with upload helper endpoint. case "PUT": // no longer part of spec handler = auth.RequireAuth(handlers.CreateNonStandardPutHandler(storage), auth.OpAll) } handler(conn, req) }
func handleCamliUsingStorage(conn http.ResponseWriter, req *http.Request, action string, storage blobserver.StorageConfiger) { handler := unsupportedHandler switch req.Method { case "GET": switch action { case "enumerate-blobs": handler = auth.RequireAuth(handlers.CreateEnumerateHandler(storage), auth.OpGet) case "stat": handler = auth.RequireAuth(handlers.CreateStatHandler(storage), auth.OpAll) default: handler = gethandler.CreateGetHandler(storage) } case "POST": switch action { case "stat": handler = auth.RequireAuth(handlers.CreateStatHandler(storage), auth.OpStat) case "upload": handler = auth.RequireAuth(handlers.CreateUploadHandler(storage), auth.OpUpload) case "remove": handler = auth.RequireAuth(handlers.CreateRemoveHandler(storage), auth.OpAll) } } handler(conn, req) }
func handleCamliSig(conn http.ResponseWriter, req *http.Request) { handler := func(conn http.ResponseWriter, req *http.Request) { httputil.BadRequestError(conn, "Unsupported path or method.") } switch req.Method { case "POST": switch req.URL.Path { case "/camli/sig/sign": handler = auth.RequireAuth(handleSign) case "/camli/sig/verify": handler = handleVerify } } handler(conn, req) }
// InstallHandlers creates and registers all the HTTP Handlers needed by config // into the provided HandlerInstaller. // // baseURL is required and specifies the root of this webserver, without trailing slash. // context may be nil (used and required by App Engine only) // // The returned shutdown value can be used to cleanly shut down the // handlers. func (config *Config) InstallHandlers(hi HandlerInstaller, baseURL string, reindex bool, context *http.Request) (shutdown io.Closer, err error) { defer func() { if e := recover(); e != nil { log.Printf("Caught panic installer handlers: %v", e) err = fmt.Errorf("Caught panic: %v", e) } }() if err := config.checkValidAuth(); err != nil { return nil, fmt.Errorf("error while configuring auth: %v", err) } prefixes := config.RequiredObject("prefixes") if err := config.Validate(); err != nil { return nil, fmt.Errorf("configuration error in root object's keys: %v", err) } if v := os.Getenv("CAMLI_PPROF_START"); v != "" { cpuf := mustCreate(v + ".cpu") defer cpuf.Close() memf := mustCreate(v + ".mem") defer memf.Close() rpprof.StartCPUProfile(cpuf) defer rpprof.StopCPUProfile() defer rpprof.WriteHeapProfile(memf) } hl := &handlerLoader{ installer: hi, baseURL: baseURL, config: make(map[string]*handlerConfig), handler: make(map[string]interface{}), context: context, reindex: reindex, } for prefix, vei := range prefixes { if !strings.HasPrefix(prefix, "/") { exitFailure("prefix %q doesn't start with /", prefix) } if !strings.HasSuffix(prefix, "/") { exitFailure("prefix %q doesn't end with /", prefix) } pmap, ok := vei.(map[string]interface{}) if !ok { exitFailure("prefix %q value is a %T, not an object", prefix, vei) } pconf := jsonconfig.Obj(pmap) enabled := pconf.OptionalBool("enabled", true) if !enabled { continue } handlerType := pconf.RequiredString("handler") handlerArgs := pconf.OptionalObject("handlerArgs") internal := pconf.OptionalBool("internal", false) if err := pconf.Validate(); err != nil { exitFailure("configuration error in prefix %s: %v", prefix, err) } h := &handlerConfig{ prefix: prefix, htype: handlerType, conf: handlerArgs, internal: internal, } hl.config[prefix] = h if handlerType == "ui" { config.UIPath = prefix } } hl.setupAll() // Now that everything is setup, run any handlers' InitHandler // methods. // And register apps that will be started later. for pfx, handler := range hl.handler { if starter, ok := handler.(*app.Handler); ok { config.apps = append(config.apps, starter) } if in, ok := handler.(blobserver.HandlerIniter); ok { if err := in.InitHandler(hl); err != nil { return nil, fmt.Errorf("Error calling InitHandler on %s: %v", pfx, err) } } } if v, _ := strconv.ParseBool(os.Getenv("CAMLI_HTTP_EXPVAR")); v { hi.Handle("/debug/vars", expvarHandler{}) } if v, _ := strconv.ParseBool(os.Getenv("CAMLI_HTTP_PPROF")); v { hi.Handle("/debug/pprof/", profileHandler{}) } hi.Handle("/debug/config", auth.RequireAuth(configHandler{config}, auth.OpAll)) hi.Handle("/debug/logs", auth.RequireAuth(http.HandlerFunc(logsHandler), auth.OpAll)) return multiCloser(hl.closers), nil }