github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/api/server/server.go (about) 1 package server // import "github.com/docker/docker/api/server" 2 3 import ( 4 "context" 5 "crypto/tls" 6 "net" 7 "net/http" 8 "strings" 9 "time" 10 11 "github.com/docker/docker/api/server/httpstatus" 12 "github.com/docker/docker/api/server/httputils" 13 "github.com/docker/docker/api/server/middleware" 14 "github.com/docker/docker/api/server/router" 15 "github.com/docker/docker/api/server/router/debug" 16 "github.com/docker/docker/dockerversion" 17 "github.com/gorilla/mux" 18 "github.com/sirupsen/logrus" 19 ) 20 21 // versionMatcher defines a variable matcher to be parsed by the router 22 // when a request is about to be served. 23 const versionMatcher = "/v{version:[0-9.]+}" 24 25 // Config provides the configuration for the API server 26 type Config struct { 27 Logging bool 28 CorsHeaders string 29 Version string 30 SocketGroup string 31 TLSConfig *tls.Config 32 } 33 34 // Server contains instance details for the server 35 type Server struct { 36 cfg *Config 37 servers []*HTTPServer 38 routers []router.Router 39 middlewares []middleware.Middleware 40 } 41 42 // New returns a new instance of the server based on the specified configuration. 43 // It allocates resources which will be needed for ServeAPI(ports, unix-sockets). 44 func New(cfg *Config) *Server { 45 return &Server{ 46 cfg: cfg, 47 } 48 } 49 50 // UseMiddleware appends a new middleware to the request chain. 51 // This needs to be called before the API routes are configured. 52 func (s *Server) UseMiddleware(m middleware.Middleware) { 53 s.middlewares = append(s.middlewares, m) 54 } 55 56 // Accept sets a listener the server accepts connections into. 57 func (s *Server) Accept(addr string, listeners ...net.Listener) { 58 for _, listener := range listeners { 59 httpServer := &HTTPServer{ 60 srv: &http.Server{ 61 Addr: addr, 62 ReadHeaderTimeout: 5 * time.Minute, // "G112: Potential Slowloris Attack (gosec)"; not a real concern for our use, so setting a long timeout. 63 }, 64 l: listener, 65 } 66 s.servers = append(s.servers, httpServer) 67 } 68 } 69 70 // Close closes servers and thus stop receiving requests 71 func (s *Server) Close() { 72 for _, srv := range s.servers { 73 if err := srv.Close(); err != nil { 74 logrus.Error(err) 75 } 76 } 77 } 78 79 // serveAPI loops through all initialized servers and spawns goroutine 80 // with Serve method for each. It sets createMux() as Handler also. 81 func (s *Server) serveAPI() error { 82 var chErrors = make(chan error, len(s.servers)) 83 for _, srv := range s.servers { 84 srv.srv.Handler = s.createMux() 85 go func(srv *HTTPServer) { 86 var err error 87 logrus.Infof("API listen on %s", srv.l.Addr()) 88 if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") { 89 err = nil 90 } 91 chErrors <- err 92 }(srv) 93 } 94 95 for range s.servers { 96 err := <-chErrors 97 if err != nil { 98 return err 99 } 100 } 101 return nil 102 } 103 104 // HTTPServer contains an instance of http server and the listener. 105 // srv *http.Server, contains configuration to create an http server and a mux router with all api end points. 106 // l net.Listener, is a TCP or Socket listener that dispatches incoming request to the router. 107 type HTTPServer struct { 108 srv *http.Server 109 l net.Listener 110 } 111 112 // Serve starts listening for inbound requests. 113 func (s *HTTPServer) Serve() error { 114 return s.srv.Serve(s.l) 115 } 116 117 // Close closes the HTTPServer from listening for the inbound requests. 118 func (s *HTTPServer) Close() error { 119 return s.l.Close() 120 } 121 122 func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc { 123 return func(w http.ResponseWriter, r *http.Request) { 124 // Define the context that we'll pass around to share info 125 // like the docker-request-id. 126 // 127 // The 'context' will be used for global data that should 128 // apply to all requests. Data that is specific to the 129 // immediate function being called should still be passed 130 // as 'args' on the function call. 131 132 // use intermediate variable to prevent "should not use basic type 133 // string as key in context.WithValue" golint errors 134 ctx := context.WithValue(r.Context(), dockerversion.UAStringKey{}, r.Header.Get("User-Agent")) 135 r = r.WithContext(ctx) 136 handlerFunc := s.handlerWithGlobalMiddlewares(handler) 137 138 vars := mux.Vars(r) 139 if vars == nil { 140 vars = make(map[string]string) 141 } 142 143 if err := handlerFunc(ctx, w, r, vars); err != nil { 144 statusCode := httpstatus.FromError(err) 145 if statusCode >= 500 { 146 logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err) 147 } 148 makeErrorHandler(err)(w, r) 149 } 150 } 151 } 152 153 // InitRouter initializes the list of routers for the server. 154 // This method also enables the Go profiler. 155 func (s *Server) InitRouter(routers ...router.Router) { 156 s.routers = append(s.routers, routers...) 157 } 158 159 type pageNotFoundError struct{} 160 161 func (pageNotFoundError) Error() string { 162 return "page not found" 163 } 164 165 func (pageNotFoundError) NotFound() {} 166 167 // createMux initializes the main router the server uses. 168 func (s *Server) createMux() *mux.Router { 169 m := mux.NewRouter() 170 171 logrus.Debug("Registering routers") 172 for _, apiRouter := range s.routers { 173 for _, r := range apiRouter.Routes() { 174 f := s.makeHTTPHandler(r.Handler()) 175 176 logrus.Debugf("Registering %s, %s", r.Method(), r.Path()) 177 m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f) 178 m.Path(r.Path()).Methods(r.Method()).Handler(f) 179 } 180 } 181 182 debugRouter := debug.NewRouter() 183 s.routers = append(s.routers, debugRouter) 184 for _, r := range debugRouter.Routes() { 185 f := s.makeHTTPHandler(r.Handler()) 186 m.Path("/debug" + r.Path()).Handler(f) 187 } 188 189 notFoundHandler := makeErrorHandler(pageNotFoundError{}) 190 m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler) 191 m.NotFoundHandler = notFoundHandler 192 m.MethodNotAllowedHandler = notFoundHandler 193 194 return m 195 } 196 197 // Wait blocks the server goroutine until it exits. 198 // It sends an error message if there is any error during 199 // the API execution. 200 func (s *Server) Wait(waitChan chan error) { 201 if err := s.serveAPI(); err != nil { 202 logrus.Errorf("ServeAPI error: %v", err) 203 waitChan <- err 204 return 205 } 206 waitChan <- nil 207 }