// Request implements Printer.Request. func (p CurlPrinter) Request(req *http.Request) { if req != nil { cmd, err := http2curl.GetCurlCommand(req) if err != nil { panic(err) } p.logger.Logf("%s", cmd.String()) } }
// AsCurlCommand returns a string representing the runnable `curl' command // version of the request. func (s *SuperAgent) AsCurlCommand() (string, error) { req, err := s.MakeRequest() if err != nil { return "", err } cmd, err := http2curl.GetCurlCommand(req) if err != nil { return "", err } return cmd.String(), nil }
func (s *SuperAgent) doDry(req *http.Request) error { if s.Dry { command, err := http2curl.GetCurlCommand(req) if err != nil { return errors.New(err) } return errors.Errorf("Because you are using the dry option, the request will not be executed. You can execute this command using: \n\n%s", command) } return nil }
func (l *cliLogger) LogHTTP(req *http.Request) { curl, err := http2curl.GetCurlCommand(req) if err != nil { l.Fatalf("Failed to convert to curl request: %q", err) } if os.Getenv("SCW_SENSITIVE") != "1" { l.Debug(l.s.HideAPICredentials(curl.String())) } else { l.Debug(curl.String()) } }
// EndBytes should be used when you want the body as bytes. The callbacks work the same way as with `End`, except that a byte array is used instead of a string. func (s *SuperAgent) EndBytes(callback ...func(response Response, body []byte, errs []error)) (Response, []byte, []error) { var ( req *http.Request err error resp Response ) // check whether there is an error. if yes, return all errors if len(s.Errors) != 0 { return nil, nil, s.Errors } // check if there is forced type switch s.ForceType { case "json", "form", "xml", "text": s.TargetType = s.ForceType // If forcetype is not set, check whether user set Content-Type header. // If yes, also bounce to the correct supported TargetType automatically. default: for k, v := range Types { if s.Header["Content-Type"] == v { s.TargetType = k } } } // if slice and map get mixed, let's bounce to rawstring if len(s.Data) != 0 && len(s.SliceData) != 0 { s.BounceToRawString = true } switch s.Method { case POST, PUT, PATCH: if s.TargetType == "json" { // If-case to give support to json array. we check if // 1) Map only: send it as json map from s.Data // 2) Array or Mix of map & array or others: send it as rawstring from s.RawString var contentJson []byte if s.BounceToRawString { contentJson = []byte(s.RawString) } else if len(s.Data) != 0 { contentJson, _ = json.Marshal(s.Data) } else if len(s.SliceData) != 0 { contentJson, _ = json.Marshal(s.SliceData) } contentReader := bytes.NewReader(contentJson) req, err = http.NewRequest(s.Method, s.Url, contentReader) if err != nil { s.Errors = append(s.Errors, err) return nil, nil, s.Errors } req.Header.Set("Content-Type", "application/json") } else if s.TargetType == "form" { var contentForm []byte if s.BounceToRawString || len(s.SliceData) != 0 { contentForm = []byte(s.RawString) } else { formData := changeMapToURLValues(s.Data) contentForm = []byte(formData.Encode()) } contentReader := bytes.NewReader(contentForm) req, err = http.NewRequest(s.Method, s.Url, contentReader) if err != nil { s.Errors = append(s.Errors, err) return nil, nil, s.Errors } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } else if s.TargetType == "text" { req, err = http.NewRequest(s.Method, s.Url, strings.NewReader(s.RawString)) req.Header.Set("Content-Type", "text/plain") } else if s.TargetType == "xml" { req, err = http.NewRequest(s.Method, s.Url, strings.NewReader(s.RawString)) req.Header.Set("Content-Type", "application/xml") } else { // TODO: if nothing match, let's return warning here } case GET, HEAD, DELETE: req, err = http.NewRequest(s.Method, s.Url, nil) if err != nil { s.Errors = append(s.Errors, err) return nil, nil, s.Errors } } for k, v := range s.Header { req.Header.Set(k, v) } // Add all querystring from Query func q := req.URL.Query() for k, v := range s.QueryData { for _, vv := range v { q.Add(k, vv) } } req.URL.RawQuery = q.Encode() // Add basic auth if s.BasicAuth != struct{ Username, Password string }{} { req.SetBasicAuth(s.BasicAuth.Username, s.BasicAuth.Password) } // Add cookies for _, cookie := range s.Cookies { req.AddCookie(cookie) } // Set Transport if !DisableTransportSwap { s.Client.Transport = s.Transport } // Log details of this request if s.Debug { dump, err := httputil.DumpRequest(req, true) s.logger.SetPrefix("[http] ") if err != nil { s.logger.Println("Error:", err) } else { s.logger.Printf("HTTP Request: %s", string(dump)) } } // Display CURL command line if s.CurlCommand { curl, err := http2curl.GetCurlCommand(req) s.logger.SetPrefix("[curl] ") if err != nil { s.logger.Println("Error:", err) } else { s.logger.Printf("CURL command line: %s", curl) } } // Send request resp, err = s.Client.Do(req) if err != nil { s.Errors = append(s.Errors, err) return nil, nil, s.Errors } defer resp.Body.Close() // Log details of this response if s.Debug { dump, err := httputil.DumpResponse(resp, true) if nil != err { s.logger.Println("Error:", err) } else { s.logger.Printf("HTTP Response: %s", string(dump)) } } body, _ := ioutil.ReadAll(resp.Body) // Reset resp.Body so it can be use again resp.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // deep copy response to give it to both return and callback func respCallback := *resp if len(callback) != 0 { callback[0](&respCallback, body, s.Errors) } return resp, body, nil }
func (s *SuperAgent) getResponseBytes() (Response, []byte, []error) { var ( req *http.Request err error resp Response ) // check whether there is an error. if yes, return all errors if len(s.Errors) != 0 { return nil, nil, s.Errors } // check if there is forced type switch s.ForceType { case "json", "form", "xml", "text": s.TargetType = s.ForceType // If forcetype is not set, check whether user set Content-Type header. // If yes, also bounce to the correct supported TargetType automatically. default: for k, v := range Types { if s.Header["Content-Type"] == v { s.TargetType = k } } } // if slice and map get mixed, let's bounce to rawstring if len(s.Data) != 0 && len(s.SliceData) != 0 { s.BounceToRawString = true } // Make Request req, err = s.MakeRequest() if err != nil { s.Errors = append(s.Errors, err) return nil, nil, s.Errors } // Set Transport if !DisableTransportSwap { s.Client.Transport = s.Transport } // Log details of this request if s.Debug { dump, err := httputil.DumpRequest(req, true) s.logger.SetPrefix("[http] ") if err != nil { s.logger.Println("Error:", err) } else { s.logger.Printf("HTTP Request: %s", string(dump)) } } // Display CURL command line if s.CurlCommand { curl, err := http2curl.GetCurlCommand(req) s.logger.SetPrefix("[curl] ") if err != nil { s.logger.Println("Error:", err) } else { s.logger.Printf("CURL command line: %s", curl) } } // Send request resp, err = s.Client.Do(req) if err != nil { s.Errors = append(s.Errors, err) return nil, nil, s.Errors } defer resp.Body.Close() // Log details of this response if s.Debug { dump, err := httputil.DumpResponse(resp, true) if nil != err { s.logger.Println("Error:", err) } else { s.logger.Printf("HTTP Response: %s", string(dump)) } } body, _ := ioutil.ReadAll(resp.Body) // Reset resp.Body so it can be use again resp.Body = ioutil.NopCloser(bytes.NewBuffer(body)) return resp, body, nil }
func (s *SuperAgent) MakeRequest() (*http.Request, error) { var ( req *http.Request err error ) switch s.Method { case POST, PUT, PATCH: if s.TargetType == "json" { // If-case to give support to json array. we check if // 1) Map only: send it as json map from s.Data // 2) Array or Mix of map & array or others: send it as rawstring from s.RawString var contentJson []byte if s.BounceToRawString { contentJson = []byte(s.RawString) } else if len(s.Data) != 0 { contentJson, _ = json.Marshal(s.Data) } else if len(s.SliceData) != 0 { contentJson, _ = json.Marshal(s.SliceData) } contentReader := bytes.NewReader(contentJson) req, err = http.NewRequest(s.Method, s.Url, contentReader) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") } else if s.TargetType == "form" || s.TargetType == "form-data" || s.TargetType == "urlencoded" { var contentForm []byte if s.BounceToRawString || len(s.SliceData) != 0 { contentForm = []byte(s.RawString) } else { formData := changeMapToURLValues(s.Data) contentForm = []byte(formData.Encode()) } contentReader := bytes.NewReader(contentForm) req, err = http.NewRequest(s.Method, s.Url, contentReader) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } else if s.TargetType == "text" { req, err = http.NewRequest(s.Method, s.Url, strings.NewReader(s.RawString)) req.Header.Set("Content-Type", "text/plain") } else if s.TargetType == "xml" { req, err = http.NewRequest(s.Method, s.Url, strings.NewReader(s.RawString)) req.Header.Set("Content-Type", "application/xml") } else if s.TargetType == "multipart" { var buf bytes.Buffer mw := multipart.NewWriter(&buf) if s.BounceToRawString { fieldName, ok := s.Header["data_fieldname"] if !ok { fieldName = "data" } fw, _ := mw.CreateFormField(fieldName) fw.Write([]byte(s.RawString)) } if len(s.Data) != 0 { formData := changeMapToURLValues(s.Data) for key, values := range formData { for _, value := range values { fw, _ := mw.CreateFormField(key) fw.Write([]byte(value)) } } } if len(s.SliceData) != 0 { fieldName, ok := s.Header["json_fieldname"] if !ok { fieldName = "data" } // copied from CreateFormField() in mime/multipart/writer.go h := make(textproto.MIMEHeader) fieldName = strings.Replace(strings.Replace(fieldName, "\\", "\\\\", -1), `"`, "\\\"", -1) h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"`, fieldName)) h.Set("Content-Type", "application/json") fw, _ := mw.CreatePart(h) contentJson, err := json.Marshal(s.SliceData) if err != nil { return nil, err } fw.Write(contentJson) } // add the files if len(s.FileData) != 0 { for _, file := range s.FileData { fw, _ := mw.CreateFormFile(file.Fieldname, file.Filename) fw.Write(file.Data) } } // close before call to FormDataContentType ! otherwise its not valid multipart mw.Close() req, err = http.NewRequest(s.Method, s.Url, &buf) req.Header.Set("Content-Type", mw.FormDataContentType()) } else { // let's return an error instead of an nil pointer exception here return nil, errors.New("TargetType '" + s.TargetType + "' could not be determined") } case "": return nil, errors.New("No method specified") default: req, err = http.NewRequest(s.Method, s.Url, nil) if err != nil { return nil, err } } for k, v := range s.Header { req.Header.Set(k, v) // Setting the host header is a special case, see this issue: https://github.com/golang/go/issues/7682 if strings.EqualFold(k, "host") { req.Host = v } } // Add all querystring from Query func q := req.URL.Query() for k, v := range s.QueryData { for _, vv := range v { q.Add(k, vv) } } req.URL.RawQuery = q.Encode() // Add basic auth if s.BasicAuth != struct{ Username, Password string }{} { req.SetBasicAuth(s.BasicAuth.Username, s.BasicAuth.Password) } // Add cookies for _, cookie := range s.Cookies { req.AddCookie(cookie) } return req, nil } // AsCurlCommand returns a string representing the runnable `curl' command // version of the request. func (s *SuperAgent) AsCurlCommand() (string, error) { req, err := s.MakeRequest() if err != nil { return "", err } cmd, err := http2curl.GetCurlCommand(req) if err != nil { return "", err } return cmd.String(), nil }
// EndBytes should be used when you want the body as bytes. The callbacks work the same way as with `End`, except that a byte array is used instead of a string. func (gr *GoReq) EndBytes(callback ...func(response Response, body []byte, errs []error)) (Response, []byte, []error) { var ( req *http.Request err error resp Response ) // check whether there is an error. if yes, return all errors if len(gr.Errors) != 0 { return nil, nil, gr.Errors } if gr.Header["Content-Type"] == "" { gr.Header["Content-Type"] = "application/json" } switch gr.Method { case POST, PUT, PATCH: if gr.FilePath != "" { //post a file buf, _ := newfileUploadRequest(gr, changeMapToMapString(gr.Data), gr.FileParam, gr.FilePath) req, err = http.NewRequest(gr.Method, gr.URL, buf) } else if gr.Header["Content-Type"] == "application/json" && len(gr.Data) > 0 { //json contentJSON, _ := json.Marshal(gr.Data) contentReader := bytes.NewReader(contentJSON) req, err = http.NewRequest(gr.Method, gr.URL, contentReader) } else if gr.Header["Content-Type"] == "application/x-www-form-urlencoded" { //form formData := changeMapToURLValues(gr.Data) req, err = http.NewRequest(gr.Method, gr.URL, strings.NewReader(formData.Encode())) } else if len(gr.RawBytesData) > 0 { //raw bytes req, err = http.NewRequest(gr.Method, gr.URL, bytes.NewReader(gr.RawBytesData)) } else { //raw string req, err = http.NewRequest(gr.Method, gr.URL, strings.NewReader(gr.RawStringData)) } case GET, HEAD, DELETE, OPTIONS: req, err = http.NewRequest(gr.Method, gr.URL, nil) default: gr.Errors = append(gr.Errors, errors.New("No method specified")) return nil, nil, gr.Errors } initRequest(req, gr) // Log details of this request if gr.Debug { dump, err := httputil.DumpRequest(req, true) gr.logger.SetPrefix("[http] ") if err != nil { gr.logger.Printf("Error: %s", err.Error()) } gr.logger.Printf("HTTP Request: %s", string(dump)) } if gr.CurlCommand { curl, err := http2curl.GetCurlCommand(req) gr.logger.SetPrefix("[curl] ") if err != nil { gr.logger.Println("Error:", err) } else { gr.logger.Printf("CURL command line: %s", curl) } } // Send request resp, err = gr.retryDo(req, gr.retry.RetryCount) // Log details of this response if gr.Debug { dump, err := httputil.DumpResponse(resp, true) if nil != err { gr.logger.Println("Error: ", err.Error()) } gr.logger.Printf("HTTP Response: %s", string(dump)) } if err != nil { gr.Errors = append(gr.Errors, err) return nil, nil, gr.Errors } defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) // Reset resp.Body so it can be use again resp.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // deep copy response to give it to both return and callback func respCallback := *resp if len(callback) != 0 { callback[0](&respCallback, body, gr.Errors) } return resp, body, nil }