Browse code

Merge pull request #27306 from stevvooe/deterministic-client-scheme

client: deterministically resolve http scheme

Antonio Murdaca authored on 2016/10/12 17:50:55
Showing 3 changed files
... ...
@@ -63,6 +63,8 @@ const DefaultVersion string = "1.23"
63 63
 // Client is the API client that performs all operations
64 64
 // against a docker server.
65 65
 type Client struct {
66
+	// scheme sets the scheme for the client
67
+	scheme string
66 68
 	// host holds the server address to connect to
67 69
 	host string
68 70
 	// proto holds the client protocol i.e. unix.
... ...
@@ -143,7 +145,19 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map
143 143
 		}
144 144
 	}
145 145
 
146
+	scheme := "http"
147
+	tlsConfig := resolveTLSConfig(client.Transport)
148
+	if tlsConfig != nil {
149
+		// TODO(stevvooe): This isn't really the right way to write clients in Go.
150
+		// `NewClient` should probably only take an `*http.Client` and work from there.
151
+		// Unfortunately, the model of having a host-ish/url-thingy as the connection
152
+		// string has us confusing protocol and transport layers. We continue doing
153
+		// this to avoid breaking existing clients but this should be addressed.
154
+		scheme = "https"
155
+	}
156
+
146 157
 	return &Client{
158
+		scheme:            scheme,
147 159
 		host:              host,
148 160
 		proto:             proto,
149 161
 		addr:              addr,
... ...
@@ -100,10 +100,8 @@ func (cli *Client) sendClientRequest(ctx context.Context, method, path string, q
100 100
 		req.Host = "docker"
101 101
 	}
102 102
 
103
-	scheme := resolveScheme(cli.client.Transport)
104
-
105 103
 	req.URL.Host = cli.addr
106
-	req.URL.Scheme = scheme
104
+	req.URL.Scheme = cli.scheme
107 105
 
108 106
 	if expectedPayload && req.Header.Get("Content-Type") == "" {
109 107
 		req.Header.Set("Content-Type", "text/plain")
... ...
@@ -111,11 +109,11 @@ func (cli *Client) sendClientRequest(ctx context.Context, method, path string, q
111 111
 
112 112
 	resp, err := ctxhttp.Do(ctx, cli.client, req)
113 113
 	if err != nil {
114
-		if scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
114
+		if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
115 115
 			return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
116 116
 		}
117 117
 
118
-		if scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
118
+		if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
119 119
 			return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
120 120
 		}
121 121
 
... ...
@@ -26,20 +26,3 @@ func resolveTLSConfig(transport http.RoundTripper) *tls.Config {
26 26
 		return nil
27 27
 	}
28 28
 }
29
-
30
-// resolveScheme detects a tls config on the transport and returns the
31
-// appropriate http scheme.
32
-//
33
-// TODO(stevvooe): This isn't really the right way to write clients in Go.
34
-// `NewClient` should probably only take an `*http.Client` and work from there.
35
-// Unfortunately, the model of having a host-ish/url-thingy as the connection
36
-// string has us confusing protocol and transport layers. We continue doing
37
-// this to avoid breaking existing clients but this should be addressed.
38
-func resolveScheme(transport http.RoundTripper) string {
39
-	c := resolveTLSConfig(transport)
40
-	if c != nil {
41
-		return "https"
42
-	}
43
-
44
-	return "http"
45
-}