Skip to content

Commit a1e722f

Browse files
committed
Adding the httpu package
Signed-off-by: Dušan Mitrović <[email protected]>
1 parent 46cb3af commit a1e722f

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-0
lines changed

constants/sizemultiples.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package constants
2+
3+
const (
4+
KiB = 1 << 10
5+
MiB = 1 << 20
6+
GiB = 1 << 30
7+
TiB = 1 << 40
8+
)

httpu/httpu.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package httpu
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"io"
7+
"net/http"
8+
"strings"
9+
10+
"github.com/nano-interactive/go-utils/v2/constants"
11+
)
12+
13+
var (
14+
ErrNoRequestURL = errors.New("request url is empty")
15+
)
16+
17+
func CurlFromRequest(request *http.Request) (string, error) {
18+
if request.URL == nil {
19+
return "", ErrNoRequestURL
20+
}
21+
22+
var b strings.Builder
23+
if request.Body == nil {
24+
b.Grow(1 * constants.KiB)
25+
} else {
26+
// It's better to overestimate
27+
// the amount of required memory
28+
// than to not allocate enough.
29+
b.Grow(1 * constants.MiB)
30+
}
31+
32+
b.WriteString("curl -s -v -X ")
33+
b.WriteString(request.Method)
34+
b.WriteRune(' ')
35+
36+
for headerName, headerValues := range request.Header {
37+
for _, headerValue := range headerValues {
38+
b.WriteString("-H '")
39+
b.WriteString(headerName)
40+
b.WriteString(": ")
41+
b.WriteString(headerValue)
42+
b.WriteString("' ")
43+
}
44+
}
45+
46+
if request.Body != nil {
47+
var buff bytes.Buffer
48+
_, err := buff.ReadFrom(request.Body)
49+
if err != nil {
50+
return "", err
51+
}
52+
53+
b.WriteString("-d '")
54+
b.WriteString(buff.String())
55+
b.WriteString("' ")
56+
57+
// reset the body after reading
58+
request.Body = io.NopCloser(bytes.NewBuffer(buff.Bytes()))
59+
}
60+
61+
b.WriteString("--compressed '")
62+
b.WriteString(request.URL.String())
63+
b.WriteString("'")
64+
65+
return b.String(), nil
66+
}

httpu/httpu_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package httpu_test
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"net/http"
7+
"net/url"
8+
"testing"
9+
10+
"github.com/nano-interactive/go-utils/v2/httpu"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestCurlFromRequest(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
request *http.Request
18+
expected string
19+
err error
20+
}{
21+
{
22+
name: "Valid GET request",
23+
request: &http.Request{
24+
Method: http.MethodGet,
25+
URL: &url.URL{Scheme: "http", Host: "example.com", Path: "/"},
26+
Header: http.Header{
27+
"User-Agent": []string{"test-agent"},
28+
},
29+
},
30+
expected: "curl -s -v -X GET -H 'User-Agent: test-agent' --compressed 'http://example.com/'",
31+
err: nil,
32+
},
33+
{
34+
name: "Valid POST request with body",
35+
request: &http.Request{
36+
Method: http.MethodPost,
37+
URL: &url.URL{Scheme: "http", Host: "example.com", Path: "/submit"},
38+
Header: http.Header{
39+
"Content-Type": []string{"application/json"},
40+
},
41+
Body: io.NopCloser(bytes.NewBufferString(`{"key":"value"}`)),
42+
},
43+
expected: "curl -s -v -X POST -H 'Content-Type: application/json' -d '{\"key\":\"value\"}' --compressed 'http://example.com/submit'",
44+
err: nil,
45+
},
46+
{
47+
name: "Request with no URL",
48+
request: &http.Request{
49+
Method: http.MethodGet,
50+
URL: nil,
51+
},
52+
expected: "",
53+
err: httpu.ErrNoRequestURL,
54+
},
55+
{
56+
name: "Request with multiple headers",
57+
request: &http.Request{
58+
Method: http.MethodGet,
59+
URL: &url.URL{Scheme: "http", Host: "example.com", Path: "/"},
60+
Header: http.Header{
61+
"User-Agent": []string{"test-agent"},
62+
"Accept": []string{"application/json", "text/html"},
63+
},
64+
},
65+
expected: "curl -s -v -X GET -H 'User-Agent: test-agent' -H 'Accept: application/json' -H 'Accept: text/html' --compressed 'http://example.com/'",
66+
err: nil,
67+
},
68+
}
69+
70+
for _, tt := range tests {
71+
t.Run(tt.name, func(t *testing.T) {
72+
result, err := httpu.CurlFromRequest(tt.request)
73+
74+
if tt.err != nil {
75+
assert.Error(t, err)
76+
assert.Equal(t, tt.err.Error(), err.Error())
77+
} else {
78+
assert.NoError(t, err)
79+
assert.Equal(t, tt.expected, result)
80+
}
81+
})
82+
}
83+
}

0 commit comments

Comments
 (0)