client: deterministically resolve http scheme
| ... | ... |
@@ -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 |
-} |