Ejemplo n.º 1
0
func startSecureServing(opt *options.HeapsterRunOptions, handler http.Handler, promHandler http.Handler,
	mux *http.ServeMux, address string) {

	if len(opt.TLSClientCAFile) > 0 {
		authPprofHandler, err := newAuthHandler(opt, handler)
		if err != nil {
			glog.Fatalf("Failed to create authorized pprof handler: %v", err)
		}
		handler = authPprofHandler

		authPromHandler, err := newAuthHandler(opt, promHandler)
		if err != nil {
			glog.Fatalf("Failed to create authorized prometheus handler: %v", err)
		}
		promHandler = authPromHandler
	}
	mux.Handle("/", handler)
	mux.Handle("/metrics", promHandler)

	// If allowed users is set, then we need to enable Client Authentication
	if len(opt.AllowedUsers) > 0 {
		server := &http.Server{
			Addr:      address,
			Handler:   mux,
			TLSConfig: &tls.Config{ClientAuth: tls.RequestClientCert},
		}
		glog.Fatal(server.ListenAndServeTLS(opt.TLSCertFile, opt.TLSKeyFile))
	} else {
		glog.Fatal(http.ListenAndServeTLS(address, opt.TLSCertFile, opt.TLSKeyFile, mux))
	}
}
Ejemplo n.º 2
0
// newMethodRouter takes the server mux that will dispatch to this router based on the matched path.
func newMethodRouter(mux *http.ServeMux, path string) *methodRouter {
	mr := &methodRouter{
		handlers: map[string]http.Handler{},
	}
	mux.Handle(path, mr)
	return mr
}
Ejemplo n.º 3
0
// HandleFunc registers a handler at the given path. It's
// http.HandleFunc(), but with a wrapper around the handler that
// provides some generic per-request functionality:
//
// * Set a Replay-Nonce header.
//
// * Respond to OPTIONS requests, including CORS preflight requests.
//
// * Set a no cache header
//
// * Respond http.StatusMethodNotAllowed for HTTP methods other than
// those listed.
//
// * Set CORS headers when responding to CORS "actual" requests.
//
// * Never send a body in response to a HEAD request. Anything
// written by the handler will be discarded if the method is HEAD.
// Also, all handlers that accept GET automatically accept HEAD.
func (wfe *WebFrontEndImpl) HandleFunc(mux *http.ServeMux, pattern string, h wfeHandlerFunc, methods ...string) {
	methodsMap := make(map[string]bool)
	for _, m := range methods {
		methodsMap[m] = true
	}
	if methodsMap["GET"] && !methodsMap["HEAD"] {
		// Allow HEAD for any resource that allows GET
		methods = append(methods, "HEAD")
		methodsMap["HEAD"] = true
	}
	methodsStr := strings.Join(methods, ", ")
	handler := http.StripPrefix(pattern, &topHandler{
		log: wfe.log,
		clk: clock.Default(),
		wfe: wfeHandlerFunc(func(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
			// We do not propagate errors here, because (1) they should be
			// transient, and (2) they fail closed.
			nonce, err := wfe.nonceService.Nonce()
			if err == nil {
				response.Header().Set("Replay-Nonce", nonce)
				logEvent.ResponseNonce = nonce
			} else {
				logEvent.AddError("unable to make nonce: %s", err)
			}

			switch request.Method {
			case "HEAD":
				// Go's net/http (and httptest) servers will strip out the body
				// of responses for us. This keeps the Content-Length for HEAD
				// requests as the same as GET requests per the spec.
			case "OPTIONS":
				wfe.Options(response, request, methodsStr, methodsMap)
				return
			}

			// No cache header is set for all requests, succeed or fail.
			addNoCacheHeader(response)

			if !methodsMap[request.Method] {
				response.Header().Set("Allow", methodsStr)
				wfe.sendError(response, logEvent, probs.MethodNotAllowed(), nil)
				return
			}

			wfe.setCORSHeaders(response, request, "")

			timeout := wfe.RequestTimeout
			if timeout == 0 {
				timeout = 5 * time.Minute
			}
			ctx, cancel := context.WithTimeout(ctx, timeout)
			// TODO(riking): add request context using WithValue

			// Call the wrapped handler.
			h(ctx, logEvent, response, request)
			cancel()
		}),
	})
	mux.Handle(pattern, handler)
}
Ejemplo n.º 4
0
Archivo: main.go Proyecto: rmg/tyk
// Create the individual API (app) specs based on live configurations and assign middleware
func loadApps(APISpecs []APISpec, Muxer *http.ServeMux) {
	// load the APi defs
	log.Info("Loading API configurations.")

	for _, spec := range APISpecs {
		// Create a new handler for each API spec
		remote, err := url.Parse(spec.APIDefinition.Proxy.TargetURL)
		if err != nil {
			log.Error("Culdn't parse target URL")
			log.Error(err)
		}

		if spec.UseOauth2 {
			addOAuthHandlers(spec, Muxer, false)
		}

		proxy := TykNewSingleHostReverseProxy(remote)
		spec.target = remote

		proxyHandler := http.HandlerFunc(ProxyHandler(proxy, spec))
		tykMiddleware := TykMiddleware{spec, proxy}

		if spec.APIDefinition.UseKeylessAccess {
			// for KeyLessAccess we can't support rate limiting, versioning or access rules
			chain := alice.New().Then(proxyHandler)
			Muxer.Handle(spec.Proxy.ListenPath, chain)

		} else {

			// Select the keying method to use for setting session states
			var keyCheck func(http.Handler) http.Handler

			if spec.APIDefinition.UseOauth2 {
				// Oauth2
				keyCheck = CreateMiddleware(&Oauth2KeyExists{tykMiddleware}, tykMiddleware)
			} else if spec.APIDefinition.UseBasicAuth {
				// Basic Auth
				keyCheck = CreateMiddleware(&BasicAuthKeyIsValid{tykMiddleware}, tykMiddleware)
			} else if spec.EnableSignatureChecking {
				// HMAC Auth
				keyCheck = CreateMiddleware(&HMACMiddleware{tykMiddleware}, tykMiddleware)
			} else {
				// Auth key
				keyCheck = CreateMiddleware(&AuthKey{tykMiddleware}, tykMiddleware)
			}

			// Use CreateMiddleware(&ModifiedMiddleware{tykMiddleware}, tykMiddleware)  to run custom middleware
			chain := alice.New(
				keyCheck,
				CreateMiddleware(&KeyExpired{tykMiddleware}, tykMiddleware),
				CreateMiddleware(&VersionCheck{tykMiddleware}, tykMiddleware),
				CreateMiddleware(&AccessRightsCheck{tykMiddleware}, tykMiddleware),
				CreateMiddleware(&RateLimitAndQuotaCheck{tykMiddleware}, tykMiddleware)).Then(proxyHandler)

			Muxer.Handle(spec.Proxy.ListenPath, chain)
		}

	}
}
Ejemplo n.º 5
0
func SetupWebsocket(mux *http.ServeMux) chan commons.Notification {
	wsSlice = make([]*webSocketWrapper, 0)
	conChan = make(chan *webSocketWrapper)
	notifChan = make(chan commons.Notification)
	go handleIncomingConnection()
	mux.Handle("/websocket", websocket.Handler(webSocketHandler))
	return notifChan
}
Ejemplo n.º 6
0
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	mux.HandleFunc("/webclock", index)
	mux.Handle("/webclock/ws", websocket.Handler(handle))
	log.Printf("registered webclock at /webclock and /webclock/ws")
}
Ejemplo n.º 7
0
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	mux.HandleFunc("/weechat", handleHome)
	mux.HandleFunc("/weechat/buflines", handleLines)
	mux.Handle("/weechat/ws", ws.Handler(handleWebsocket))
}
Ejemplo n.º 8
0
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	mux.HandleFunc("/irc", home)
	mux.Handle("/irc/ws", websocket.Handler(connect))
	log.Printf("registered irc at /irc and /irc/ws")
}
Ejemplo n.º 9
0
func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
	for source, target := range redirects {
		h := Handler(prefix + target + "/")
		p := prefix + source
		mux.Handle(p, h)
		mux.Handle(p+"/", h)
	}
}
Ejemplo n.º 10
0
func (ah *apiHandler) RegisterPublicDir(mux *http.ServeMux) {
	if ah.conf.PublicDir == "" {
		return
	}
	fs := http.FileServer(http.Dir(ah.conf.PublicDir))
	fs = prometheus.InstrumentHandler("frontend", fs)
	prefix := ah.prefix("")
	mux.Handle(prefix, http.StripPrefix(prefix, fs))
}
Ejemplo n.º 11
0
// Serve all files in the current directory, or only a few select filetypes (html, css, js, png and txt)
func registerHandlers(mux *http.ServeMux, handlePath, servedir string, perm pinterface.IPermissions, luapool *lStatePool, cache *FileCache, addDomain bool) {

	// Handle all requests with this function
	allRequests := func(w http.ResponseWriter, req *http.Request) {
		if perm.Rejected(w, req) {
			// Get and call the Permission Denied function
			perm.DenyFunction()(w, req)
			// Reject the request by returning
			return
		}

		// Local to this function
		servedir := servedir

		// Look for the directory that is named the same as the host
		if addDomain {
			servedir = filepath.Join(servedir, getDomain(req))
		}

		urlpath := req.URL.Path
		filename := url2filename(servedir, urlpath)
		// Remove the trailing slash from the filename, if any
		noslash := filename
		if strings.HasSuffix(filename, pathsep) {
			noslash = filename[:len(filename)-1]
		}
		hasdir := fs.exists(filename) && fs.isDir(filename)
		dirname := filename
		hasfile := fs.exists(noslash)

		// Set the server header.
		serverHeaders(w)

		// Share the directory or file
		if hasdir {
			dirPage(w, req, servedir, dirname, perm, luapool, cache)
			return
		} else if !hasdir && hasfile {
			// Share a single file instead of a directory
			filePage(w, req, noslash, perm, luapool, cache)
			return
		}
		// Not found
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, noPage(filename))
	}

	// Handle requests differently depending on if rate limiting is enabled or not
	if disableRateLimiting {
		mux.HandleFunc(handlePath, allRequests)
	} else {
		limiter := tollbooth.NewLimiter(limitRequests, time.Second)
		limiter.MessageContentType = "text/html; charset=utf-8"
		limiter.Message = easyPage("Rate-limit exceeded", "<div style='color:red'>You have reached the maximum request limit.</div>")
		mux.Handle(handlePath, tollbooth.LimitFuncHandler(limiter, allRequests))
	}
}
Ejemplo n.º 12
0
Archivo: godoc.go Proyecto: tav/go
func registerPublicHandlers(mux *http.ServeMux) {
	mux.Handle(cmdHandler.pattern, &cmdHandler)
	mux.Handle(pkgHandler.pattern, &pkgHandler)
	mux.HandleFunc("/doc/codewalk/", codewalk)
	mux.HandleFunc("/search", search)
	mux.Handle("/robots.txt", fileServer)
	mux.HandleFunc("/opensearch.xml", serveSearchDesc)
	mux.HandleFunc("/", serveFile)
}
Ejemplo n.º 13
0
func NewTHTTPServerFromMux(
	mux *http.ServeMux,
	pattern string,
) (*THTTPServer, error) {
	server := &THTTPServer{deliveries: make(chan *THTTPRequest)}
	mux.Handle(pattern, &HTTPHandler{server})

	return server, nil
}
Ejemplo n.º 14
0
// AddDischargeHandler adds handlers to the given
// ServeMux to serve third party caveat discharges
// using the given service.
//
// The handlers are added under the given rootPath,
// which must be non-empty.
//
// The check function is used to check whether a client making the given
// request should be allowed a discharge for the given caveat. If it
// does not return an error, the caveat will be discharged, with any
// returned caveats also added to the discharge macaroon.
// If it returns an error with a *Error cause, the error will be marshaled
// and sent back to the client.
//
// The name space served by DischargeHandler is as follows.
// All parameters can be provided either as URL attributes
// or form attributes. The result is always formatted as a JSON
// object.
//
// On failure, all endpoints return an error described by
// the Error type.
//
// POST /discharge
//	params:
//		id: id of macaroon to discharge
//		location: location of original macaroon (optional (?))
//		?? flow=redirect|newwindow
//	result on success (http.StatusOK):
//		{
//			Macaroon *macaroon.Macaroon
//		}
//
// GET /publickey
//	result:
//		public key of service
//		expiry time of key
func AddDischargeHandler(mux *http.ServeMux, rootPath string, svc *bakery.Service, checker func(req *http.Request, cavId, cav string) ([]checkers.Caveat, error)) {
	d := &dischargeHandler{
		svc:     svc,
		checker: checker,
	}
	mux.Handle(path.Join(rootPath, "discharge"), mkHandler(handleJSON(d.serveDischarge)))
	// TODO(rog) is there a case for making public key caveat signing
	// optional?
	mux.Handle(path.Join(rootPath, "publickey"), mkHandler(handleJSON(d.servePublicKey)))
}
Ejemplo n.º 15
0
// Configures the server to handler API requests to the default paths.
// If mux is not specified then http.DefaultServeMux is used.
func (ed *EndpointsServer) HandleHttp(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	r := newRouter()
	r.HandleFunc("/_ah/api/explorer", ed.HandleApiExplorerRequest)
	r.HandleFunc("/_ah/api/static", ed.HandleApiStaticRequest)
	r.HandleFunc("/_ah/api/", ed.ServeHTTP)
	mux.Handle("/", r)
}
Ejemplo n.º 16
0
// Configures the server to handler API requests to the default paths.
// If mux is not specified then http.DefaultServeMux is used.
func (ed *EndpointsServer) HandleHttp(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	r := newRouter()
	r.HandleFunc(path.Join(ed.root, "/explorer"), ed.HandleApiExplorerRequest)
	r.HandleFunc(path.Join(ed.root, "/static"), ed.HandleApiStaticRequest)
	r.HandleFunc("/", ed.ServeHTTP)
	mux.Handle(ed.root, r)
}
Ejemplo n.º 17
0
// adds api routes to given mix router
func AddRoutes(mux *http.ServeMux) error {
	api := rest.NewApi()

	logger := log.New(nil, "", 0)
	lg.CopyLoggerTo("INFO", logger)

	loggerWarning := log.New(nil, "", 0)
	lg.CopyLoggerTo("WARNING", loggerWarning)

	if lg.V(100) {
		api.Use(&middlewares.AccessLogApacheMiddleware{
			Format: "%S\033[0m \033[36;1m%Dμs\033[0m \"%r\" \033[1;30m%u \"%{User-Agent}i\"\033[0m",
		})
	} else if lg.V(20) {
		api.Use(&middlewares.AccessLogApacheMiddleware{
			Format: "%s %Dμs %r",
		})
	} else if lg.V(3) {
		api.Use(&middlewares.AccessLogApacheErrorMiddleware{
			AccessLogApacheMiddleware: &middlewares.AccessLogApacheMiddleware{
				Format: "%s %Dμs %r",
			},
		})
	}
	api.Use(
		&rest.TimerMiddleware{},
		&rest.RecorderMiddleware{},
		&rest.PoweredByMiddleware{},
		// &rest.ContentTypeCheckerMiddleware{},
	)
	if lg.V(5) {
		api.Use(
			&rest.RecoverMiddleware{
				EnableResponseStackTrace: true,
				Logger: logger,
			},
		)
	} else {
		api.Use(
			&rest.RecoverMiddleware{
				Logger: logger,
			},
		)
	}

	router, err := rest.MakeRouter(routes...)
	if err != nil {
		panic(err)
	}
	api.SetApp(router)
	handler := api.MakeHandler()
	mux.Handle("/api/", http.StripPrefix("/api", handler))
	return err
}
Ejemplo n.º 18
0
// Register add the endpoints of this service to the given ServeMux,
// and binds Tx. Returns the ConnStatus channel from Tx.Bind.
//
// Must be called once, before the server is started.
func (h *Handler) Register(mux *http.ServeMux) <-chan smpp.ConnStatus {
	h.init()
	p := urlprefix(h)
	mux.Handle(p+"/send", h.send())
	mux.Handle(p+"/query", h.query())
	mux.Handle(p+"/sse", h.sse())
	mux.Handle(p+"/ws/jsonrpc", h.wsrpc())
	mux.Handle(p+"/ws/jsonrpc/events", h.wsrpcEvents())
	h.Handler = mux
	return h.Tx.Bind()
}
Ejemplo n.º 19
0
// setting serveMux to nil will use http.DefaultServeMux instead.
func ConfigureHttpHandler(serveMux *http.ServeMux) {
	if serveMux == nil {
		serveMux = http.DefaultServeMux
	}

	SetFileServer()

	serveMux.Handle(Config.AssetsUrl, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ServeRequest(w, r)
	}))
}
Ejemplo n.º 20
0
func NewHTTPDisplay(mux *http.ServeMux, onRun func()) traceDisplay {
	v := httpDisplay{}
	v.OnRun = onRun
	v.update = make(chan struct{})
	v.msgs = make(chan jsonMsg)

	mux.HandleFunc("/", v.handleRoot)
	mux.Handle("/updates", websocket.Handler(v.updateSocket))
	mux.HandleFunc("/run", v.handleRun)

	return &v
}
Ejemplo n.º 21
0
func addStaticBinary(mux *http.ServeMux, path string, content []byte) {
	mux.Handle(
		path,
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			http.ServeContent(
				w,
				r,
				path,
				appStartTime,
				bytes.NewReader(content))
		}))
}
Ejemplo n.º 22
0
func (self *AnonymousPageServer) Attach(s *http.ServeMux) {
	s.Handle(self.prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, name := path.Split(r.URL.Path)
		id, err := strconv.ParseInt(name, 10, 64)
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			io.WriteString(w, "invalid page id")
		} else {
			self.getPage(id).ServeHTTP(w, r)
		}
	}))
}
Ejemplo n.º 23
0
func SetupHTTP(mux *http.ServeMux) {
	for _, route := range routes {
		mux.HandleFunc(route.pattern, route.handler)
	}
	mux.Handle("/demos/", http.StripPrefix("/demos/", http.FileServer(http.Dir(config.Constants.DemosFolder))))

	if config.Constants.ServeStatic {
		mux.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
			http.ServeFile(w, r, "views/static.html")
		})

	}
}
Ejemplo n.º 24
0
// prepareServer prepares the Web handlers for the setup wizard if there is no HTTPS config or
// the normal app if the app is already configured
func PrepareServer(smux *http.ServeMux) address {
	// load config...
	cfg := LoadConfig()
	if cfg == nil { // if config is null then run the setup
		return PrepareSetup(smux) // always on the default serve mux
	}
	// otherwise start the normal app
	log.Printf("Starting WebCA normal startup...")
	smux.HandleFunc("/", index)
	smux.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("img"))))
	smux.Handle("/favicon.ico", http.FileServer(http.Dir("img")))
	return address{webCAURL(cfg), cfg.certFile(), cfg.keyFile(), true}
}
Ejemplo n.º 25
0
func WithProxyMux(handler http.Handler, mux *http.ServeMux) http.Handler {
	if mux == nil {
		return handler
	}

	// register the handler at this stage against everything under slash.  More specific paths that get registered will take precedence
	// this effectively delegates by default unless something specific gets registered.
	mux.Handle("/", handler)

	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		mux.ServeHTTP(w, req)
	})
}
Ejemplo n.º 26
0
func initDebug(mux *http.ServeMux) {
	stats.prev = time.Now()

	expvar.Publish("dcp", expvar.Func(dcp))
	expvar.Publish("goroutines", expvar.Func(goroutines))

	mux.Handle("/debug/vars/", http.HandlerFunc(expvarHandler))
	mux.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
}
Ejemplo n.º 27
0
// Register registers HTTP handlers that redirect old godoc paths to their new
// equivalents and assist in accessing the issue tracker, wiki, code review
// system, etc. If mux is nil it uses http.DefaultServeMux.
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	handlePathRedirects(mux, pkgRedirects, "/pkg/")
	handlePathRedirects(mux, cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		mux.Handle(p, PrefixHandler(p, redirect))
	}
	for path, redirect := range redirects {
		mux.Handle(path, Handler(redirect))
	}
}
Ejemplo n.º 28
0
func main() {

	var handlerInstance *HandlerObject = NewHandlerObject(123)

	var httpMux *http.ServeMux = http.NewServeMux()
	httpServer := &http.Server{
		Addr:           ":8080",
		Handler:        httpMux,
		ReadTimeout:    2 * time.Second,
		WriteTimeout:   2 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	var httpsMux *http.ServeMux = http.NewServeMux()
	httpsServer := &http.Server{
		Addr:           ":8443",
		Handler:        httpsMux,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	httpMux.Handle("/foo", handlerInstance)
	httpMux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%+v", r)
		r.Body = http.MaxBytesReader(w, nopCloser{r.Body}, 1024)
		fmt.Fprintf(w, "HandlerFunc, %q", html.EscapeString(r.URL.Path))
	})

	httpsMux.Handle("/foo", handlerInstance)
	httpsMux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%+v", r)
		r.Body = http.MaxBytesReader(w, nopCloser{r.Body}, 65536)
		fmt.Fprintf(w, "HandlerFunc, %q", html.EscapeString(r.URL.Path))
	})

	go func() {
		log.Println("Before starting HTTPS listener...")
		err := httpsServer.ListenAndServeTLS("server.crt", "server.key.insecure")
		if err != nil {
			log.Fatal("HTTPS listener couldn't start")
		}
	}()

	log.Println("Before starting HTTP listener...")
	err := httpServer.ListenAndServe()
	if err != nil {
		log.Fatal("HTTP listener couldn't start")
	}
}
Ejemplo n.º 29
0
func RegisterRoutes(r *http.ServeMux, dockerAddr string) {
	apiRouter := mux.NewRouter()
	container.RegisterRoutes(apiRouter)

	apiWithMiddleware := negroni.New()
	apiMiddleware := NewApiMiddleware(dockerAddr)
	apiWithMiddleware.Use(apiMiddleware)
	apiWithMiddleware.UseHandler(apiRouter)
	r.Handle("/api/", apiWithMiddleware)
	/*r.Handle("/api/", negroni.New(
		NewApiMiddleware(dockerAddr),
		negroni.Wrap(apiRouter),
	))*/
}
Ejemplo n.º 30
0
Archivo: ffiti.go Proyecto: qpliu/ffiti
func Init(serveMux *http.ServeMux, config Config) error {
	versionedRoot := "/" + config.Version + "/"
	serveMux.Handle(versionedRoot, http.StripPrefix(versionedRoot, http.FileServer(http.Dir(config.Documents))))
	serveMux.Handle("/", http.RedirectHandler(versionedRoot, http.StatusTemporaryRedirect))

	serveMux.HandleFunc("/v1/post", func(w http.ResponseWriter, r *http.Request) {
		post, err := data.GetPost(r)
		if err != nil {
			log.Printf("data.GetPost,err=%s", err.Error())
			http.Error(w, "Bad request", http.StatusBadRequest)
			return
		}
		err = config.DataStore.Storage(r).Post(post.Location.Key(), *post)
		if err != nil {
			log.Printf("config.Storage.GetPost,err=%s", err.Error())
			http.Error(w, "Internal server error", http.StatusInternalServerError)
			return
		}
		log.Printf("/v1/post:loc=%v", post.Location)
		w.WriteHeader(http.StatusCreated)
	})

	serveMux.HandleFunc("/v1/get", func(w http.ResponseWriter, r *http.Request) {
		loc, err := data.GetLocation(r)
		if err != nil {
			log.Printf("data.GetLocation,err=%s", err.Error())
			http.Error(w, "Bad request", http.StatusBadRequest)
			return
		}
		log.Printf("/v1/get:loc=%v", loc)
		result := Posts{Bounds: loc.Bounds()}
		storage := config.DataStore.Storage(r)
		for _, key := range loc.Keys() {
			if msgs, err := storage.Get(key); err == nil {
				for _, msg := range msgs {
					result.Posts = append(result.Posts, msg)
				}
			}
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(result)
	})

	serveMux.HandleFunc("/v1/version", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(config.Version))
	})

	return nil
}