Refactor client/request

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2016-10-31 12:39:38 -04:00
parent 85a0bd062d
commit 5f066ed250
2 changed files with 49 additions and 36 deletions

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/http"
"net/http/httputil" "net/http/httputil"
"net/url" "net/url"
"strings" "strings"
@ -38,12 +39,14 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
return types.HijackedResponse{}, err return types.HijackedResponse{}, err
} }
req, err := cli.newRequest("POST", path, query, bodyEncoded, headers) apiPath := cli.getAPIPath(path, query)
req, err := http.NewRequest("POST", apiPath, bodyEncoded)
if err != nil { if err != nil {
return types.HijackedResponse{}, err return types.HijackedResponse{}, err
} }
req.Host = cli.addr req = cli.addHeaders(req, headers)
req.Host = cli.addr
req.Header.Set("Connection", "Upgrade") req.Header.Set("Connection", "Upgrade")
req.Header.Set("Upgrade", "tcp") req.Header.Set("Upgrade", "tcp")

View File

@ -38,21 +38,29 @@ func (cli *Client) get(ctx context.Context, path string, query url.Values, heade
// postWithContext sends an http request to the docker API using the method POST with a specific go context. // postWithContext sends an http request to the docker API using the method POST with a specific go context.
func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) { func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
return cli.sendRequest(ctx, "POST", path, query, obj, headers) body, headers, err := encodeBody(obj, headers)
if err != nil {
return serverResponse{}, err
}
return cli.sendRequest(ctx, "POST", path, query, body, headers)
} }
func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) { func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
return cli.sendClientRequest(ctx, "POST", path, query, body, headers) return cli.sendRequest(ctx, "POST", path, query, body, headers)
} }
// put sends an http request to the docker API using the method PUT. // put sends an http request to the docker API using the method PUT.
func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) { func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
return cli.sendRequest(ctx, "PUT", path, query, obj, headers) body, headers, err := encodeBody(obj, headers)
if err != nil {
return serverResponse{}, err
}
return cli.sendRequest(ctx, "PUT", path, query, body, headers)
} }
// put sends an http request to the docker API using the method PUT. // put sends an http request to the docker API using the method PUT.
func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) { func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
return cli.sendClientRequest(ctx, "PUT", path, query, body, headers) return cli.sendRequest(ctx, "PUT", path, query, body, headers)
} }
// delete sends an http request to the docker API using the method DELETE. // delete sends an http request to the docker API using the method DELETE.
@ -60,39 +68,35 @@ func (cli *Client) delete(ctx context.Context, path string, query url.Values, he
return cli.sendRequest(ctx, "DELETE", path, query, nil, headers) return cli.sendRequest(ctx, "DELETE", path, query, nil, headers)
} }
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) { type headers map[string][]string
var body io.Reader
if obj != nil { func encodeBody(obj interface{}, headers headers) (io.Reader, headers, error) {
var err error if obj == nil {
body, err = encodeData(obj) return nil, headers, nil
if err != nil {
return serverResponse{}, err
}
if headers == nil {
headers = make(map[string][]string)
}
headers["Content-Type"] = []string{"application/json"}
} }
return cli.sendClientRequest(ctx, method, path, query, body, headers) body, err := encodeData(obj)
if err != nil {
return nil, headers, err
}
if headers == nil {
headers = make(map[string][]string)
}
headers["Content-Type"] = []string{"application/json"}
return body, headers, nil
} }
func (cli *Client) sendClientRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) { func (cli *Client) buildRequest(method, path string, body io.Reader, headers headers) (*http.Request, error) {
serverResp := serverResponse{
body: nil,
statusCode: -1,
}
expectedPayload := (method == "POST" || method == "PUT") expectedPayload := (method == "POST" || method == "PUT")
if expectedPayload && body == nil { if expectedPayload && body == nil {
body = bytes.NewReader([]byte{}) body = bytes.NewReader([]byte{})
} }
req, err := cli.newRequest(method, path, query, body, headers) req, err := http.NewRequest(method, path, body)
if err != nil { if err != nil {
return serverResp, err return nil, err
} }
req = cli.addHeaders(req, headers)
if cli.proto == "unix" || cli.proto == "npipe" { if cli.proto == "unix" || cli.proto == "npipe" {
// For local communications, it doesn't matter what the host is. We just // For local communications, it doesn't matter what the host is. We just
@ -106,6 +110,19 @@ func (cli *Client) sendClientRequest(ctx context.Context, method, path string, q
if expectedPayload && req.Header.Get("Content-Type") == "" { if expectedPayload && req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "text/plain") req.Header.Set("Content-Type", "text/plain")
} }
return req, nil
}
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers headers) (serverResponse, error) {
req, err := cli.buildRequest(method, cli.getAPIPath(path, query), body, headers)
if err != nil {
return serverResponse{}, err
}
return cli.doRequest(ctx, req)
}
func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResponse, error) {
serverResp := serverResponse{statusCode: -1}
resp, err := ctxhttp.Do(ctx, cli.client, req) resp, err := ctxhttp.Do(ctx, cli.client, req)
if err != nil { if err != nil {
@ -193,13 +210,7 @@ func (cli *Client) sendClientRequest(ctx context.Context, method, path string, q
return serverResp, nil return serverResp, nil
} }
func (cli *Client) newRequest(method, path string, query url.Values, body io.Reader, headers map[string][]string) (*http.Request, error) { func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request {
apiPath := cli.getAPIPath(path, query)
req, err := http.NewRequest(method, apiPath, body)
if err != nil {
return nil, err
}
// Add CLI Config's HTTP Headers BEFORE we set the Docker headers // Add CLI Config's HTTP Headers BEFORE we set the Docker headers
// then the user can't change OUR headers // then the user can't change OUR headers
for k, v := range cli.customHTTPHeaders { for k, v := range cli.customHTTPHeaders {
@ -211,8 +222,7 @@ func (cli *Client) newRequest(method, path string, query url.Values, body io.Rea
req.Header[k] = v req.Header[k] = v
} }
} }
return req
return req, nil
} }
func encodeData(data interface{}) (*bytes.Buffer, error) { func encodeData(data interface{}) (*bytes.Buffer, error) {