client.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package lib
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "strings"
  8. "github.com/docker/docker/pkg/sockets"
  9. "github.com/docker/docker/pkg/tlsconfig"
  10. )
  11. // Client is the API client that performs all operations
  12. // against a docker server.
  13. type Client struct {
  14. // proto holds the client protocol i.e. unix.
  15. proto string
  16. // addr holds the client address.
  17. addr string
  18. // basePath holds the path to prepend to the requests
  19. basePath string
  20. // scheme holds the scheme of the client i.e. https.
  21. scheme string
  22. // tlsConfig holds the tls configuration to use in hijacked requests.
  23. tlsConfig *tls.Config
  24. // httpClient holds the client transport instance. Exported to keep the old code running.
  25. httpClient *http.Client
  26. // version of the server to talk to.
  27. version string
  28. // custom http headers configured by users
  29. customHTTPHeaders map[string]string
  30. }
  31. // NewClient initializes a new API client for the given host and API version.
  32. // It won't send any version information if the version number is empty.
  33. // It uses the tlsOptions to decide whether to use a secure connection or not.
  34. // It also initializes the custom http headers to add to each request.
  35. func NewClient(host string, version string, tlsOptions *tlsconfig.Options, httpHeaders map[string]string) (*Client, error) {
  36. var (
  37. basePath string
  38. tlsConfig *tls.Config
  39. scheme = "http"
  40. protoAddrParts = strings.SplitN(host, "://", 2)
  41. proto, addr = protoAddrParts[0], protoAddrParts[1]
  42. )
  43. if proto == "tcp" {
  44. parsed, err := url.Parse("tcp://" + addr)
  45. if err != nil {
  46. return nil, err
  47. }
  48. addr = parsed.Host
  49. basePath = parsed.Path
  50. }
  51. if tlsOptions != nil {
  52. scheme = "https"
  53. var err error
  54. tlsConfig, err = tlsconfig.Client(*tlsOptions)
  55. if err != nil {
  56. return nil, err
  57. }
  58. }
  59. // The transport is created here for reuse during the client session.
  60. transport := &http.Transport{
  61. TLSClientConfig: tlsConfig,
  62. }
  63. sockets.ConfigureTCPTransport(transport, proto, addr)
  64. return &Client{
  65. proto: proto,
  66. addr: addr,
  67. basePath: basePath,
  68. scheme: scheme,
  69. tlsConfig: tlsConfig,
  70. httpClient: &http.Client{Transport: transport},
  71. version: version,
  72. customHTTPHeaders: httpHeaders,
  73. }, nil
  74. }
  75. // getAPIPath returns the versioned request path to call the api.
  76. // It appends the query parameters to the path if they are not empty.
  77. func (cli *Client) getAPIPath(p string, query url.Values) string {
  78. var apiPath string
  79. if cli.version != "" {
  80. v := strings.TrimPrefix(cli.version, "v")
  81. apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
  82. } else {
  83. apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
  84. }
  85. if len(query) > 0 {
  86. apiPath += "?" + query.Encode()
  87. }
  88. return apiPath
  89. }