github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/api/server/middleware.go (about) 1 package server 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io/ioutil" 7 "net/http" 8 "runtime" 9 "strings" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/api" 13 "github.com/docker/docker/api/server/httputils" 14 "github.com/docker/docker/dockerversion" 15 "github.com/docker/docker/errors" 16 "github.com/docker/docker/pkg/authorization" 17 "github.com/docker/docker/pkg/version" 18 "golang.org/x/net/context" 19 ) 20 21 // middleware is an adapter to allow the use of ordinary functions as Docker API filters. 22 // Any function that has the appropriate signature can be register as a middleware. 23 type middleware func(handler httputils.APIFunc) httputils.APIFunc 24 25 // debugRequestMiddleware dumps the request to logger 26 func debugRequestMiddleware(handler httputils.APIFunc) httputils.APIFunc { 27 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 28 logrus.Debugf("%s %s", r.Method, r.RequestURI) 29 30 if r.Method == "POST" { 31 if err := httputils.CheckForJSON(r); err == nil { 32 var buf bytes.Buffer 33 if _, err := buf.ReadFrom(r.Body); err == nil { 34 r.Body.Close() 35 r.Body = ioutil.NopCloser(&buf) 36 var postForm map[string]interface{} 37 if err := json.Unmarshal(buf.Bytes(), &postForm); err == nil { 38 if _, exists := postForm["password"]; exists { 39 postForm["password"] = "*****" 40 } 41 formStr, errMarshal := json.Marshal(postForm) 42 if errMarshal == nil { 43 logrus.Debugf("form data: %s", string(formStr)) 44 } else { 45 logrus.Debugf("form data: %q", postForm) 46 } 47 } 48 } 49 } 50 } 51 52 return handler(ctx, w, r, vars) 53 } 54 } 55 56 // authorizationMiddleware perform authorization on the request. 57 func (s *Server) authorizationMiddleware(handler httputils.APIFunc) httputils.APIFunc { 58 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 59 // User and UserAuthNMethod are taken from AuthN plugins 60 // Currently tracked in https://github.com/docker/docker/pull/13994 61 user := "" 62 userAuthNMethod := "" 63 authCtx := authorization.NewCtx(s.authZPlugins, user, userAuthNMethod, r.Method, r.RequestURI) 64 65 if err := authCtx.AuthZRequest(w, r); err != nil { 66 logrus.Errorf("AuthZRequest for %s %s returned error: %s", r.Method, r.RequestURI, err) 67 return err 68 } 69 70 rw := authorization.NewResponseModifier(w) 71 72 if err := handler(ctx, rw, r, vars); err != nil { 73 logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.RequestURI, err) 74 return err 75 } 76 77 if err := authCtx.AuthZResponse(rw, r); err != nil { 78 logrus.Errorf("AuthZResponse for %s %s returned error: %s", r.Method, r.RequestURI, err) 79 return err 80 } 81 return nil 82 } 83 } 84 85 // userAgentMiddleware checks the User-Agent header looking for a valid docker client spec. 86 func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc { 87 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 88 if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { 89 dockerVersion := version.Version(s.cfg.Version) 90 91 userAgent := strings.Split(r.Header.Get("User-Agent"), "/") 92 93 // v1.20 onwards includes the GOOS of the client after the version 94 // such as Docker/1.7.0 (linux) 95 if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") { 96 userAgent[1] = strings.Split(userAgent[1], " ")[0] 97 } 98 99 if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) { 100 logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) 101 } 102 } 103 return handler(ctx, w, r, vars) 104 } 105 } 106 107 // corsMiddleware sets the CORS header expectations in the server. 108 func (s *Server) corsMiddleware(handler httputils.APIFunc) httputils.APIFunc { 109 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 110 // If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*" 111 // otherwise, all head values will be passed to HTTP handler 112 corsHeaders := s.cfg.CorsHeaders 113 if corsHeaders == "" && s.cfg.EnableCors { 114 corsHeaders = "*" 115 } 116 117 if corsHeaders != "" { 118 writeCorsHeaders(w, r, corsHeaders) 119 } 120 return handler(ctx, w, r, vars) 121 } 122 } 123 124 // versionMiddleware checks the api version requirements before passing the request to the server handler. 125 func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc { 126 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 127 apiVersion := version.Version(vars["version"]) 128 if apiVersion == "" { 129 apiVersion = api.DefaultVersion 130 } 131 132 if apiVersion.GreaterThan(api.DefaultVersion) { 133 return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.DefaultVersion) 134 } 135 if apiVersion.LessThan(api.MinVersion) { 136 return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.DefaultVersion) 137 } 138 139 w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")") 140 ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion) 141 return handler(ctx, w, r, vars) 142 } 143 } 144 145 // handleWithGlobalMiddlwares wraps the handler function for a request with 146 // the server's global middlewares. The order of the middlewares is backwards, 147 // meaning that the first in the list will be evaluated last. 148 // 149 // Example: handleWithGlobalMiddlewares(s.getContainersName) 150 // 151 // s.loggingMiddleware( 152 // s.userAgentMiddleware( 153 // s.corsMiddleware( 154 // versionMiddleware(s.getContainersName) 155 // ) 156 // ) 157 // ) 158 // ) 159 func (s *Server) handleWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc { 160 middlewares := []middleware{ 161 versionMiddleware, 162 s.corsMiddleware, 163 s.userAgentMiddleware, 164 } 165 166 // Only want this on debug level 167 if s.cfg.Logging && logrus.GetLevel() == logrus.DebugLevel { 168 middlewares = append(middlewares, debugRequestMiddleware) 169 } 170 171 if len(s.cfg.AuthZPluginNames) > 0 { 172 s.authZPlugins = authorization.NewPlugins(s.cfg.AuthZPluginNames) 173 middlewares = append(middlewares, s.authorizationMiddleware) 174 } 175 176 h := handler 177 for _, m := range middlewares { 178 h = m(h) 179 } 180 return h 181 }