Skip to content

Commit

Permalink
improve parseRequesBody and add additional benchmarks
Browse files Browse the repository at this point in the history
Final benchmarks:
```shell
 % go test -benchmem -bench=. -run=^Benchmark
goos: darwin
goarch: amd64
pkg: github.com/go-resty/resty/v2
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Benchmark_parseRequestBody_string-16                                     7623501               155.3 ns/op            16 B/op          1 allocs/op
Benchmark_parseRequestBody_byte-16                                       8421992               141.6 ns/op            16 B/op          1 allocs/op
Benchmark_parseRequestBody_reader_with_SetContentLength-16              17632350                67.37 ns/op           16 B/op          1 allocs/op
Benchmark_parseRequestBody_reader_without_SetContentLength-16           26575016                45.34 ns/op            0 B/op          0 allocs/op
Benchmark_parseRequestBody_struct-16                                     1243986               953.8 ns/op            40 B/op          2 allocs/op
Benchmark_parseRequestBody_struct_xml-16                                  495250              2458 ns/op            4647 B/op         10 allocs/op
Benchmark_parseRequestBody_map-16                                         694786              1761 ns/op             454 B/op         12 allocs/op
Benchmark_parseRequestBody_slice-16                                      1304724               913.1 ns/op            32 B/op          2 allocs/op
Benchmark_parseRequestBody_FormData-16                                   1000000              1128 ns/op             272 B/op          9 allocs/op
Benchmark_parseRequestBody_MultiPart-16                                    93248             12583 ns/op            8738 B/op        130 allocs/op
```
  • Loading branch information
SVilgelm committed Sep 29, 2023
1 parent bed3f36 commit a950b1e
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 46 deletions.
66 changes: 24 additions & 42 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
"time"
)
Expand Down Expand Up @@ -134,45 +135,34 @@ func parseRequestHeader(c *Client, r *Request) error {
return nil
}

func parseRequestBody(c *Client, r *Request) (err error) {
func parseRequestBody(c *Client, r *Request) error {
if isPayloadSupported(r.Method, c.AllowGetMethodPayload) {
// Handling Multipart
if r.isMultiPart {
if err = handleMultipart(c, r); err != nil {
return
switch {
case r.isMultiPart: // Handling Multipart
if err := handleMultipart(c, r); err != nil {
return err
}

goto CL
}

// Handling Form Data
if len(c.FormData) > 0 || len(r.FormData) > 0 {
case len(c.FormData) > 0 || len(r.FormData) > 0: // Handling Form Data
handleFormData(c, r)

goto CL
}

// Handling Request body
if r.Body != nil {
case r.Body != nil: // Handling Request body
handleContentType(c, r)

if err = handleRequestBody(c, r); err != nil {
return
if err := handleRequestBody(c, r); err != nil {
return err
}
}
}

CL:
// by default resty won't set content length, you can if you want to :)
if c.setContentLength || r.setContentLength {
if r.bodyBuf == nil {
r.Header.Set(hdrContentLengthKey, "0")
} else {
r.Header.Set(hdrContentLengthKey, fmt.Sprintf("%d", r.bodyBuf.Len()))
r.Header.Set(hdrContentLengthKey, strconv.Itoa(r.bodyBuf.Len()))
}
}

return
return nil
}

func createHTTPRequest(c *Client, r *Request) (err error) {
Expand Down Expand Up @@ -370,13 +360,13 @@ func parseResponseBody(c *Client, res *Response) (err error) {
return
}

func handleMultipart(c *Client, r *Request) (err error) {
func handleMultipart(c *Client, r *Request) error {
r.bodyBuf = acquireBuffer()
w := multipart.NewWriter(r.bodyBuf)

for k, v := range c.FormData {
for _, iv := range v {
if err = w.WriteField(k, iv); err != nil {
if err := w.WriteField(k, iv); err != nil {
return err
}
}
Expand All @@ -385,41 +375,33 @@ func handleMultipart(c *Client, r *Request) (err error) {
for k, v := range r.FormData {
for _, iv := range v {
if strings.HasPrefix(k, "@") { // file
err = addFile(w, k[1:], iv)
if err != nil {
return
if err := addFile(w, k[1:], iv); err != nil {
return err
}
} else { // form value
if err = w.WriteField(k, iv); err != nil {
if err := w.WriteField(k, iv); err != nil {
return err
}
}
}
}

// #21 - adding io.Reader support
if len(r.multipartFiles) > 0 {
for _, f := range r.multipartFiles {
err = addFileReader(w, f)
if err != nil {
return
}
for _, f := range r.multipartFiles {
if err := addFileReader(w, f); err != nil {
return err

Check warning on line 392 in middleware.go

View check run for this annotation

Codecov / codecov/patch

middleware.go#L392

Added line #L392 was not covered by tests
}
}

// GitHub #130 adding multipart field support with content type
if len(r.multipartFields) > 0 {
for _, mf := range r.multipartFields {
if err = addMultipartFormField(w, mf); err != nil {
return
}
for _, mf := range r.multipartFields {
if err := addMultipartFormField(w, mf); err != nil {
return err

Check warning on line 399 in middleware.go

View check run for this annotation

Codecov / codecov/patch

middleware.go#L399

Added line #L399 was not covered by tests
}
}

r.Header.Set(hdrContentTypeKey, w.FormDataContentType())
err = w.Close()

return
return w.Close()
}

func handleFormData(c *Client, r *Request) {
Expand Down
19 changes: 15 additions & 4 deletions middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ func Benchmark_parseRequestBody_byte(b *testing.B) {
}
}

func Benchmark_parseRequestBody_reader(b *testing.B) {
func Benchmark_parseRequestBody_reader_with_SetContentLength(b *testing.B) {
c := New()
r := c.R()
r.SetBody(bytes.NewBufferString("foo")).SetContentLength(true)
Expand All @@ -797,6 +797,17 @@ func Benchmark_parseRequestBody_reader(b *testing.B) {
}
}
}
func Benchmark_parseRequestBody_reader_without_SetContentLength(b *testing.B) {
c := New()
r := c.R()
r.SetBody(bytes.NewBufferString("foo"))
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := parseRequestBody(c, r); err != nil {
b.Errorf("parseRequestBody() error = %v", err)
}
}
}

func Benchmark_parseRequestBody_struct(b *testing.B) {
type FooBar struct {
Expand All @@ -805,7 +816,7 @@ func Benchmark_parseRequestBody_struct(b *testing.B) {
}
c := New()
r := c.R()
r.SetBody(FooBar{Foo: "1", Bar: "2"}).SetContentLength(true)
r.SetBody(FooBar{Foo: "1", Bar: "2"}).SetContentLength(true).SetHeader(hdrContentTypeKey, jsonContentType)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := parseRequestBody(c, r); err != nil {
Expand Down Expand Up @@ -836,7 +847,7 @@ func Benchmark_parseRequestBody_map(b *testing.B) {
r.SetBody(map[string]string{
"foo": "1",
"bar": "2",
}).SetContentLength(true)
}).SetContentLength(true).SetHeader(hdrContentTypeKey, jsonContentType)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := parseRequestBody(c, r); err != nil {
Expand All @@ -848,7 +859,7 @@ func Benchmark_parseRequestBody_map(b *testing.B) {
func Benchmark_parseRequestBody_slice(b *testing.B) {
c := New()
r := c.R()
r.SetBody([]string{"1", "2"}).SetContentLength(true)
r.SetBody([]string{"1", "2"}).SetContentLength(true).SetHeader(hdrContentTypeKey, jsonContentType)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := parseRequestBody(c, r); err != nil {
Expand Down

0 comments on commit a950b1e

Please sign in to comment.