Browse Source

refactor(server): treat Server as an http.Handler

Brian Waldon 12 years ago
parent
commit
5c3a3db2d8
3 changed files with 69 additions and 74 deletions
  1. 5 2
      etcd.go
  2. 8 8
      server/cors.go
  3. 56 64
      server/server.go

+ 5 - 2
etcd.go

@@ -19,6 +19,7 @@ package main
 import (
 import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
+	"net/http"
 	"os"
 	"os"
 	"runtime"
 	"runtime"
 	"time"
 	"time"
@@ -157,7 +158,6 @@ func main() {
 	sConfig := server.ServerConfig{
 	sConfig := server.ServerConfig{
 		Name:     info.Name,
 		Name:     info.Name,
 		URL:      info.EtcdURL,
 		URL:      info.EtcdURL,
-		CORS:     corsInfo,
 	}
 	}
 	s := server.New(sConfig, ps, registry, store, &mb)
 	s := server.New(sConfig, ps, registry, store, &mb)
 
 
@@ -181,5 +181,8 @@ func main() {
 	go func() {
 	go func() {
 		log.Fatal(ps.Serve(psListener, config.Snapshot, config.Peers))
 		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))
 }
 }

+ 8 - 8
server/cors.go

@@ -45,24 +45,24 @@ func (c corsInfo) OriginAllowed(origin string) bool {
 	return c["*"] || c[origin]
 	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
 // 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-Methods", "POST, GET, OPTIONS, PUT, DELETE")
 	w.Header().Add("Access-Control-Allow-Origin", origin)
 	w.Header().Add("Access-Control-Allow-Origin", origin)
 }
 }
 
 
 // ServeHTTP adds the correct CORS headers based on the origin and returns immediatly
 // ServeHTTP adds the correct CORS headers based on the origin and returns immediatly
 // with a 200 OK if the method is OPTIONS.
 // 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.
 	// Write CORS header.
-	if h.info.OriginAllowed("*") {
+	if h.Info.OriginAllowed("*") {
 		h.addHeader(w, "*")
 		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)
 		h.addHeader(w, origin)
 	}
 	}
 
 
@@ -71,5 +71,5 @@ func (h *corsHTTPMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request)
 		return
 		return
 	}
 	}
 
 
-	h.next.ServeHTTP(w, req)
+	h.Handler.ServeHTTP(w, req)
 }
 }

+ 56 - 64
server/server.go

@@ -25,51 +25,36 @@ import (
 type ServerConfig struct {
 type ServerConfig struct {
 	Name string
 	Name string
 	URL  string
 	URL  string
-	CORS *corsInfo
 }
 }
 
 
 // This is the default implementation of the Server interface.
 // This is the default implementation of the Server interface.
 type Server struct {
 type Server struct {
-	http.Server
 	Config         ServerConfig
 	Config         ServerConfig
 	peerServer     *PeerServer
 	peerServer     *PeerServer
 	registry       *Registry
 	registry       *Registry
 	store          store.Store
 	store          store.Store
-	router         *mux.Router
-	corsMiddleware *corsHTTPMiddleware
-	metrics     *metrics.Bucket
+	metrics        *metrics.Bucket
+
 	listener net.Listener
 	listener net.Listener
+
+	trace          bool
 }
 }
 
 
 // Creates a new Server.
 // Creates a new Server.
 func New(sConfig ServerConfig, peerServer *PeerServer, registry *Registry, store store.Store, mb *metrics.Bucket) *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{
 	s := &Server{
-		Config: sConfig,
-		Server: http.Server{
-			Handler: cors,
-		},
+		Config:         sConfig,
 		store:          store,
 		store:          store,
 		registry:       registry,
 		registry:       registry,
 		peerServer:     peerServer,
 		peerServer:     peerServer,
-		router:         r,
-		corsMiddleware: cors,
 		metrics:     mb,
 		metrics:     mb,
 	}
 	}
 
 
-	// Install the routes.
-	s.handleFunc("/version", s.GetVersionHandler).Methods("GET")
-	s.installV1()
-	s.installV2()
-	s.installMod()
-
 	return s
 	return s
 }
 }
 
 
 func (s *Server) EnableTracing() {
 func (s *Server) EnableTracing() {
-	s.installDebug()
+	s.trace = true
 }
 }
 
 
 // The current state of the server in the cluster.
 // The current state of the server in the cluster.
@@ -112,64 +97,62 @@ func (s *Server) Store() store.Store {
 	return s.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)))
 	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.
 // 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)
 		return f(w, req, s)
 	})
 	})
 }
 }
 
 
 // Adds a v2 server handler to the router.
 // 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)
 		return f(w, req, s)
 	})
 	})
 }
 }
 
 
 // Adds a server handler to the router.
 // 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.
 	// Wrap the standard HandleFunc interface to pass in the server reference.
 	return r.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
 	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.
 // Stops the server.