github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/api/server/server.go (about) 1 package server 2 3 import ( 4 "crypto/tls" 5 "net" 6 "net/http" 7 "os" 8 "strings" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/api/server/httputils" 12 "github.com/docker/docker/api/server/router" 13 "github.com/docker/docker/api/server/router/container" 14 "github.com/docker/docker/api/server/router/local" 15 "github.com/docker/docker/api/server/router/network" 16 "github.com/docker/docker/api/server/router/system" 17 "github.com/docker/docker/api/server/router/volume" 18 "github.com/docker/docker/daemon" 19 "github.com/docker/docker/pkg/authorization" 20 "github.com/docker/docker/pkg/sockets" 21 "github.com/docker/docker/utils" 22 "github.com/gorilla/mux" 23 "golang.org/x/net/context" 24 ) 25 26 // versionMatcher defines a variable matcher to be parsed by the router 27 // when a request is about to be served. 28 const versionMatcher = "/v{version:[0-9.]+}" 29 30 // Config provides the configuration for the API server 31 type Config struct { 32 Logging bool 33 EnableCors bool 34 CorsHeaders string 35 AuthZPluginNames []string 36 Version string 37 SocketGroup string 38 TLSConfig *tls.Config 39 Addrs []Addr 40 } 41 42 // Server contains instance details for the server 43 type Server struct { 44 cfg *Config 45 servers []*HTTPServer 46 routers []router.Router 47 authZPlugins []authorization.Plugin 48 } 49 50 // Addr contains string representation of address and its protocol (tcp, unix...). 51 type Addr struct { 52 Proto string 53 Addr string 54 } 55 56 // New returns a new instance of the server based on the specified configuration. 57 // It allocates resources which will be needed for ServeAPI(ports, unix-sockets). 58 func New(cfg *Config) (*Server, error) { 59 s := &Server{ 60 cfg: cfg, 61 } 62 for _, addr := range cfg.Addrs { 63 srv, err := s.newServer(addr.Proto, addr.Addr) 64 if err != nil { 65 return nil, err 66 } 67 logrus.Debugf("Server created for HTTP on %s (%s)", addr.Proto, addr.Addr) 68 s.servers = append(s.servers, srv...) 69 } 70 return s, nil 71 } 72 73 // Close closes servers and thus stop receiving requests 74 func (s *Server) Close() { 75 for _, srv := range s.servers { 76 if err := srv.Close(); err != nil { 77 logrus.Error(err) 78 } 79 } 80 } 81 82 // ServeAPI loops through all initialized servers and spawns goroutine 83 // with Server method for each. It sets CreateMux() as Handler also. 84 func (s *Server) ServeAPI() error { 85 var chErrors = make(chan error, len(s.servers)) 86 for _, srv := range s.servers { 87 srv.srv.Handler = s.CreateMux() 88 go func(srv *HTTPServer) { 89 var err error 90 logrus.Infof("API listen on %s", srv.l.Addr()) 91 if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") { 92 err = nil 93 } 94 chErrors <- err 95 }(srv) 96 } 97 98 for i := 0; i < len(s.servers); i++ { 99 err := <-chErrors 100 if err != nil { 101 return err 102 } 103 } 104 105 return nil 106 } 107 108 // HTTPServer contains an instance of http server and the listener. 109 // srv *http.Server, contains configuration to create a http server and a mux router with all api end points. 110 // l net.Listener, is a TCP or Socket listener that dispatches incoming request to the router. 111 type HTTPServer struct { 112 srv *http.Server 113 l net.Listener 114 } 115 116 // Serve starts listening for inbound requests. 117 func (s *HTTPServer) Serve() error { 118 return s.srv.Serve(s.l) 119 } 120 121 // Close closes the HTTPServer from listening for the inbound requests. 122 func (s *HTTPServer) Close() error { 123 return s.l.Close() 124 } 125 126 func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) { 127 logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders) 128 w.Header().Add("Access-Control-Allow-Origin", corsHeaders) 129 w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth") 130 w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS") 131 } 132 133 func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) { 134 if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert { 135 logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") 136 } 137 if l, err = sockets.NewTCPSocket(addr, s.cfg.TLSConfig); err != nil { 138 return nil, err 139 } 140 if err := allocateDaemonPort(addr); err != nil { 141 return nil, err 142 } 143 return 144 } 145 146 func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc { 147 return func(w http.ResponseWriter, r *http.Request) { 148 // log the handler call 149 logrus.Debugf("Calling %s %s", r.Method, r.URL.Path) 150 151 // Define the context that we'll pass around to share info 152 // like the docker-request-id. 153 // 154 // The 'context' will be used for global data that should 155 // apply to all requests. Data that is specific to the 156 // immediate function being called should still be passed 157 // as 'args' on the function call. 158 ctx := context.Background() 159 handlerFunc := s.handleWithGlobalMiddlewares(handler) 160 161 vars := mux.Vars(r) 162 if vars == nil { 163 vars = make(map[string]string) 164 } 165 166 if err := handlerFunc(ctx, w, r, vars); err != nil { 167 logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err)) 168 httputils.WriteError(w, err) 169 } 170 } 171 } 172 173 // InitRouters initializes a list of routers for the server. 174 func (s *Server) InitRouters(d *daemon.Daemon) { 175 s.addRouter(container.NewRouter(d)) 176 s.addRouter(local.NewRouter(d)) 177 s.addRouter(network.NewRouter(d)) 178 s.addRouter(system.NewRouter(d)) 179 s.addRouter(volume.NewRouter(d)) 180 } 181 182 // addRouter adds a new router to the server. 183 func (s *Server) addRouter(r router.Router) { 184 s.routers = append(s.routers, r) 185 } 186 187 // CreateMux initializes the main router the server uses. 188 // we keep enableCors just for legacy usage, need to be removed in the future 189 func (s *Server) CreateMux() *mux.Router { 190 m := mux.NewRouter() 191 if os.Getenv("DEBUG") != "" { 192 profilerSetup(m, "/debug/") 193 } 194 195 logrus.Debugf("Registering routers") 196 for _, apiRouter := range s.routers { 197 for _, r := range apiRouter.Routes() { 198 f := s.makeHTTPHandler(r.Handler()) 199 200 logrus.Debugf("Registering %s, %s", r.Method(), r.Path()) 201 m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f) 202 m.Path(r.Path()).Methods(r.Method()).Handler(f) 203 } 204 } 205 206 return m 207 }