func (s *httpSuite) TestNonValidatingClientGetter(c *gc.C) { client := utils.GetNonValidatingHTTPClient() resp, err := client.Get(s.Server.URL) c.Assert(err, gc.IsNil) resp.Body.Close() c.Assert(resp.StatusCode, gc.Equals, http.StatusOK) client1 := utils.GetNonValidatingHTTPClient() c.Assert(client1, gc.Not(gc.Equals), client) }
func (s *toolsWithMacaroonsSuite) TestCanPostWithLocalLogin(c *gc.C) { // Create a new user, and a local login macaroon for it. user := s.Factory.MakeUser(c, &factory.UserParams{Password: "******"}) conn := s.OpenAPIAs(c, user.Tag(), "hunter2") defer conn.Close() mac, err := usermanager.NewClient(conn).CreateLocalLoginMacaroon(user.UserTag()) c.Assert(err, jc.ErrorIsNil) checkCount := 0 s.DischargerLogin = func() string { checkCount++ return user.UserTag().Id() } do := func(req *http.Request) (*http.Response, error) { data, err := json.Marshal(macaroon.Slice{mac}) if err != nil { return nil, err } req.Header.Add(httpbakery.MacaroonsHeader, base64.StdEncoding.EncodeToString(data)) return utils.GetNonValidatingHTTPClient().Do(req) } // send without using bakeryDo, so we don't pass any macaroon cookies // along. resp := s.sendRequest(c, httpRequestParams{ method: "POST", url: s.toolsURI(c, ""), tag: user.UserTag().String(), password: "", // no password forces macaroon usage do: do, }) s.assertErrorResponse(c, resp, http.StatusBadRequest, "expected binaryVersion argument") c.Assert(checkCount, gc.Equals, 0) }
// UploadTools uploads tools at the specified location to the API server over HTTPS. func (c *Client) UploadTools(r io.Reader, vers version.Binary, additionalSeries ...string) (*tools.Tools, error) { // Prepare the upload request. query := fmt.Sprintf("binaryVersion=%s&series=%s", vers, strings.Join(additionalSeries, ","), ) endpoint, err := c.st.apiEndpoint("/tools", query) if err != nil { return nil, errors.Trace(err) } req, err := http.NewRequest("POST", endpoint.String(), r) if err != nil { return nil, errors.Annotate(err, "cannot create upload request") } req.SetBasicAuth(c.st.tag, c.st.password) req.Header.Set("Content-Type", "application/x-tar-gz") // Send the request. // BUG(dimitern) 2013-12-17 bug #1261780 // Due to issues with go 1.1.2, fixed later, we cannot use a // regular TLS client with the CACert here, because we get "x509: // cannot validate certificate for 127.0.0.1 because it doesn't // contain any IP SANs". Once we use a later go version, this // should be changed to connect to the API server with a regular // HTTP+TLS enabled client, using the CACert (possily cached, like // the tag and password) passed in api.Open()'s info argument. resp, err := utils.GetNonValidatingHTTPClient().Do(req) if err != nil { return nil, errors.Annotate(err, "cannot upload tools") } defer resp.Body.Close() // Now parse the response & return. body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.Annotate(err, "cannot read tools upload response") } if resp.StatusCode != http.StatusOK { // TODO (2015/09/15, bug #1499277) parse as JSON not as text. message := fmt.Sprintf("%s", bytes.TrimSpace(body)) if resp.StatusCode == http.StatusBadRequest && strings.Contains(message, params.CodeOperationBlocked) { // Operation Blocked errors must contain correct error code and message. return nil, ¶ms.Error{Code: params.CodeOperationBlocked, Message: message} } return nil, errors.Errorf("tools upload failed: %v (%s)", resp.StatusCode, message) } var jsonResponse params.ToolsResult if err := json.Unmarshal(body, &jsonResponse); err != nil { return nil, errors.Annotate(err, "cannot unmarshal upload response") } if err := jsonResponse.Error; err != nil { return nil, errors.Annotate(err, "error uploading tools") } return jsonResponse.Tools, nil }
func (c *registerCommand) secretKeyLogin(addrs []string, request params.SecretKeyLoginRequest) (*params.SecretKeyLoginResponse, error) { buf, err := json.Marshal(&request) if err != nil { return nil, errors.Annotate(err, "marshalling request") } r := bytes.NewReader(buf) // Determine which address to use by attempting to open an API // connection with each of the addresses. Note that we do not // know the CA certificate yet, so we do not want to send any // sensitive information. We make no attempt to log in until // we can verify the server's identity. opts := api.DefaultDialOpts() opts.InsecureSkipVerify = true conn, err := c.apiOpen(&api.Info{ Addrs: addrs, SkipLogin: true, // NOTE(axw) CACert is required, but ignored if // InsecureSkipVerify is set. We should try to // bring together CACert and InsecureSkipVerify // so they can be validated together. CACert: "ignored", }, opts) if err != nil { return nil, errors.Trace(err) } apiAddr := conn.Addr() if err := conn.Close(); err != nil { return nil, errors.Trace(err) } // Using the address we connected to above, perform the request. urlString := fmt.Sprintf("https://%s/register", apiAddr) httpReq, err := http.NewRequest("POST", urlString, r) if err != nil { return nil, errors.Trace(err) } httpReq.Header.Set("Content-Type", "application/json") httpClient := utils.GetNonValidatingHTTPClient() httpResp, err := httpClient.Do(httpReq) if err != nil { return nil, errors.Trace(err) } defer httpResp.Body.Close() if httpResp.StatusCode != http.StatusOK { var resp params.ErrorResult if err := json.NewDecoder(httpResp.Body).Decode(&resp); err != nil { return nil, errors.Trace(err) } return nil, resp.Error } var resp params.SecretKeyLoginResponse if err := json.NewDecoder(httpResp.Body).Decode(&resp); err != nil { return nil, errors.Trace(err) } return &resp, nil }
func (s *httpSuite) TestInsecureClientSucceeds(c *gc.C) { response, err := utils.GetNonValidatingHTTPClient().Get(s.Server.URL) c.Assert(err, gc.IsNil) defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) c.Assert(err, gc.IsNil) c.Check(string(body), gc.Equals, "Greetings!\n") }
func (c *Client) UploadTools( toolsFilename string, vers version.Binary, fakeSeries ...string, ) ( tools *tools.Tools, err error, ) { toolsTarball, err := os.Open(toolsFilename) if err != nil { return nil, err } defer toolsTarball.Close() // Prepare the upload request. url := fmt.Sprintf("%s/tools?binaryVersion=%s&series=%s", c.st.serverRoot, vers, strings.Join(fakeSeries, ",")) req, err := http.NewRequest("POST", url, toolsTarball) if err != nil { return nil, fmt.Errorf("cannot create upload request: %v", err) } req.SetBasicAuth(c.st.tag, c.st.password) req.Header.Set("Content-Type", "application/x-tar-gz") // Send the request. // BUG(dimitern) 2013-12-17 bug #1261780 // Due to issues with go 1.1.2, fixed later, we cannot use a // regular TLS client with the CACert here, because we get "x509: // cannot validate certificate for 127.0.0.1 because it doesn't // contain any IP SANs". Once we use a later go version, this // should be changed to connect to the API server with a regular // HTTP+TLS enabled client, using the CACert (possily cached, like // the tag and password) passed in api.Open()'s info argument. resp, err := utils.GetNonValidatingHTTPClient().Do(req) if err != nil { return nil, fmt.Errorf("cannot upload charm: %v", err) } if resp.StatusCode == http.StatusMethodNotAllowed { // API server is older than 1.17.5, so tools upload // is not supported; notify the client. return nil, ¶ms.Error{ Message: "tools upload is not supported by the API server", Code: params.CodeNotImplemented, } } // Now parse the response & return. body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("cannot read tools upload response: %v", err) } defer resp.Body.Close() var jsonResponse params.ToolsResult if err := json.Unmarshal(body, &jsonResponse); err != nil { return nil, fmt.Errorf("cannot unmarshal upload response: %v", err) } if err := jsonResponse.Error; err != nil { return nil, fmt.Errorf("error uploading tools: %v", err) } return jsonResponse.Tools, nil }
func (s *authHttpSuite) sendRequest(c *gc.C, tag, password, method, uri, contentType string, body io.Reader) (*http.Response, error) { req, err := http.NewRequest(method, uri, body) c.Assert(err, gc.IsNil) if tag != "" && password != "" { req.SetBasicAuth(tag, password) } if contentType != "" { req.Header.Set("Content-Type", contentType) } return utils.GetNonValidatingHTTPClient().Do(req) }
func (s *registrationSuite) testInvalidRequest(c *gc.C, requestBody, errorMessage, errorCode string, statusCode int) { httptesting.AssertJSONCall(c, httptesting.JSONCallParams{ Do: utils.GetNonValidatingHTTPClient().Do, URL: s.registrationURL(c), Method: "POST", Body: strings.NewReader(requestBody), ExpectStatus: statusCode, ExpectBody: ¶ms.ErrorResult{ Error: ¶ms.Error{Message: errorMessage, Code: errorCode}, }, }) }
func (s *registrationSuite) TestRegisterInvalidMethod(c *gc.C) { httptesting.AssertJSONCall(c, httptesting.JSONCallParams{ Do: utils.GetNonValidatingHTTPClient().Do, URL: s.registrationURL(c), Method: "GET", ExpectStatus: http.StatusMethodNotAllowed, ExpectBody: ¶ms.ErrorResult{ Error: ¶ms.Error{ Message: `unsupported method: "GET"`, Code: params.CodeMethodNotAllowed, }, }, }) }
// fetchAndCacheTools fetches tools with the specified version by searching for a URL // in simplestreams and GETting it, caching the result in toolstorage before returning // to the caller. func (h *toolsDownloadHandler) fetchAndCacheTools(v version.Binary, stor toolstorage.Storage, st *state.State) (io.ReadCloser, error) { envcfg, err := st.EnvironConfig() if err != nil { return nil, err } env, err := environs.New(envcfg) if err != nil { return nil, err } tools, err := envtools.FindExactTools(env, v.Number, v.Series, v.Arch) if err != nil { return nil, err } // No need to verify the server's identity because we verify the SHA-256 hash. logger.Infof("fetching %v tools from %v", v, tools.URL) resp, err := utils.GetNonValidatingHTTPClient().Get(tools.URL) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { msg := fmt.Sprintf("bad HTTP response: %v", resp.Status) if body, err := ioutil.ReadAll(resp.Body); err == nil { msg += fmt.Sprintf(" (%s)", bytes.TrimSpace(body)) } return nil, errors.New(msg) } data, sha256, err := readAndHash(resp.Body) if err != nil { return nil, err } if int64(len(data)) != tools.Size { return nil, errors.Errorf("size mismatch for %s", tools.URL) } if sha256 != tools.SHA256 { return nil, errors.Errorf("hash mismatch for %s", tools.URL) } // Cache tarball in toolstorage before returning. metadata := toolstorage.Metadata{ Version: v, Size: tools.Size, SHA256: tools.SHA256, } if err := stor.AddTools(bytes.NewReader(data), metadata); err != nil { return nil, errors.Annotate(err, "error caching tools") } return ioutil.NopCloser(bytes.NewReader(data)), nil }
// UploadTools uploads tools at the specified location to the API server over HTTPS. func (c *Client) UploadTools(r io.Reader, vers version.Binary) (*tools.Tools, error) { // Older versions of Juju expect to be told which series to expand // the uploaded tools to on the server-side. In new versions we // do this automatically, and the parameter will be ignored. fakeSeries := version.OSSupportedSeries(vers.OS) // Prepare the upload request. url := fmt.Sprintf("%s/tools?binaryVersion=%s&series=%s", c.st.serverRoot, vers, strings.Join(fakeSeries, ",")) req, err := http.NewRequest("POST", url, r) if err != nil { return nil, errors.Annotate(err, "cannot create upload request") } req.SetBasicAuth(c.st.tag, c.st.password) req.Header.Set("Content-Type", "application/x-tar-gz") // Send the request. // BUG(dimitern) 2013-12-17 bug #1261780 // Due to issues with go 1.1.2, fixed later, we cannot use a // regular TLS client with the CACert here, because we get "x509: // cannot validate certificate for 127.0.0.1 because it doesn't // contain any IP SANs". Once we use a later go version, this // should be changed to connect to the API server with a regular // HTTP+TLS enabled client, using the CACert (possily cached, like // the tag and password) passed in api.Open()'s info argument. resp, err := utils.GetNonValidatingHTTPClient().Do(req) if err != nil { return nil, errors.Annotate(err, "cannot upload charm") } defer resp.Body.Close() // Now parse the response & return. body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.Annotate(err, "cannot read tools upload response") } if resp.StatusCode != http.StatusOK { return nil, errors.Errorf("tools upload failed: %v (%s)", resp.StatusCode, bytes.TrimSpace(body)) } var jsonResponse params.ToolsResult if err := json.Unmarshal(body, &jsonResponse); err != nil { return nil, errors.Annotate(err, "cannot unmarshal upload response") } if err := jsonResponse.Error; err != nil { return nil, errors.Annotate(err, "error uploading tools") } return jsonResponse.Tools, nil }
func fetchCharmArchive(url *url.URL) ([]byte, error) { client := utils.GetNonValidatingHTTPClient() resp, err := client.Get(url.String()) if err != nil { return nil, errors.Annotatef(err, "cannot get %q", url) } body, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { return nil, errors.Annotatef(err, "cannot read charm archive") } if resp.StatusCode != http.StatusOK { return nil, errors.Errorf("cannot get %q: %s %s", url, resp.Status, body) } return body, nil }
func (s *registrationSuite) TestRegister(c *gc.C) { // Ensure we cannot log in with the password yet. const password = "******" c.Assert(s.bob.PasswordValid(password), jc.IsFalse) validNonce := []byte(strings.Repeat("X", 24)) secretKey := s.bob.SecretKey() ciphertext := s.sealBox( c, validNonce, secretKey, fmt.Sprintf(`{"password": "******"}`, password), ) resp := httptesting.Do(c, httptesting.DoRequestParams{ Do: utils.GetNonValidatingHTTPClient().Do, URL: s.registrationURL(c), Method: "POST", JSONBody: ¶ms.SecretKeyLoginRequest{ User: "******", Nonce: validNonce, PayloadCiphertext: ciphertext, }, }) c.Assert(resp.StatusCode, gc.Equals, http.StatusOK) defer resp.Body.Close() // It should be possible to log in as bob with the // password "hunter2" now, and there should be no // secret key any longer. err := s.bob.Refresh() c.Assert(err, jc.ErrorIsNil) c.Assert(s.bob.PasswordValid(password), jc.IsTrue) c.Assert(s.bob.SecretKey(), gc.IsNil) var response params.SecretKeyLoginResponse bodyData, err := ioutil.ReadAll(resp.Body) c.Assert(err, jc.ErrorIsNil) err = json.Unmarshal(bodyData, &response) c.Assert(err, jc.ErrorIsNil) c.Assert(response.Nonce, gc.HasLen, len(validNonce)) plaintext := s.openBox(c, response.PayloadCiphertext, response.Nonce, secretKey) var responsePayload params.SecretKeyLoginResponsePayload err = json.Unmarshal(plaintext, &responsePayload) c.Assert(err, jc.ErrorIsNil) c.Assert(responsePayload.CACert, gc.Equals, s.BackingState.CACert()) model, err := s.BackingState.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(responsePayload.ControllerUUID, gc.Equals, model.ControllerUUID()) }
func (s *toolsWithMacaroonsSuite) TestCanPostWithLocalLogin(c *gc.C) { // Create a new local user that we can log in as // using macaroon authentication. const password = "******" user := s.Factory.MakeUser(c, &factory.UserParams{Password: password}) // Install a "web-page" visitor that deals with the interaction // method that Juju controllers support for authenticating local // users. Note: the use of httpbakery.NewMultiVisitor is necessary // to trigger httpbakery to query the authentication methods and // bypass browser authentication. var prompted bool jar := apitesting.NewClearableCookieJar() client := utils.GetNonValidatingHTTPClient() client.Jar = jar bakeryClient := httpbakery.NewClient() bakeryClient.Client = client bakeryClient.WebPageVisitor = httpbakery.NewMultiVisitor(apiauthentication.NewVisitor( user.UserTag().Id(), func(username string) (string, error) { c.Assert(username, gc.Equals, user.UserTag().Id()) prompted = true return password, nil }, )) bakeryDo := func(req *http.Request) (*http.Response, error) { var body io.ReadSeeker if req.Body != nil { body = req.Body.(io.ReadSeeker) req.Body = nil } return bakeryClient.DoWithBodyAndCustomError(req, body, bakeryGetError) } resp := s.sendRequest(c, httpRequestParams{ method: "POST", url: s.toolsURI(c, ""), tag: user.UserTag().String(), password: "", // no password forces macaroon usage do: bakeryDo, }) s.assertErrorResponse(c, resp, http.StatusBadRequest, "expected binaryVersion argument") c.Assert(prompted, jc.IsTrue) }
func (u *Upgrader) ensureTools(agentTools *coretools.Tools) error { logger.Infof("fetching tools from %q", agentTools.URL) // The reader MUST verify the tools' hash, so there is no // need to validate the peer. We cannot anyway: see http://pad.lv/1261780. resp, err := utils.GetNonValidatingHTTPClient().Get(agentTools.URL) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("bad HTTP response: %v", resp.Status) } err = agenttools.UnpackTools(u.dataDir, agentTools, resp.Body) if err != nil { return fmt.Errorf("cannot unpack tools: %v", err) } logger.Infof("unpacked tools %s to %s", agentTools.Version, u.dataDir) return nil }
func (s *authHttpSuite) sendRequest(c *gc.C, p httpRequestParams) *http.Response { c.Logf("sendRequest: %s", p.url) hp := httptesting.DoRequestParams{ Do: p.do, Method: p.method, URL: p.url, Body: p.body, JSONBody: p.jsonBody, Header: make(http.Header), Username: p.tag, Password: p.password, ExpectError: p.expectError, } if p.contentType != "" { hp.Header.Set("Content-Type", p.contentType) } if p.nonce != "" { hp.Header.Set(params.MachineNonceHeader, p.nonce) } if hp.Do == nil { hp.Do = utils.GetNonValidatingHTTPClient().Do } return httptesting.Do(c, hp) }
func (s *httpSuite) TestInsecureClientCached(c *gc.C) { client1 := utils.GetNonValidatingHTTPClient() client2 := utils.GetNonValidatingHTTPClient() c.Check(client1, gc.Equals, client2) }
func (s *httpSuite) TestNonValidatingClientGetter(c *gc.C) { client1 := utils.GetNonValidatingHTTPClient() client2 := utils.GetHTTPClient(utils.NoVerifySSLHostnames) c.Check(client1, gc.Equals, client2) }
func (s *dialSuite) TestInsecureClientNoAccess(c *gc.C) { s.PatchValue(&utils.OutgoingAccessAllowed, false) _, err := utils.GetNonValidatingHTTPClient().Get("http://10.0.0.1:1234") c.Assert(err, gc.ErrorMatches, `.*access to address "10.0.0.1:1234" not allowed`) }
func (s *httpDialSuite) TestInsecureClientAllowAccess(c *gc.C) { _, err := utils.GetNonValidatingHTTPClient().Get("http://0.1.2.3:1234") c.Assert(err, gc.ErrorMatches, `Get http://0.1.2.3:1234: dial tcp 0.1.2.3:1234: connect: .*`) }
// AddLocalCharm prepares the given charm with a local: schema in its // URL, and uploads it via the API server, returning the assigned // charm URL. If the API server does not support charm uploads, an // error satisfying params.IsCodeNotImplemented() is returned. func (c *Client) AddLocalCharm(curl *charm.URL, ch charm.Charm) (*charm.URL, error) { if curl.Schema != "local" { return nil, fmt.Errorf("expected charm URL with local: schema, got %q", curl.String()) } // Package the charm for uploading. var archive *os.File switch ch := ch.(type) { case *charm.Dir: var err error if archive, err = ioutil.TempFile("", "charm"); err != nil { return nil, fmt.Errorf("cannot create temp file: %v", err) } defer os.Remove(archive.Name()) defer archive.Close() if err := ch.BundleTo(archive); err != nil { return nil, fmt.Errorf("cannot repackage charm: %v", err) } if _, err := archive.Seek(0, 0); err != nil { return nil, fmt.Errorf("cannot rewind packaged charm: %v", err) } case *charm.Bundle: var err error if archive, err = os.Open(ch.Path); err != nil { return nil, fmt.Errorf("cannot read charm archive: %v", err) } defer archive.Close() default: return nil, fmt.Errorf("unknown charm type %T", ch) } // Prepare the upload request. url := fmt.Sprintf("%s/charms?series=%s", c.st.serverRoot, curl.Series) req, err := http.NewRequest("POST", url, archive) if err != nil { return nil, fmt.Errorf("cannot create upload request: %v", err) } req.SetBasicAuth(c.st.tag, c.st.password) req.Header.Set("Content-Type", "application/zip") // Send the request. // BUG(dimitern) 2013-12-17 bug #1261780 // Due to issues with go 1.1.2, fixed later, we cannot use a // regular TLS client with the CACert here, because we get "x509: // cannot validate certificate for 127.0.0.1 because it doesn't // contain any IP SANs". Once we use a later go version, this // should be changed to connect to the API server with a regular // HTTP+TLS enabled client, using the CACert (possily cached, like // the tag and password) passed in api.Open()'s info argument. resp, err := utils.GetNonValidatingHTTPClient().Do(req) if err != nil { return nil, fmt.Errorf("cannot upload charm: %v", err) } if resp.StatusCode == http.StatusMethodNotAllowed { // API server is 1.16 or older, so charm upload // is not supported; notify the client. return nil, ¶ms.Error{ Message: "charm upload is not supported by the API server", Code: params.CodeNotImplemented, } } // Now parse the response & return. body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("cannot read charm upload response: %v", err) } defer resp.Body.Close() var jsonResponse params.CharmsResponse if err := json.Unmarshal(body, &jsonResponse); err != nil { return nil, fmt.Errorf("cannot unmarshal upload response: %v", err) } if jsonResponse.Error != "" { return nil, fmt.Errorf("error uploading charm: %v", jsonResponse.Error) } return charm.MustParseURL(jsonResponse.CharmURL), nil }
// AddLocalCharm prepares the given charm with a local: schema in its // URL, and uploads it via the API server, returning the assigned // charm URL. If the API server does not support charm uploads, an // error satisfying params.IsCodeNotImplemented() is returned. func (c *Client) AddLocalCharm(curl *charm.URL, ch charm.Charm) (*charm.URL, error) { if curl.Schema != "local" { return nil, errors.Errorf("expected charm URL with local: schema, got %q", curl.String()) } // Package the charm for uploading. var archive *os.File switch ch := ch.(type) { case *charm.CharmDir: var err error if archive, err = ioutil.TempFile("", "charm"); err != nil { return nil, errors.Annotate(err, "cannot create temp file") } defer os.Remove(archive.Name()) defer archive.Close() if err := ch.ArchiveTo(archive); err != nil { return nil, errors.Annotate(err, "cannot repackage charm") } if _, err := archive.Seek(0, 0); err != nil { return nil, errors.Annotate(err, "cannot rewind packaged charm") } case *charm.CharmArchive: var err error if archive, err = os.Open(ch.Path); err != nil { return nil, errors.Annotate(err, "cannot read charm archive") } defer archive.Close() default: return nil, errors.Errorf("unknown charm type %T", ch) } endPoint, err := c.apiEndpoint("charms", "series="+curl.Series) if err != nil { return nil, errors.Trace(err) } // wrap archive in a noopCloser to prevent the underlying transport closing // the request body. This is neccessary to prevent a data race on the underlying // *os.File as the http transport _may_ issue Close once the body is sent, or it // may not if there is an error. noop := &noopCloser{archive} req, err := http.NewRequest("POST", endPoint, noop) if err != nil { return nil, errors.Annotate(err, "cannot create upload request") } req.SetBasicAuth(c.st.tag, c.st.password) req.Header.Set("Content-Type", "application/zip") // Send the request. // BUG(dimitern) 2013-12-17 bug #1261780 // Due to issues with go 1.1.2, fixed later, we cannot use a // regular TLS client with the CACert here, because we get "x509: // cannot validate certificate for 127.0.0.1 because it doesn't // contain any IP SANs". Once we use a later go version, this // should be changed to connect to the API server with a regular // HTTP+TLS enabled client, using the CACert (possily cached, like // the tag and password) passed in api.Open()'s info argument. resp, err := utils.GetNonValidatingHTTPClient().Do(req) if err != nil { return nil, errors.Annotate(err, "cannot upload charm") } defer resp.Body.Close() // Now parse the response & return. body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.Annotate(err, "cannot read charm upload response") } if resp.StatusCode != http.StatusOK { return nil, errors.Errorf("charm upload failed: %v (%s)", resp.StatusCode, bytes.TrimSpace(body)) } var jsonResponse params.CharmsResponse if err := json.Unmarshal(body, &jsonResponse); err != nil { return nil, errors.Annotate(err, "cannot unmarshal upload response") } if jsonResponse.Error != "" { return nil, errors.Errorf("error uploading charm: %v", jsonResponse.Error) } return charm.MustParseURL(jsonResponse.CharmURL), nil }
func (s *CmdSuite) TestHttpTransport(c *gc.C) { transport := http.DefaultTransport.(*http.Transport) c.Assert(transport.DisableKeepAlives, jc.IsTrue) client := utils.GetNonValidatingHTTPClient() c.Assert(client.Transport.(*http.Transport).DisableKeepAlives, jc.IsTrue) }