github.com/moby/docker@v26.1.3+incompatible/api/server/middleware/version.go (about) 1 package middleware // import "github.com/docker/docker/api/server/middleware" 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "runtime" 8 9 "github.com/docker/docker/api" 10 "github.com/docker/docker/api/server/httputils" 11 "github.com/docker/docker/api/types/versions" 12 ) 13 14 // VersionMiddleware is a middleware that 15 // validates the client and server versions. 16 type VersionMiddleware struct { 17 serverVersion string 18 19 // defaultAPIVersion is the default API version provided by the API server, 20 // specified as "major.minor". It is usually configured to the latest API 21 // version [github.com/docker/docker/api.DefaultVersion]. 22 // 23 // API requests for API versions greater than this version are rejected by 24 // the server and produce a [versionUnsupportedError]. 25 defaultAPIVersion string 26 27 // minAPIVersion is the minimum API version provided by the API server, 28 // specified as "major.minor". 29 // 30 // API requests for API versions lower than this version are rejected by 31 // the server and produce a [versionUnsupportedError]. 32 minAPIVersion string 33 } 34 35 // NewVersionMiddleware creates a VersionMiddleware with the given versions. 36 func NewVersionMiddleware(serverVersion, defaultAPIVersion, minAPIVersion string) (*VersionMiddleware, error) { 37 if versions.LessThan(defaultAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(defaultAPIVersion, api.DefaultVersion) { 38 return nil, fmt.Errorf("invalid default API version (%s): must be between %s and %s", defaultAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion) 39 } 40 if versions.LessThan(minAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(minAPIVersion, api.DefaultVersion) { 41 return nil, fmt.Errorf("invalid minimum API version (%s): must be between %s and %s", minAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion) 42 } 43 if versions.GreaterThan(minAPIVersion, defaultAPIVersion) { 44 return nil, fmt.Errorf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", minAPIVersion, defaultAPIVersion) 45 } 46 return &VersionMiddleware{ 47 serverVersion: serverVersion, 48 defaultAPIVersion: defaultAPIVersion, 49 minAPIVersion: minAPIVersion, 50 }, nil 51 } 52 53 type versionUnsupportedError struct { 54 version, minVersion, maxVersion string 55 } 56 57 func (e versionUnsupportedError) Error() string { 58 if e.minVersion != "" { 59 return fmt.Sprintf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", e.version, e.minVersion) 60 } 61 return fmt.Sprintf("client version %s is too new. Maximum supported API version is %s", e.version, e.maxVersion) 62 } 63 64 func (e versionUnsupportedError) InvalidParameter() {} 65 66 // WrapHandler returns a new handler function wrapping the previous one in the request chain. 67 func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 68 return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 69 w.Header().Set("Server", fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS)) 70 w.Header().Set("API-Version", v.defaultAPIVersion) 71 w.Header().Set("OSType", runtime.GOOS) 72 73 apiVersion := vars["version"] 74 if apiVersion == "" { 75 apiVersion = v.defaultAPIVersion 76 } 77 if versions.LessThan(apiVersion, v.minAPIVersion) { 78 return versionUnsupportedError{version: apiVersion, minVersion: v.minAPIVersion} 79 } 80 if versions.GreaterThan(apiVersion, v.defaultAPIVersion) { 81 return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultAPIVersion} 82 } 83 ctx = context.WithValue(ctx, httputils.APIVersionKey{}, apiVersion) 84 return handler(ctx, w, r, vars) 85 } 86 }