Browse code

Always return version and server headers

If a 400 error is returned due to an API version mismatch, no
version and server-identification headers were returned by the API.

All information in these headers is "static", so there is no
reason to omit the information in case of an error being
returned.

This patch updates the version middleware to always
return the headers.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2017/10/10 19:40:15
Showing 2 changed files
... ...
@@ -43,6 +43,10 @@ func (e versionUnsupportedError) InvalidParameter() {}
43 43
 // WrapHandler returns a new handler function wrapping the previous one in the request chain.
44 44
 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 {
45 45
 	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
46
+		w.Header().Set("Server", fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS))
47
+		w.Header().Set("API-Version", v.defaultVersion)
48
+		w.Header().Set("OSType", runtime.GOOS)
49
+
46 50
 		apiVersion := vars["version"]
47 51
 		if apiVersion == "" {
48 52
 			apiVersion = v.defaultVersion
... ...
@@ -53,11 +57,6 @@ func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.
53 53
 		if versions.GreaterThan(apiVersion, v.defaultVersion) {
54 54
 			return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultVersion}
55 55
 		}
56
-
57
-		header := fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS)
58
-		w.Header().Set("Server", header)
59
-		w.Header().Set("API-Version", v.defaultVersion)
60
-		w.Header().Set("OSType", runtime.GOOS)
61 56
 		// nolint: golint
62 57
 		ctx = context.WithValue(ctx, "api-version", apiVersion)
63 58
 		return handler(ctx, w, r, vars)
... ...
@@ -3,10 +3,12 @@ package middleware
3 3
 import (
4 4
 	"net/http"
5 5
 	"net/http/httptest"
6
+	"runtime"
6 7
 	"strings"
7 8
 	"testing"
8 9
 
9 10
 	"github.com/docker/docker/api/server/httputils"
11
+	"github.com/stretchr/testify/assert"
10 12
 	"golang.org/x/net/context"
11 13
 )
12 14
 
... ...
@@ -80,3 +82,31 @@ func TestVersionMiddlewareVersionTooNew(t *testing.T) {
80 80
 		t.Fatalf("Expected too new client error, got %v", err)
81 81
 	}
82 82
 }
83
+
84
+func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
85
+	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
86
+		if httputils.VersionFromContext(ctx) == "" {
87
+			t.Fatal("Expected version, got empty string")
88
+		}
89
+		return nil
90
+	}
91
+
92
+	defaultVersion := "1.10.0"
93
+	minVersion := "1.2.0"
94
+	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
95
+	h := m.WrapHandler(handler)
96
+
97
+	req, _ := http.NewRequest("GET", "/containers/json", nil)
98
+	resp := httptest.NewRecorder()
99
+	ctx := context.Background()
100
+
101
+	vars := map[string]string{"version": "0.1"}
102
+	err := h(ctx, resp, req, vars)
103
+
104
+	assert.Error(t, err)
105
+	hdr := resp.Result().Header
106
+	assert.Contains(t, hdr.Get("Server"), "Docker/"+defaultVersion)
107
+	assert.Contains(t, hdr.Get("Server"), runtime.GOOS)
108
+	assert.Equal(t, hdr.Get("API-Version"), defaultVersion)
109
+	assert.Equal(t, hdr.Get("OSType"), runtime.GOOS)
110
+}