middleware.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package server
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io/ioutil"
  6. "net/http"
  7. "runtime"
  8. "strings"
  9. "github.com/Sirupsen/logrus"
  10. "github.com/docker/docker/api"
  11. "github.com/docker/docker/api/server/httputils"
  12. "github.com/docker/docker/dockerversion"
  13. "github.com/docker/docker/errors"
  14. "github.com/docker/docker/pkg/version"
  15. "golang.org/x/net/context"
  16. )
  17. // middleware is an adapter to allow the use of ordinary functions as Docker API filters.
  18. // Any function that has the appropriate signature can be register as a middleware.
  19. type middleware func(handler httputils.APIFunc) httputils.APIFunc
  20. // debugRequestMiddleware dumps the request to logger
  21. func debugRequestMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  22. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  23. logrus.Debugf("%s %s", r.Method, r.RequestURI)
  24. if r.Method == "POST" {
  25. if err := httputils.CheckForJSON(r); err == nil {
  26. var buf bytes.Buffer
  27. if _, err := buf.ReadFrom(r.Body); err == nil {
  28. r.Body.Close()
  29. r.Body = ioutil.NopCloser(&buf)
  30. var postForm map[string]interface{}
  31. if err := json.Unmarshal(buf.Bytes(), &postForm); err == nil {
  32. if _, exists := postForm["password"]; exists {
  33. postForm["password"] = "*****"
  34. }
  35. logrus.Debugf("form data: %q", postForm)
  36. }
  37. }
  38. }
  39. }
  40. return handler(ctx, w, r, vars)
  41. }
  42. }
  43. // userAgentMiddleware checks the User-Agent header looking for a valid docker client spec.
  44. func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  45. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  46. if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
  47. dockerVersion := version.Version(s.cfg.Version)
  48. userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
  49. // v1.20 onwards includes the GOOS of the client after the version
  50. // such as Docker/1.7.0 (linux)
  51. if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") {
  52. userAgent[1] = strings.Split(userAgent[1], " ")[0]
  53. }
  54. if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
  55. logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
  56. }
  57. }
  58. return handler(ctx, w, r, vars)
  59. }
  60. }
  61. // corsMiddleware sets the CORS header expectations in the server.
  62. func (s *Server) corsMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  63. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  64. // If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
  65. // otherwise, all head values will be passed to HTTP handler
  66. corsHeaders := s.cfg.CorsHeaders
  67. if corsHeaders == "" && s.cfg.EnableCors {
  68. corsHeaders = "*"
  69. }
  70. if corsHeaders != "" {
  71. writeCorsHeaders(w, r, corsHeaders)
  72. }
  73. return handler(ctx, w, r, vars)
  74. }
  75. }
  76. // versionMiddleware checks the api version requirements before passing the request to the server handler.
  77. func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc {
  78. return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  79. apiVersion := version.Version(vars["version"])
  80. if apiVersion == "" {
  81. apiVersion = api.Version
  82. }
  83. if apiVersion.GreaterThan(api.Version) {
  84. return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.Version)
  85. }
  86. if apiVersion.LessThan(api.MinVersion) {
  87. return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.Version)
  88. }
  89. w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")")
  90. ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion)
  91. return handler(ctx, w, r, vars)
  92. }
  93. }
  94. // handleWithGlobalMiddlwares wraps the handler function for a request with
  95. // the server's global middlewares. The order of the middlewares is backwards,
  96. // meaning that the first in the list will be evaludated last.
  97. //
  98. // Example: handleWithGlobalMiddlewares(s.getContainersName)
  99. //
  100. // s.loggingMiddleware(
  101. // s.userAgentMiddleware(
  102. // s.corsMiddleware(
  103. // versionMiddleware(s.getContainersName)
  104. // )
  105. // )
  106. // )
  107. // )
  108. func (s *Server) handleWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc {
  109. middlewares := []middleware{
  110. versionMiddleware,
  111. s.corsMiddleware,
  112. s.userAgentMiddleware,
  113. }
  114. // Only want this on debug level
  115. if s.cfg.Logging && logrus.GetLevel() == logrus.DebugLevel {
  116. middlewares = append(middlewares, debugRequestMiddleware)
  117. }
  118. h := handler
  119. for _, m := range middlewares {
  120. h = m(h)
  121. }
  122. return h
  123. }