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