Skip to content

Commit 41199c3

Browse files
authored
Improve parseRequestHeader function and add the unit tests and benchmarks (#712)
* Benchmarks and Unit tests for parseRequestHeader function ```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_parseRequestHeader-16 1168611 1042 ns/op 496 B/op 8 allocs/op PASS ok github.com/go-resty/resty/v2 2.383s ``` * improve the performance of parseRequestHeader ```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_parseRequestHeader-16 7956481 155.6 ns/op 0 B/op 0 allocs/op PASS ok github.com/go-resty/resty/v2 1.599s ```
1 parent b852413 commit 41199c3

File tree

2 files changed

+125
-16
lines changed

2 files changed

+125
-16
lines changed

middleware.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -116,28 +116,21 @@ func parseRequestURL(c *Client, r *Request) error {
116116
}
117117

118118
func parseRequestHeader(c *Client, r *Request) error {
119-
hdr := make(http.Header)
120-
for k := range c.Header {
121-
hdr[k] = append(hdr[k], c.Header[k]...)
122-
}
123-
124-
for k := range r.Header {
125-
hdr.Del(k)
126-
hdr[k] = append(hdr[k], r.Header[k]...)
119+
for k, v := range c.Header {
120+
if _, ok := r.Header[k]; ok {
121+
continue
122+
}
123+
r.Header[k] = v[:]
127124
}
128125

129-
if IsStringEmpty(hdr.Get(hdrUserAgentKey)) {
130-
hdr.Set(hdrUserAgentKey, hdrUserAgentValue)
126+
if IsStringEmpty(r.Header.Get(hdrUserAgentKey)) {
127+
r.Header.Set(hdrUserAgentKey, hdrUserAgentValue)
131128
}
132129

133-
ct := hdr.Get(hdrContentTypeKey)
134-
if IsStringEmpty(hdr.Get(hdrAcceptKey)) && !IsStringEmpty(ct) &&
135-
(IsJSONType(ct) || IsXMLType(ct)) {
136-
hdr.Set(hdrAcceptKey, hdr.Get(hdrContentTypeKey))
130+
if ct := r.Header.Get(hdrContentTypeKey); IsStringEmpty(r.Header.Get(hdrAcceptKey)) && !IsStringEmpty(ct) && (IsJSONType(ct) || IsXMLType(ct)) {
131+
r.Header.Set(hdrAcceptKey, r.Header.Get(hdrContentTypeKey))
137132
}
138133

139-
r.Header = hdr
140-
141134
return nil
142135
}
143136

middleware_test.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package resty
22

33
import (
4+
"net/http"
45
"net/url"
6+
"reflect"
57
"testing"
68
)
79

@@ -227,3 +229,117 @@ func Test_parseRequestURL(t *testing.T) {
227229
})
228230
}
229231
}
232+
233+
func Test_parseRequestHeader(t *testing.T) {
234+
for _, tt := range []struct {
235+
name string
236+
init func(c *Client, r *Request)
237+
expectedHeader http.Header
238+
}{
239+
{
240+
name: "headers in request",
241+
init: func(c *Client, r *Request) {
242+
r.SetHeaders(map[string]string{
243+
"foo": "1",
244+
"bar": "2",
245+
})
246+
},
247+
expectedHeader: http.Header{
248+
http.CanonicalHeaderKey("foo"): []string{"1"},
249+
http.CanonicalHeaderKey("bar"): []string{"2"},
250+
http.CanonicalHeaderKey(hdrUserAgentKey): []string{hdrUserAgentValue},
251+
},
252+
},
253+
{
254+
name: "headers in client",
255+
init: func(c *Client, r *Request) {
256+
c.SetHeaders(map[string]string{
257+
"foo": "1",
258+
"bar": "2",
259+
})
260+
},
261+
expectedHeader: http.Header{
262+
http.CanonicalHeaderKey("foo"): []string{"1"},
263+
http.CanonicalHeaderKey("bar"): []string{"2"},
264+
http.CanonicalHeaderKey(hdrUserAgentKey): []string{hdrUserAgentValue},
265+
},
266+
},
267+
{
268+
name: "headers in client and request",
269+
init: func(c *Client, r *Request) {
270+
c.SetHeaders(map[string]string{
271+
"foo": "1", // ignored, because of the same header in the request
272+
"bar": "2",
273+
})
274+
r.SetHeaders(map[string]string{
275+
"foo": "3",
276+
"xyz": "4",
277+
})
278+
},
279+
expectedHeader: http.Header{
280+
http.CanonicalHeaderKey("foo"): []string{"3"},
281+
http.CanonicalHeaderKey("bar"): []string{"2"},
282+
http.CanonicalHeaderKey("xyz"): []string{"4"},
283+
http.CanonicalHeaderKey(hdrUserAgentKey): []string{hdrUserAgentValue},
284+
},
285+
},
286+
{
287+
name: "no headers",
288+
init: func(c *Client, r *Request) {},
289+
expectedHeader: http.Header{
290+
http.CanonicalHeaderKey(hdrUserAgentKey): []string{hdrUserAgentValue},
291+
},
292+
},
293+
{
294+
name: "user agent",
295+
init: func(c *Client, r *Request) {
296+
c.SetHeader(hdrUserAgentKey, "foo bar")
297+
},
298+
expectedHeader: http.Header{
299+
http.CanonicalHeaderKey(hdrUserAgentKey): []string{"foo bar"},
300+
},
301+
},
302+
{
303+
name: "json content type",
304+
init: func(c *Client, r *Request) {
305+
c.SetHeader(hdrContentTypeKey, "application/json")
306+
},
307+
expectedHeader: http.Header{
308+
http.CanonicalHeaderKey(hdrContentTypeKey): []string{"application/json"},
309+
http.CanonicalHeaderKey(hdrAcceptKey): []string{"application/json"},
310+
http.CanonicalHeaderKey(hdrUserAgentKey): []string{hdrUserAgentValue},
311+
},
312+
},
313+
} {
314+
t.Run(tt.name, func(t *testing.T) {
315+
c := New()
316+
r := c.R()
317+
tt.init(c, r)
318+
if err := parseRequestHeader(c, r); err != nil {
319+
t.Errorf("parseRequestHeader() error = %v", err)
320+
}
321+
if !reflect.DeepEqual(tt.expectedHeader, r.Header) {
322+
t.Errorf("r.Header = %#+v does not match expected %#+v", r.Header, tt.expectedHeader)
323+
}
324+
})
325+
}
326+
}
327+
328+
func Benchmark_parseRequestHeader(b *testing.B) {
329+
c := New()
330+
r := c.R()
331+
c.SetHeaders(map[string]string{
332+
"foo": "1", // ignored, because of the same header in the request
333+
"bar": "2",
334+
})
335+
r.SetHeaders(map[string]string{
336+
"foo": "3",
337+
"xyz": "4",
338+
})
339+
b.ResetTimer()
340+
for i := 0; i < b.N; i++ {
341+
if err := parseRequestHeader(c, r); err != nil {
342+
b.Errorf("parseRequestHeader() error = %v", err)
343+
}
344+
}
345+
}

0 commit comments

Comments
 (0)