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  }