Skip to content

Commit a3c54bb

Browse files
authored
🐛 bug: Respect DisablePathNormalizing during client requests (#3773)
1 parent 58514f3 commit a3c54bb

4 files changed

Lines changed: 84 additions & 15 deletions

File tree

client/client.go

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ type Client struct {
5555
userResponseHooks []ResponseHook
5656
builtinResponseHooks []ResponseHook
5757

58-
timeout time.Duration
59-
mu sync.RWMutex
60-
debug bool
58+
timeout time.Duration
59+
mu sync.RWMutex
60+
debug bool
61+
disablePathNormalizing bool
6162
}
6263

6364
// R creates a new Request associated with the client.
@@ -353,6 +354,17 @@ func (c *Client) SetReferer(r string) *Client {
353354
return c
354355
}
355356

357+
// DisablePathNormalizing reports whether path normalizing is disabled for the client.
358+
func (c *Client) DisablePathNormalizing() bool {
359+
return c.disablePathNormalizing
360+
}
361+
362+
// SetDisablePathNormalizing configures the client to disable or enable path normalizing.
363+
func (c *Client) SetDisablePathNormalizing(disable bool) *Client {
364+
c.disablePathNormalizing = disable
365+
return c
366+
}
367+
356368
// PathParam returns the value of the specified path parameter. Returns an empty string if it does not exist.
357369
func (c *Client) PathParam(key string) string {
358370
if val, ok := (*c.path)[key]; ok {
@@ -529,6 +541,7 @@ func (c *Client) Reset() {
529541
c.referer = ""
530542
c.retryConfig = nil
531543
c.debug = false
544+
c.disablePathNormalizing = false
532545

533546
if c.cookieJar != nil {
534547
c.cookieJar.Release()
@@ -545,18 +558,19 @@ func (c *Client) Reset() {
545558
// JSON is used as the default serialization mechanism. The priority is:
546559
// Body > FormData > File.
547560
type Config struct {
548-
Ctx context.Context //nolint:containedctx // It's needed to be stored in the config.
549-
Body any
550-
Header map[string]string
551-
Param map[string]string
552-
Cookie map[string]string
553-
PathParam map[string]string
554-
FormData map[string]string
555-
UserAgent string
556-
Referer string
557-
File []*File
558-
Timeout time.Duration
559-
MaxRedirects int
561+
Ctx context.Context //nolint:containedctx // It's needed to be stored in the config.
562+
Body any
563+
Header map[string]string
564+
Param map[string]string
565+
Cookie map[string]string
566+
PathParam map[string]string
567+
FormData map[string]string
568+
UserAgent string
569+
Referer string
570+
File []*File
571+
Timeout time.Duration
572+
MaxRedirects int
573+
DisablePathNormalizing bool
560574
}
561575

562576
// setConfigToRequest sets the parameters passed via Config to the Request.
@@ -602,6 +616,10 @@ func setConfigToRequest(req *Request, config ...Config) {
602616
req.SetMaxRedirects(cfg.MaxRedirects)
603617
}
604618

619+
if cfg.DisablePathNormalizing {
620+
req.SetDisablePathNormalizing(true)
621+
}
622+
605623
if cfg.Body != nil {
606624
req.SetJSON(cfg.Body)
607625
return

client/hooks.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ func parserRequestURL(c *Client, req *Request) error {
9393
}
9494

9595
// Set the URI in the raw request.
96+
disablePathNormalizing := c.DisablePathNormalizing() || req.DisablePathNormalizing()
9697
req.RawRequest.SetRequestURI(uri)
98+
req.RawRequest.URI().DisablePathNormalizing = disablePathNormalizing
99+
if disablePathNormalizing {
100+
req.RawRequest.URI().SetPathBytes(req.RawRequest.URI().PathOriginal())
101+
}
97102

98103
// Merge query parameters.
99104
hashSplit := strings.Split(splitURL[1], "#")

client/hooks_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,37 @@ func Test_Parser_Request_URL(t *testing.T) {
207207
require.True(t, flag2)
208208
require.True(t, flag3)
209209
})
210+
211+
t.Run("request disable path normalizing should be respected", func(t *testing.T) {
212+
t.Parallel()
213+
client := New()
214+
req := AcquireRequest().
215+
SetURL("https://example.my.host/other.host%2Fpath%2Fto%2Fdata%23123").
216+
SetDisablePathNormalizing(true)
217+
218+
t.Cleanup(func() {
219+
ReleaseRequest(req)
220+
})
221+
222+
err := parserRequestURL(client, req)
223+
require.NoError(t, err)
224+
require.Equal(t, "https://example.my.host/other.host%2Fpath%2Fto%2Fdata%23123", req.RawRequest.URI().String())
225+
})
226+
227+
t.Run("client disable path normalizing should be respected", func(t *testing.T) {
228+
t.Parallel()
229+
client := New().SetDisablePathNormalizing(true)
230+
req := AcquireRequest().
231+
SetURL("https://example.my.host/other.host%2Fpath%2Fto%2Fdata%23123")
232+
233+
t.Cleanup(func() {
234+
ReleaseRequest(req)
235+
})
236+
237+
err := parserRequestURL(client, req)
238+
require.NoError(t, err)
239+
require.Equal(t, "https://example.my.host/other.host%2Fpath%2Fto%2Fdata%23123", req.RawRequest.URI().String())
240+
})
210241
}
211242

212243
func Test_Parser_Request_Header(t *testing.T) {

client/request.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ type Request struct {
6868
maxRedirects int
6969

7070
bodyType bodyType
71+
72+
disablePathNormalizing bool
7173
}
7274

7375
// Method returns the HTTP method set in the Request.
@@ -605,6 +607,18 @@ func (r *Request) SetMaxRedirects(count int) *Request {
605607
return r
606608
}
607609

610+
// DisablePathNormalizing reports whether path normalizing is disabled for the Request.
611+
func (r *Request) DisablePathNormalizing() bool {
612+
return r.disablePathNormalizing
613+
}
614+
615+
// SetDisablePathNormalizing configures the Request to disable or enable path normalizing.
616+
func (r *Request) SetDisablePathNormalizing(disable bool) *Request {
617+
r.disablePathNormalizing = disable
618+
r.RawRequest.URI().DisablePathNormalizing = disable
619+
return r
620+
}
621+
608622
// checkClient ensures that a Client is set. If none is set, it defaults to the global defaultClient.
609623
func (r *Request) checkClient() {
610624
if r.client == nil {
@@ -671,6 +685,7 @@ func (r *Request) Reset() {
671685
r.maxRedirects = 0
672686
r.bodyType = noBody
673687
r.boundary = boundary
688+
r.disablePathNormalizing = false
674689

675690
for len(r.files) != 0 {
676691
t := r.files[0]

0 commit comments

Comments
 (0)