Example #1
0
// 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)
	})
}
Example #2
0
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)
}
Example #3
0
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)
}
Example #4
0
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)
}
Example #5
0
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)
}
Example #6
0
// 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
}