server.go 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package server // import "github.com/docker/docker/api/server"
  2. import (
  3. "context"
  4. "net/http"
  5. "github.com/containerd/containerd/log"
  6. "github.com/docker/docker/api/server/httpstatus"
  7. "github.com/docker/docker/api/server/httputils"
  8. "github.com/docker/docker/api/server/middleware"
  9. "github.com/docker/docker/api/server/router"
  10. "github.com/docker/docker/api/server/router/debug"
  11. "github.com/docker/docker/dockerversion"
  12. "github.com/gorilla/mux"
  13. )
  14. // versionMatcher defines a variable matcher to be parsed by the router
  15. // when a request is about to be served.
  16. const versionMatcher = "/v{version:[0-9.]+}"
  17. // Server contains instance details for the server
  18. type Server struct {
  19. middlewares []middleware.Middleware
  20. }
  21. // UseMiddleware appends a new middleware to the request chain.
  22. // This needs to be called before the API routes are configured.
  23. func (s *Server) UseMiddleware(m middleware.Middleware) {
  24. s.middlewares = append(s.middlewares, m)
  25. }
  26. func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
  27. return func(w http.ResponseWriter, r *http.Request) {
  28. // Define the context that we'll pass around to share info
  29. // like the docker-request-id.
  30. //
  31. // The 'context' will be used for global data that should
  32. // apply to all requests. Data that is specific to the
  33. // immediate function being called should still be passed
  34. // as 'args' on the function call.
  35. // use intermediate variable to prevent "should not use basic type
  36. // string as key in context.WithValue" golint errors
  37. ctx := context.WithValue(r.Context(), dockerversion.UAStringKey{}, r.Header.Get("User-Agent"))
  38. r = r.WithContext(ctx)
  39. handlerFunc := s.handlerWithGlobalMiddlewares(handler)
  40. vars := mux.Vars(r)
  41. if vars == nil {
  42. vars = make(map[string]string)
  43. }
  44. if err := handlerFunc(ctx, w, r, vars); err != nil {
  45. statusCode := httpstatus.FromError(err)
  46. if statusCode >= 500 {
  47. log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
  48. }
  49. makeErrorHandler(err)(w, r)
  50. }
  51. }
  52. }
  53. type pageNotFoundError struct{}
  54. func (pageNotFoundError) Error() string {
  55. return "page not found"
  56. }
  57. func (pageNotFoundError) NotFound() {}
  58. // CreateMux returns a new mux with all the routers registered.
  59. func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
  60. m := mux.NewRouter()
  61. log.G(context.TODO()).Debug("Registering routers")
  62. for _, apiRouter := range routers {
  63. for _, r := range apiRouter.Routes() {
  64. f := s.makeHTTPHandler(r.Handler())
  65. log.G(context.TODO()).Debugf("Registering %s, %s", r.Method(), r.Path())
  66. m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
  67. m.Path(r.Path()).Methods(r.Method()).Handler(f)
  68. }
  69. }
  70. debugRouter := debug.NewRouter()
  71. for _, r := range debugRouter.Routes() {
  72. f := s.makeHTTPHandler(r.Handler())
  73. m.Path("/debug" + r.Path()).Handler(f)
  74. }
  75. notFoundHandler := makeErrorHandler(pageNotFoundError{})
  76. m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
  77. m.NotFoundHandler = notFoundHandler
  78. m.MethodNotAllowedHandler = notFoundHandler
  79. return m
  80. }