Example #1
0
// 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())
	}
}
Example #2
0
// 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
}
Example #3
0
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
}
Example #4
0
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())
	}
}
Example #5
0
// 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
}
Example #6
0
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
}
Example #7
0
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
}
Example #8
0
// 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
}