http2curl.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package http2curl
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net/http"
  8. "sort"
  9. "strings"
  10. )
  11. // CurlCommand contains exec.Command compatible slice + helpers
  12. type CurlCommand struct {
  13. slice []string
  14. }
  15. // append appends a string to the CurlCommand
  16. func (c *CurlCommand) append(newSlice ...string) {
  17. c.slice = append(c.slice, newSlice...)
  18. }
  19. // String returns a ready to copy/paste command
  20. func (c *CurlCommand) String() string {
  21. return strings.Join(c.slice, " ")
  22. }
  23. // nopCloser is used to create a new io.ReadCloser for req.Body
  24. type nopCloser struct {
  25. io.Reader
  26. }
  27. func bashEscape(str string) string {
  28. return `'` + strings.Replace(str, `'`, `'\''`, -1) + `'`
  29. }
  30. func (nopCloser) Close() error { return nil }
  31. // GetCurlCommand returns a CurlCommand corresponding to an http.Request
  32. func GetCurlCommand(req *http.Request) (*CurlCommand, error) {
  33. command := CurlCommand{}
  34. command.append("curl")
  35. command.append("-X", bashEscape(req.Method))
  36. if req.Body != nil {
  37. body, err := ioutil.ReadAll(req.Body)
  38. if err != nil {
  39. return nil, err
  40. }
  41. req.Body = nopCloser{bytes.NewBuffer(body)}
  42. bodyEscaped := bashEscape(string(body))
  43. command.append("-d", bodyEscaped)
  44. }
  45. var keys []string
  46. for k := range req.Header {
  47. keys = append(keys, k)
  48. }
  49. sort.Strings(keys)
  50. for _, k := range keys {
  51. command.append("-H", bashEscape(fmt.Sprintf("%s: %s", k, strings.Join(req.Header[k], " "))))
  52. }
  53. command.append(bashEscape(req.URL.String()))
  54. return &command, nil
  55. }