func (c *Couch) req(method, url string, headers http.Header, body []byte, user *url.Userinfo) (*http.Response, error) { if c.send == nil { panic("send func not set") } // Create a new request req, err := http.NewRequest(method, url, nil) if err != nil { return nil, err } req.Close = true req.TransferEncoding = []string{"chunked"} req.Body = ioutil.NopCloser(bytes.NewBuffer(body)) req.ContentLength = int64(len(body)) // Set headers if headers != nil { req.Header = headers } // Set auth credentials if user != nil { if p, ok := user.Password(); ok { req.SetBasicAuth(user.Username(), p) } } resp, err := c.send(req) if err != nil { return nil, err } return resp, nil }
func basicAuthTestcase(t *testing.T, upstreamUser, clientUser *url.Userinfo) { backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { u, p, ok := r.BasicAuth() if ok { w.Write([]byte(u)) } if ok && p != "" { w.Write([]byte(":")) w.Write([]byte(p)) } })) defer backend.Close() backURL, err := url.Parse(backend.URL) if err != nil { t.Fatalf("Failed to parse URL: %v", err) } backURL.User = upstreamUser p := &Proxy{ Next: httpserver.EmptyNext, Upstreams: []Upstream{newFakeUpstream(backURL.String(), false)}, } r, err := http.NewRequest("GET", "/foo", nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } if clientUser != nil { u := clientUser.Username() p, _ := clientUser.Password() r.SetBasicAuth(u, p) } w := httptest.NewRecorder() p.ServeHTTP(w, r) if w.Code != 200 { t.Fatalf("Invalid response code: %d", w.Code) } body, _ := ioutil.ReadAll(w.Body) if clientUser != nil { if string(body) != clientUser.String() { t.Fatalf("Invalid auth info: %s", string(body)) } } else { if upstreamUser != nil { if string(body) != upstreamUser.String() { t.Fatalf("Invalid auth info: %s", string(body)) } } else { if string(body) != "" { t.Fatalf("Invalid auth info: %s", string(body)) } } } }
func getCredentials(a httpRequestArgs, hdrCreds *url.Userinfo, auths []string) (datastore.Credentials, errors.Error) { var creds datastore.Credentials if hdrCreds != nil { // Credentials are in the request URL: username := hdrCreds.Username() password, _ := hdrCreds.Password() creds = make(datastore.Credentials) creds[username] = password return creds, nil } if len(auths) > 0 { // Credentials are in the request header: // TODO: implement non-Basic auth (digest, ntlm) auth := auths[0] if strings.HasPrefix(auth, "Basic ") { encoded_creds := strings.Split(auth, " ")[1] decoded_creds, err := base64.StdEncoding.DecodeString(encoded_creds) if err != nil { return creds, errors.NewServiceErrorBadValue(err, CREDS) } // Authorization header is in format "user:pass" // per http://tools.ietf.org/html/rfc1945#section-10.2 u_details := strings.Split(string(decoded_creds), ":") switch len(u_details) { case 2: creds = make(datastore.Credentials) creds[u_details[0]] = u_details[1] case 3: creds = make(datastore.Credentials) // Support usernames like "local:xxx" or "admin:xxx" creds[strings.Join(u_details[:2], ":")] = u_details[2] default: // Authorization header format is incorrect return creds, errors.NewServiceErrorBadValue(nil, CREDS) } } return creds, nil } // Credentials may be in request arguments: cred_data, err := a.getCredentials() if err == nil && len(cred_data) > 0 { creds = make(datastore.Credentials) for _, cred := range cred_data { user, user_ok := cred["user"] pass, pass_ok := cred["pass"] if user_ok && pass_ok { creds[user] = pass } else { err = errors.NewServiceErrorMissingValue("user or pass") break } } } return creds, err }
func (sm *Manager) Login(ctx context.Context, u *url.Userinfo) error { req := types.Login{ This: sm.Reference(), } if u != nil { req.UserName = u.Username() if pw, ok := u.Password(); ok { req.Password = pw } } login, err := methods.Login(ctx, sm.client, &req) if err != nil { return err } sm.userSession = &login.Returnval return nil }
// Send constructs and sends an HTTP request. func (s *Session) Send(r *Request) (response *Response, err error) { r.Method = strings.ToUpper(r.Method) // // Create a URL object from the raw url string. This will allow us to compose // query parameters programmatically and be guaranteed of a well-formed URL. // u, err := url.Parse(r.Url) if err != nil { s.log("URL", r.Url) s.log(err) return } // // Default query parameters // p := Params{} if s.Params != nil { for k, v := range *s.Params { p[k] = v } } // // User-supplied params override default // if r.Params != nil { for k, v := range *r.Params { p[k] = v } } // // Encode parameters // vals := u.Query() for k, v := range p { vals.Set(k, v) } u.RawQuery = vals.Encode() // // Create a Request object; if populated, Data field is JSON encoded as // request body // header := http.Header{} if s.Header != nil { for k, _ := range *s.Header { v := s.Header.Get(k) header.Set(k, v) } } var req *http.Request var buf *bytes.Buffer if r.Payload != nil { if r.RawPayload { var ok bool // buf can be nil interface at this point // so we'll do extra nil check buf, ok = r.Payload.(*bytes.Buffer) if !ok { err = errors.New("Payload must be of type *bytes.Buffer if RawPayload is set to true") return } } else { var b []byte b, err = json.Marshal(&r.Payload) if err != nil { s.log(err) return } buf = bytes.NewBuffer(b) } if buf != nil { req, err = http.NewRequest(r.Method, u.String(), buf) } else { req, err = http.NewRequest(r.Method, u.String(), nil) } if err != nil { s.log(err) return } header.Add("Content-Type", "application/json") } else { // no data to encode req, err = http.NewRequest(r.Method, u.String(), nil) if err != nil { s.log(err) return } } // // Merge Session and Request options // var userinfo *url.Userinfo if u.User != nil { userinfo = u.User } if s.Userinfo != nil { userinfo = s.Userinfo } // Prefer Request's user credentials if r.Userinfo != nil { userinfo = r.Userinfo } if r.Header != nil { for k, v := range *r.Header { header.Set(k, v[0]) // Is there always guarnateed to be at least one value for a header? } } if header.Get("Accept") == "" { header.Add("Accept", "application/json") // Default, can be overridden with Opts } req.Header = header // // Set HTTP Basic authentication if userinfo is supplied // if userinfo != nil { pwd, _ := userinfo.Password() req.SetBasicAuth(userinfo.Username(), pwd) if u.Scheme != "https" { s.log("WARNING: Using HTTP Basic Auth in cleartext is insecure.") } } // // Execute the HTTP request // // Debug log request s.log("--------------------------------------------------------------------------------") s.log("REQUEST") s.log("--------------------------------------------------------------------------------") s.log(pretty(req)) s.log("Payload:") if r.RawPayload && s.Log && buf != nil { s.log(base64.StdEncoding.EncodeToString(buf.Bytes())) } else { s.log(pretty(r.Payload)) } r.timestamp = time.Now() var client *http.Client if s.Client != nil { client = s.Client } else { client = &http.Client{} s.Client = client } resp, err := client.Do(req) if err != nil { s.log(err) return } defer resp.Body.Close() r.status = resp.StatusCode r.response = resp // // Unmarshal // r.body, err = ioutil.ReadAll(resp.Body) if err != nil { s.log(err) return } if string(r.body) != "" { if resp.StatusCode < 300 && r.Result != nil { err = json.Unmarshal(r.body, r.Result) } if resp.StatusCode >= 400 && r.Error != nil { json.Unmarshal(r.body, r.Error) // Should we ignore unmarshall error? } } rsp := Response(*r) response = &rsp // Debug log response s.log("--------------------------------------------------------------------------------") s.log("RESPONSE") s.log("--------------------------------------------------------------------------------") s.log("Status: ", response.status) s.log("Header:") s.log(pretty(response.HttpResponse().Header)) s.log("Body:") if response.body != nil { raw := json.RawMessage{} if json.Unmarshal(response.body, &raw) == nil { s.log(pretty(&raw)) } else { s.log(pretty(response.RawText())) } } else { s.log("Empty response body") } return }
func basicAuth(user *url.Userinfo) string { username := user.Username() password, _ := user.Password() return "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password)) }
// Send constructs and sends an HTTP request. func (s *Session) SendPB(r *Request) (response *Response, err error) { startTime := time.Now() r.Method = strings.ToUpper(r.Method) u, err := url.Parse(r.Url) if err != nil { s.log("URL", r.Url) s.log(err) return } p := Params{} if s.Params != nil { for k, v := range *s.Params { p[k] = v } } if r.Params != nil { for k, v := range *r.Params { p[k] = v } } vals := u.Query() for k, v := range p { vals.Set(k, v) } u.RawQuery = vals.Encode() header := http.Header{} if s.Header != nil { for k := range *s.Header { v := s.Header.Get(k) header.Set(k, v) } } var req *http.Request var buf *bytes.Buffer if r.Payload != nil { if r.RawPayload { var ok bool buf, ok = r.Payload.(*bytes.Buffer) if !ok { err = errors.New("Payload must be of type *bytes.Buffer if RawPayload is set to true") return } } else { var b []byte b, err = json.Marshal(&r.Payload) if err != nil { s.log(err) return } buf = bytes.NewBuffer(b) } if buf != nil { req, err = http.NewRequest(r.Method, u.String(), buf) } else { req, err = http.NewRequest(r.Method, u.String(), nil) } if err != nil { s.log(err) return } header.Add("Content-Type", "application/json") } else { // no data to encode req, err = http.NewRequest(r.Method, u.String(), nil) if err != nil { s.log(err) return } } var userinfo *url.Userinfo if u.User != nil { userinfo = u.User } if s.Userinfo != nil { userinfo = s.Userinfo } // Prefer Request's user credentials if r.Userinfo != nil { userinfo = r.Userinfo } if r.Header != nil { for k, v := range *r.Header { header.Set(k, v[0]) // Is there always guarnateed to be at least one value for a header? } } if header.Get("Accept") == "" { header.Add("Accept", "application/octet-stream") } req.Header = header if userinfo != nil { pwd, _ := userinfo.Password() req.SetBasicAuth(userinfo.Username(), pwd) if u.Scheme != "https" { s.log("WARNING: Using HTTP Basic Auth in cleartext is insecure.") } } s.log("--------------------------------------------------------------------------------") s.log("REQUEST") s.log("--------------------------------------------------------------------------------") s.log(pretty(req)) s.log("Payload:") if r.RawPayload && s.Log && buf != nil { s.log(base64.StdEncoding.EncodeToString(buf.Bytes())) } else { s.log(pretty(r.Payload)) } r.timestamp = time.Now() var client *http.Client if s.Client != nil { client = s.Client } else { //client = NewClientSupportTimeout() client = &http.Client{} } resp, err := client.Do(req) if err != nil { s.log(err) fmt.Printf("[Neo4J-HTTP] | %s | %s | %s \n", r.Url, r.Method, err.Error()) return } defer resp.Body.Close() r.status = resp.StatusCode r.response = resp r.body, err = ioutil.ReadAll(resp.Body) if err != nil { s.log(err) return } if string(r.body) != "" { if resp.StatusCode < 300 && r.Result != nil { proto.Unmarshal(r.body, r.Result.(proto.Message)) } //ignore 4xx or 5xx response } rsp := Response(*r) response = &rsp s.log("--------------------------------------------------------------------------------") s.log("RESPONSE") s.log("--------------------------------------------------------------------------------") s.log("Status: ", response.status) s.log("Header:") s.log(pretty(response.HttpResponse().Header)) s.log("Body:") if response.body != nil { raw := json.RawMessage{} if json.Unmarshal(response.body, &raw) == nil { s.log(pretty(&raw)) } else { s.log(pretty(response.RawText())) } } else { s.log("Empty response body") } elapsed := float64(time.Since(startTime).Nanoseconds()) / 1000000.0 if elapsed > 100 { fmt.Printf("[Neo4J-HTTP] | %d | %s | %s | %d | %.2fms | \n", time.Now().UnixNano()/1e6, r.Url, r.Method, resp.StatusCode, elapsed) } return }
// Send constructs and sends an HTTP request. func (s *Session) Send(inputRequest *Request, responseResult JsonDeserializer) (response *Response, err error) { // Allocate a Response object and initialize its Result field with the responseResult we expect to see response = &Response{ Result: responseResult, } // Extract Url parsedUrl, err := url.Parse(inputRequest.Url) if err != nil { s.log("URL", inputRequest.Url) s.log(err) return } // Encode query parameters if inputRequest.QueryParams != nil { vals := parsedUrl.Query() for k, v := range *inputRequest.QueryParams { vals.Set(k, v) } parsedUrl.RawQuery = vals.Encode() } // Add generic headers header := http.Header{} if s.Header != nil { for k, _ := range *s.Header { v := s.Header.Get(k) header.Set(k, v) } } // // Add Session specific headers // // Kill Bill Tenant headers from the Session if s.ApiKey != "" && s.ApiSecret != "" { header.Set("X-Killbill-ApiKey", s.ApiKey) header.Set("X-Killbill-ApiSecret", s.ApiSecret) } // JSESSIONID if s.JsessionId != "" { header.Set("Cookie", s.JsessionId) } if inputRequest.Header != nil { for k, v := range *inputRequest.Header { header.Set(k, v[0]) } } // TODO only accept if header.Get("Accept") == "" { header.Add("Accept", "application/json") } // Create the http request var req *http.Request var buf *bytes.Buffer inputRequest.Method = strings.ToUpper(inputRequest.Method) if inputRequest.Body != nil { var b []byte b, err = json.Marshal(&inputRequest.Body) if err != nil { s.log(err) return } //fmt.Printf("JSON :") //fmt.Println(string(b)) buf = bytes.NewBuffer(b) if buf != nil { req, err = http.NewRequest(inputRequest.Method, parsedUrl.String(), buf) } else { req, err = http.NewRequest(inputRequest.Method, parsedUrl.String(), nil) } if err != nil { s.log(err) return } // TODO only support application/json header.Add("Content-Type", "application/json") } else { req, err = http.NewRequest(inputRequest.Method, parsedUrl.String(), nil) if err != nil { s.log(err) return } } // Set all headers in the request req.Header = header // Basic Auth for the request var userInfo *url.Userinfo if parsedUrl.User != nil { userInfo = parsedUrl.User } if s.Userinfo != nil { userInfo = s.Userinfo } if userInfo != nil { pwd, _ := userInfo.Password() req.SetBasicAuth(userInfo.Username(), pwd) } // Debug log request s.log("--------------------------------------------------------------------------------") s.log("REQUEST") s.log("--------------------------------------------------------------------------------") s.log(pretty(req)) s.log("Body:") s.log(pretty(inputRequest.Body)) // TODO we need to capture elapsed time response.timestamp = time.Now() // // Execute the HTTP request // var client *http.Client if s.Client != nil { client = s.Client } else { client = &http.Client{} } resp, err := client.Do(req) if err != nil { s.log(err) return } // Don't forget to close the stream on return defer resp.Body.Close() // Extract and set JSESSIONID into session s.setJsessionId(resp.Header) // // Set Response // response.status = resp.StatusCode response.httpResponse = resp // Read body if status if good if resp.StatusCode < 300 { response.body, err = ioutil.ReadAll(resp.Body) if err != nil { s.log(err) return } } else { err = errors.New(fmt.Sprintf("%s%d", "Call failed with http status ", resp.StatusCode)) } // TODO Only work for json // Deserialize json if Result was provided if string(response.body) != "" && response.Result != nil { err = response.Result.FromJson(response.body) } // Debug log response s.log("--------------------------------------------------------------------------------") s.log("RESPONSE") s.log("--------------------------------------------------------------------------------") s.log("Status: ", response.status) s.log("Result: ", response.Result) return }
// Hack based on Napping Send method to allow uploading files func (s *OSession) Upload(r *napping.Request, file []byte) (response string, err error) { r.Method = strings.ToUpper(r.Method) // // Create a URL object from the raw url string. This will allow us to compose // query parameters programmatically and be guaranteed of a well-formed URL. // u, err := url.Parse(r.Url) if err != nil { log.Printf("%v", err) return } // // Default query parameters // p := url.Values{} // // Encode parameters // u.RawQuery = p.Encode() // // Create a Request object; if populated, Data field is JSON encoded as // request body // header := http.Header{} if s.Header != nil { for k, _ := range *s.Header { v := s.Header.Get(k) header.Set(k, v) } } var req *http.Request buf := new(bytes.Buffer) w := multipart.NewWriter(buf) part, err := w.CreateFormFile("filename", "dbimport") if err != nil { log.Printf("FormFile %v", err) } part.Write(file) err = w.Close() req, err = http.NewRequest(r.Method, u.String(), buf) header.Set("Content-Type", w.FormDataContentType()) // // Merge Session and Request options // var userinfo *url.Userinfo if u.User != nil { userinfo = u.User } if s.Userinfo != nil { userinfo = s.Userinfo } // Prefer Request's user credentials if r.Userinfo != nil { userinfo = r.Userinfo } if r.Header != nil { for k, v := range *r.Header { header.Set(k, v[0]) // Is there always guarnateed to be at least one value for a header? } } if header.Get("Accept") == "" { header.Add("Accept", "application/json") // Default, can be overridden with Opts } req.Header = header // // Set HTTP Basic authentication if userinfo is supplied // if userinfo != nil { pwd, _ := userinfo.Password() req.SetBasicAuth(userinfo.Username(), pwd) if u.Scheme != "https" { //s.log("WARNING: Using HTTP Basic Auth in cleartext is insecure.") } } // // Execute the HTTP request // var client *http.Client if s.Client != nil { client = s.Client } else { client = &http.Client{} s.Client = client } resp, err := client.Do(req) if err != nil { log.Printf("%v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Body: %v", err) return } response = string(body) return }