github.com/a4a881d4/docker@v1.9.0-rc2/api/server/middleware.go (about)

     1  package server
     2  
     3  import (
     4  	"net/http"
     5  	"runtime"
     6  	"strings"
     7  
     8  	"github.com/Sirupsen/logrus"
     9  	"github.com/docker/docker/api"
    10  	"github.com/docker/docker/api/server/httputils"
    11  	"github.com/docker/docker/autogen/dockerversion"
    12  	"github.com/docker/docker/errors"
    13  	"github.com/docker/docker/pkg/version"
    14  	"golang.org/x/net/context"
    15  )
    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  
    21  // loggingMiddleware logs each request when logging is enabled.
    22  func (s *Server) loggingMiddleware(handler httputils.APIFunc) httputils.APIFunc {
    23  	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    24  		if s.cfg.Logging {
    25  			logrus.Infof("%s %s", r.Method, r.RequestURI)
    26  		}
    27  		return handler(ctx, w, r, vars)
    28  	}
    29  }
    30  
    31  // userAgentMiddleware checks the User-Agent header looking for a valid docker client spec.
    32  func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc {
    33  	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    34  		if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
    35  			dockerVersion := version.Version(s.cfg.Version)
    36  
    37  			userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
    38  
    39  			// v1.20 onwards includes the GOOS of the client after the version
    40  			// such as Docker/1.7.0 (linux)
    41  			if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") {
    42  				userAgent[1] = strings.Split(userAgent[1], " ")[0]
    43  			}
    44  
    45  			if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
    46  				logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
    47  			}
    48  		}
    49  		return handler(ctx, w, r, vars)
    50  	}
    51  }
    52  
    53  // corsMiddleware sets the CORS header expectations in the server.
    54  func (s *Server) corsMiddleware(handler httputils.APIFunc) httputils.APIFunc {
    55  	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    56  		// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
    57  		// otherwise, all head values will be passed to HTTP handler
    58  		corsHeaders := s.cfg.CorsHeaders
    59  		if corsHeaders == "" && s.cfg.EnableCors {
    60  			corsHeaders = "*"
    61  		}
    62  
    63  		if corsHeaders != "" {
    64  			writeCorsHeaders(w, r, corsHeaders)
    65  		}
    66  		return handler(ctx, w, r, vars)
    67  	}
    68  }
    69  
    70  // versionMiddleware checks the api version requirements before passing the request to the server handler.
    71  func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc {
    72  	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    73  		apiVersion := version.Version(vars["version"])
    74  		if apiVersion == "" {
    75  			apiVersion = api.Version
    76  		}
    77  
    78  		if apiVersion.GreaterThan(api.Version) {
    79  			return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.Version)
    80  		}
    81  		if apiVersion.LessThan(api.MinVersion) {
    82  			return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.Version)
    83  		}
    84  
    85  		w.Header().Set("Server", "Docker/"+dockerversion.VERSION+" ("+runtime.GOOS+")")
    86  		ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion)
    87  		return handler(ctx, w, r, vars)
    88  	}
    89  }
    90  
    91  // handleWithGlobalMiddlwares wraps the handler function for a request with
    92  // the server's global middlewares. The order of the middlewares is backwards,
    93  // meaning that the first in the list will be evaludated last.
    94  //
    95  // Example: handleWithGlobalMiddlewares(s.getContainersName)
    96  //
    97  //	s.loggingMiddleware(
    98  //		s.userAgentMiddleware(
    99  //			s.corsMiddleware(
   100  //				versionMiddleware(s.getContainersName)
   101  //			)
   102  //		)
   103  //	)
   104  // )
   105  func (s *Server) handleWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc {
   106  	middlewares := []middleware{
   107  		versionMiddleware,
   108  		s.corsMiddleware,
   109  		s.userAgentMiddleware,
   110  		s.loggingMiddleware,
   111  	}
   112  
   113  	h := handler
   114  	for _, m := range middlewares {
   115  		h = m(h)
   116  	}
   117  	return h
   118  }