diff --git a/etcd.go b/etcd.go index ac1be5f1b..8f98fa34e 100644 --- a/etcd.go +++ b/etcd.go @@ -19,6 +19,7 @@ package main import ( "fmt" "net" + "net/http" "os" "runtime" "time" @@ -157,7 +158,6 @@ func main() { sConfig := server.ServerConfig{ Name: info.Name, URL: info.EtcdURL, - CORS: corsInfo, } s := server.New(sConfig, ps, registry, store, &mb) @@ -181,5 +181,8 @@ func main() { go func() { log.Fatal(ps.Serve(psListener, config.Snapshot, config.Peers)) }() - log.Fatal(s.Serve(sListener)) + + log.Infof("etcd server [name %s, listen on %s, advertised url %s]", s.Config.Name, sListener.Addr(), s.Config.URL) + sHTTP := &server.CORSHTTPMiddleware{s, corsInfo} + log.Fatal(http.Serve(sListener, sHTTP)) } diff --git a/server/cors.go b/server/cors.go index c9698573a..d585fbfc9 100644 --- a/server/cors.go +++ b/server/cors.go @@ -45,24 +45,24 @@ func (c corsInfo) OriginAllowed(origin string) bool { return c["*"] || c[origin] } -type corsHTTPMiddleware struct { - next http.Handler - info *corsInfo +type CORSHTTPMiddleware struct { + Handler http.Handler + Info *corsInfo } // addHeader adds the correct cors headers given an origin -func (h *corsHTTPMiddleware) addHeader(w http.ResponseWriter, origin string) { +func (h *CORSHTTPMiddleware) addHeader(w http.ResponseWriter, origin string) { w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") w.Header().Add("Access-Control-Allow-Origin", origin) } // ServeHTTP adds the correct CORS headers based on the origin and returns immediatly // with a 200 OK if the method is OPTIONS. -func (h *corsHTTPMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (h *CORSHTTPMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Write CORS header. - if h.info.OriginAllowed("*") { + if h.Info.OriginAllowed("*") { h.addHeader(w, "*") - } else if origin := req.Header.Get("Origin"); h.info.OriginAllowed(origin) { + } else if origin := req.Header.Get("Origin"); h.Info.OriginAllowed(origin) { h.addHeader(w, origin) } @@ -71,5 +71,5 @@ func (h *corsHTTPMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request) return } - h.next.ServeHTTP(w, req) + h.Handler.ServeHTTP(w, req) } diff --git a/server/server.go b/server/server.go index c3bedfaf6..dd6d08ff0 100644 --- a/server/server.go +++ b/server/server.go @@ -25,51 +25,36 @@ import ( type ServerConfig struct { Name string URL string - CORS *corsInfo } // This is the default implementation of the Server interface. type Server struct { - http.Server Config ServerConfig peerServer *PeerServer registry *Registry store store.Store - router *mux.Router - corsMiddleware *corsHTTPMiddleware - metrics *metrics.Bucket + metrics *metrics.Bucket + listener net.Listener + + trace bool } // Creates a new Server. func New(sConfig ServerConfig, peerServer *PeerServer, registry *Registry, store store.Store, mb *metrics.Bucket) *Server { - r := mux.NewRouter() - cors := &corsHTTPMiddleware{r, sConfig.CORS} - s := &Server{ - Config: sConfig, - Server: http.Server{ - Handler: cors, - }, + Config: sConfig, store: store, registry: registry, peerServer: peerServer, - router: r, - corsMiddleware: cors, metrics: mb, } - // Install the routes. - s.handleFunc("/version", s.GetVersionHandler).Methods("GET") - s.installV1() - s.installV2() - s.installMod() - return s } func (s *Server) EnableTracing() { - s.installDebug() + s.trace = true } // The current state of the server in the cluster. @@ -112,64 +97,62 @@ func (s *Server) Store() store.Store { return s.store } -func (s *Server) installV1() { - s.handleFuncV1("/v1/keys/{key:.*}", v1.GetKeyHandler).Methods("GET") - s.handleFuncV1("/v1/keys/{key:.*}", v1.SetKeyHandler).Methods("POST", "PUT") - s.handleFuncV1("/v1/keys/{key:.*}", v1.DeleteKeyHandler).Methods("DELETE") - s.handleFuncV1("/v1/watch/{key:.*}", v1.WatchKeyHandler).Methods("GET", "POST") - s.handleFunc("/v1/leader", s.GetLeaderHandler).Methods("GET") - s.handleFunc("/v1/machines", s.GetPeersHandler).Methods("GET") - s.handleFunc("/v1/peers", s.GetPeersHandler).Methods("GET") - s.handleFunc("/v1/stats/self", s.GetStatsHandler).Methods("GET") - s.handleFunc("/v1/stats/leader", s.GetLeaderStatsHandler).Methods("GET") - s.handleFunc("/v1/stats/store", s.GetStoreStatsHandler).Methods("GET") +func (s *Server) installV1(r *mux.Router) { + s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.GetKeyHandler).Methods("GET") + s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.SetKeyHandler).Methods("POST", "PUT") + s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.DeleteKeyHandler).Methods("DELETE") + s.handleFuncV1(r, "/v1/watch/{key:.*}", v1.WatchKeyHandler).Methods("GET", "POST") + s.handleFunc(r, "/v1/leader", s.GetLeaderHandler).Methods("GET") + s.handleFunc(r, "/v1/machines", s.GetPeersHandler).Methods("GET") + s.handleFunc(r, "/v1/peers", s.GetPeersHandler).Methods("GET") + s.handleFunc(r, "/v1/stats/self", s.GetStatsHandler).Methods("GET") + s.handleFunc(r, "/v1/stats/leader", s.GetLeaderStatsHandler).Methods("GET") + s.handleFunc(r, "/v1/stats/store", s.GetStoreStatsHandler).Methods("GET") } -func (s *Server) installV2() { - s.handleFuncV2("/v2/keys/{key:.*}", v2.GetHandler).Methods("GET") - s.handleFuncV2("/v2/keys/{key:.*}", v2.PostHandler).Methods("POST") - s.handleFuncV2("/v2/keys/{key:.*}", v2.PutHandler).Methods("PUT") - s.handleFuncV2("/v2/keys/{key:.*}", v2.DeleteHandler).Methods("DELETE") - s.handleFunc("/v2/leader", s.GetLeaderHandler).Methods("GET") - s.handleFunc("/v2/machines", s.GetPeersHandler).Methods("GET") - s.handleFunc("/v2/peers", s.GetPeersHandler).Methods("GET") - s.handleFunc("/v2/stats/self", s.GetStatsHandler).Methods("GET") - s.handleFunc("/v2/stats/leader", s.GetLeaderStatsHandler).Methods("GET") - s.handleFunc("/v2/stats/store", s.GetStoreStatsHandler).Methods("GET") - s.handleFunc("/v2/speedTest", s.SpeedTestHandler).Methods("GET") +func (s *Server) installV2(r *mux.Router) { + s.handleFuncV2(r, "/v2/keys/{key:.*}", v2.GetHandler).Methods("GET") + s.handleFuncV2(r, "/v2/keys/{key:.*}", v2.PostHandler).Methods("POST") + s.handleFuncV2(r, "/v2/keys/{key:.*}", v2.PutHandler).Methods("PUT") + s.handleFuncV2(r, "/v2/keys/{key:.*}", v2.DeleteHandler).Methods("DELETE") + s.handleFunc(r, "/v2/leader", s.GetLeaderHandler).Methods("GET") + s.handleFunc(r, "/v2/machines", s.GetPeersHandler).Methods("GET") + s.handleFunc(r, "/v2/peers", s.GetPeersHandler).Methods("GET") + s.handleFunc(r, "/v2/stats/self", s.GetStatsHandler).Methods("GET") + s.handleFunc(r, "/v2/stats/leader", s.GetLeaderStatsHandler).Methods("GET") + s.handleFunc(r, "/v2/stats/store", s.GetStoreStatsHandler).Methods("GET") + s.handleFunc(r, "/v2/speedTest", s.SpeedTestHandler).Methods("GET") } -func (s *Server) installMod() { - r := s.router +func (s *Server) installMod(r *mux.Router) { r.PathPrefix("/mod").Handler(http.StripPrefix("/mod", mod.HttpHandler(s.Config.URL))) } -func (s *Server) installDebug() { - s.handleFunc("/debug/metrics", s.GetMetricsHandler).Methods("GET") - s.router.HandleFunc("/debug/pprof", pprof.Index) - s.router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) - s.router.HandleFunc("/debug/pprof/profile", pprof.Profile) - s.router.HandleFunc("/debug/pprof/symbol", pprof.Symbol) - s.router.HandleFunc("/debug/pprof/{name}", pprof.Index) +func (s *Server) installDebug(r *mux.Router) { + s.handleFunc(r, "/debug/metrics", s.GetMetricsHandler).Methods("GET") + r.HandleFunc("/debug/pprof", pprof.Index) + r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + r.HandleFunc("/debug/pprof/profile", pprof.Profile) + r.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + r.HandleFunc("/debug/pprof/{name}", pprof.Index) } // Adds a v1 server handler to the router. -func (s *Server) handleFuncV1(path string, f func(http.ResponseWriter, *http.Request, v1.Server) error) *mux.Route { - return s.handleFunc(path, func(w http.ResponseWriter, req *http.Request) error { +func (s *Server) handleFuncV1(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request, v1.Server) error) *mux.Route { + return s.handleFunc(r, path, func(w http.ResponseWriter, req *http.Request) error { return f(w, req, s) }) } // Adds a v2 server handler to the router. -func (s *Server) handleFuncV2(path string, f func(http.ResponseWriter, *http.Request, v2.Server) error) *mux.Route { - return s.handleFunc(path, func(w http.ResponseWriter, req *http.Request) error { +func (s *Server) handleFuncV2(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request, v2.Server) error) *mux.Route { + return s.handleFunc(r, path, func(w http.ResponseWriter, req *http.Request) error { return f(w, req, s) }) } // Adds a server handler to the router. -func (s *Server) handleFunc(path string, f func(http.ResponseWriter, *http.Request) error) *mux.Route { - r := s.router +func (s *Server) handleFunc(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request) error) *mux.Route { // Wrap the standard HandleFunc interface to pass in the server reference. return r.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) { @@ -189,11 +172,20 @@ func (s *Server) handleFunc(path string, f func(http.ResponseWriter, *http.Reque }) } -// Start to listen and response etcd client command -func (s *Server) Serve(listener net.Listener) error { - log.Infof("etcd server [name %s, listen on %s, advertised url %s]", s.Config.Name, listener.Addr(), s.Config.URL) - s.listener = listener - return s.Server.Serve(listener) +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + router := mux.NewRouter() + + // Install the routes. + s.handleFunc(router, "/version", s.GetVersionHandler).Methods("GET") + s.installV1(router) + s.installV2(router) + s.installMod(router) + + if s.trace { + s.installDebug(router) + } + + router.ServeHTTP(w, r) } // Stops the server.