func (r *RegisterMeteredCharm) getCharmPlans(client *httpbakery.Client, cURL string) ([]string, error) { if r.QueryURL == "" { return nil, errors.Errorf("no plan query url specified") } qURL, err := url.Parse(r.QueryURL) if err != nil { return nil, errors.Trace(err) } query := qURL.Query() query.Set("charm-url", cURL) qURL.RawQuery = query.Encode() req, err := http.NewRequest("GET", qURL.String(), nil) if err != nil { return nil, errors.Trace(err) } response, err := client.Do(req) if err != nil { return nil, errors.Trace(err) } defer response.Body.Close() if response.StatusCode != http.StatusOK { return nil, errors.Errorf("failed to query plans: http response is %d", response.StatusCode) } var planInfo []struct { URL string `json:"url"` } dec := json.NewDecoder(response.Body) err = dec.Decode(&planInfo) if err != nil { return nil, errors.Trace(err) } info := make([]string, len(planInfo)) for i, p := range planInfo { info[i] = p.URL } return info, nil }
func (r *RegisterMeteredCharm) getDefaultPlan(client *httpbakery.Client, cURL string) (string, error) { if r.QueryURL == "" { return "", errors.Errorf("no plan query url specified") } qURL, err := url.Parse(r.QueryURL + "/default") if err != nil { return "", errors.Trace(err) } query := qURL.Query() query.Set("charm-url", cURL) qURL.RawQuery = query.Encode() req, err := http.NewRequest("GET", qURL.String(), nil) if err != nil { return "", errors.Trace(err) } response, err := client.Do(req) if err != nil { return "", errors.Trace(err) } defer response.Body.Close() if response.StatusCode == http.StatusNotFound { return "", &noDefaultPlanError{cURL} } if response.StatusCode != http.StatusOK { return "", errors.Errorf("failed to query default plan: http response is %d", response.StatusCode) } var planInfo struct { URL string `json:"url"` } dec := json.NewDecoder(response.Body) err = dec.Decode(&planInfo) if err != nil { return "", errors.Trace(err) } return planInfo.URL, nil }
// client represents a client of the target service. // In this simple example, it just tries a GET // request, which will fail unless the client // has the required authorization. func clientRequest(client *httpbakery.Client, serverEndpoint string) (string, error) { // The Do function implements the mechanics // of actually gathering discharge macaroons // when required, and retrying the request // when necessary. req, err := http.NewRequest("GET", serverEndpoint, nil) if err != nil { return "", errgo.Notef(err, "cannot make new HTTP request") } resp, err := client.Do(req) if err != nil { return "", errgo.NoteMask(err, "GET failed", errgo.Any) } defer resp.Body.Close() // TODO(rog) unmarshal error data, err := ioutil.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("cannot read response: %v", err) } return string(data), nil }
func (s *ClientSuite) TestMacaroonCookiePath(c *gc.C) { svc := newService("loc", nil) cookiePath := "" ts := httptest.NewServer(serverHandler(svc, "", func() string { return cookiePath })) defer ts.Close() var client *httpbakery.Client doRequest := func() { req, err := http.NewRequest("GET", ts.URL+"/foo/bar/", nil) c.Assert(err, gc.IsNil) client = httpbakery.NewClient() resp, err := client.Do(req) c.Assert(err, gc.IsNil) defer resp.Body.Close() assertResponse(c, resp, "done") } assertCookieCount := func(path string, n int) { u, err := url.Parse(ts.URL + path) c.Assert(err, gc.IsNil) c.Assert(client.Jar.Cookies(u), gc.HasLen, n) } cookiePath = "" c.Logf("- cookie path %q", cookiePath) doRequest() assertCookieCount("", 0) assertCookieCount("/foo", 0) assertCookieCount("/foo", 0) assertCookieCount("/foo/", 0) assertCookieCount("/foo/bar/", 1) assertCookieCount("/foo/bar/baz", 1) cookiePath = "/foo/" c.Logf("- cookie path %q", cookiePath) doRequest() assertCookieCount("", 0) assertCookieCount("/foo", 0) assertCookieCount("/foo/", 1) assertCookieCount("/foo/bar/", 1) assertCookieCount("/foo/bar/baz", 1) cookiePath = "/foo" c.Logf("- cookie path %q", cookiePath) doRequest() assertCookieCount("", 0) assertCookieCount("/bar", 0) assertCookieCount("/foo", 1) assertCookieCount("/foo/", 1) assertCookieCount("/foo/bar/", 1) assertCookieCount("/foo/bar/baz", 1) cookiePath = "../" c.Logf("- cookie path %q", cookiePath) doRequest() assertCookieCount("", 0) assertCookieCount("/bar", 0) assertCookieCount("/foo", 0) assertCookieCount("/foo/", 1) assertCookieCount("/foo/bar/", 1) assertCookieCount("/foo/bar/baz", 1) cookiePath = "../bar" c.Logf("- cookie path %q", cookiePath) doRequest() assertCookieCount("", 0) assertCookieCount("/bar", 0) assertCookieCount("/foo", 0) assertCookieCount("/foo/", 0) assertCookieCount("/foo/bar/", 1) assertCookieCount("/foo/bar/baz", 1) assertCookieCount("/foo/baz", 0) assertCookieCount("/foo/baz/", 0) assertCookieCount("/foo/baz/bar", 0) cookiePath = "/" c.Logf("- cookie path %q", cookiePath) doRequest() assertCookieCount("", 1) assertCookieCount("/bar", 1) assertCookieCount("/foo", 1) assertCookieCount("/foo/", 1) assertCookieCount("/foo/bar/", 1) assertCookieCount("/foo/bar/baz", 1) }
// VisitWebPage creates a function that can be used with // httpbakery.Client.VisitWebPage. The function uses c to access the // visit URL. If no agent-login cookie has been configured for u an error // with the cause of ErrNoAgentLoginCookie will be returned. If the login // fails the returned error will be of type *httpbakery.Error. If the // response from the visitURL cannot be interpreted the error will be of // type *UnexpectedResponseError. // // If using SetUpAuth, it should not be necessary to use // this function. func VisitWebPage(c *httpbakery.Client) func(u *url.URL) error { return func(u *url.URL) error { err := ErrNoAgentLoginCookie for _, c := range c.Jar.Cookies(u) { if c.Name == cookieName { err = nil break } } if err != nil { return errgo.WithCausef(err, http.ErrNoCookie, "cannot perform agent login") } req, err := http.NewRequest("GET", u.String(), nil) if err != nil { return errgo.Notef(err, "cannot create request") } resp, err := c.Do(req) if err != nil { return errgo.Notef(err, "cannot perform request") } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { logger.Errorf("cannot read response body: %s", err) b = []byte{} } mt, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) if err != nil { logger.Warningf("cannot parse response content type: %s", err) mt = "" } if mt != "application/json" { uerr := (*UnexpectedResponseError)(resp) uerr.Body = ioutil.NopCloser(bytes.NewReader(b)) return uerr } if resp.StatusCode != http.StatusOK { var herr httpbakery.Error err := json.Unmarshal(b, &herr) if err == nil && herr.Message != "" { return &herr } if err != nil { logger.Warningf("cannot unmarshal error response: %s", err) } uerr := (*UnexpectedResponseError)(resp) uerr.Body = ioutil.NopCloser(bytes.NewReader(b)) return uerr } var ar agentResponse err = json.Unmarshal(b, &ar) if err == nil && ar.AgentLogin { return nil } if err != nil { logger.Warningf("cannot unmarshal response: %s", err) } uerr := (*UnexpectedResponseError)(resp) uerr.Body = ioutil.NopCloser(bytes.NewReader(b)) return uerr } }