Skip to content

Commit

Permalink
Allow redirect URI path to not be normalized. (#1638)
Browse files Browse the repository at this point in the history
* Allow redirect URI path to not be normalized.

* Introduce DisableRedirectPathNormalizing field to Request

* Use field name as start of comment.

Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>

---------

Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>
  • Loading branch information
skidder and erikdubbelboer authored Oct 30, 2023
1 parent 772e4aa commit 42bd7bb
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 2 deletions.
5 changes: 3 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1064,16 +1064,17 @@ func doRequestFollowRedirects(req *Request, resp *Response, url string, maxRedir
err = ErrMissingLocation
break
}
url = getRedirectURL(url, location)
url = getRedirectURL(url, location, req.DisableRedirectPathNormalizing)
}

return statusCode, body, err
}

func getRedirectURL(baseURL string, location []byte) string {
func getRedirectURL(baseURL string, location []byte, disablePathNormalizing bool) string {
u := AcquireURI()
u.Update(baseURL)
u.UpdateBytes(location)
u.DisablePathNormalizing = disablePathNormalizing
redirectURL := u.String()
ReleaseURI(u)
return redirectURL
Expand Down
86 changes: 86 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1589,6 +1589,10 @@ func TestClientFollowRedirects(t *testing.T) {
u := ctx.URI()
u.Update("/bar")
ctx.Redirect(u.String(), StatusFound)
case "/abc/*/123":
u := ctx.URI()
u.Update("/xyz/*/456")
ctx.Redirect(u.String(), StatusFound)
default:
ctx.Success("text/plain", ctx.Path())
}
Expand Down Expand Up @@ -1710,6 +1714,31 @@ func TestClientFollowRedirects(t *testing.T) {
ReleaseResponse(resp)
}

for i := 0; i < 10; i++ {
req := AcquireRequest()
resp := AcquireResponse()

req.SetRequestURI("http://xxx/abc/*/123")
req.URI().DisablePathNormalizing = true
req.DisableRedirectPathNormalizing = true

err := c.DoRedirects(req, resp, 16)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

if statusCode := resp.StatusCode(); statusCode != StatusOK {
t.Fatalf("unexpected status code: %d", statusCode)
}

if body := string(resp.Body()); body != "/xyz/*/456" {
t.Fatalf("unexpected response %q. Expecting %q", body, "/xyz/*/456")
}

ReleaseRequest(req)
ReleaseResponse(resp)
}

req := AcquireRequest()
resp := AcquireResponse()

Expand Down Expand Up @@ -3306,3 +3335,60 @@ func TestClientTransportEx(t *testing.T) {
t.Errorf("round trip count should be: %v", roundTripCount)
}
}

func Test_getRedirectURL(t *testing.T) {
type args struct {
baseURL string
location []byte
disablePathNormalizing bool
}
tests := []struct {
name string
args args
want string
}{
{
name: "Path normalizing enabled, no special characters in path",
args: args{
baseURL: "http://foo.example.com/abc",
location: []byte("http://bar.example.com/def"),
disablePathNormalizing: false,
},
want: "http://bar.example.com/def",
},
{
name: "Path normalizing enabled, special characters in path",
args: args{
baseURL: "http://foo.example.com/abc/*/def",
location: []byte("http://bar.example.com/123/*/456"),
disablePathNormalizing: false,
},
want: "http://bar.example.com/123/%2A/456",
},
{
name: "Path normalizing disabled, no special characters in path",
args: args{
baseURL: "http://foo.example.com/abc",
location: []byte("http://bar.example.com/def"),
disablePathNormalizing: true,
},
want: "http://bar.example.com/def",
},
{
name: "Path normalizing disabled, special characters in path",
args: args{
baseURL: "http://foo.example.com/abc/*/def",
location: []byte("http://bar.example.com/123/*/456"),
disablePathNormalizing: true,
},
want: "http://bar.example.com/123/*/456",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getRedirectURL(tt.args.baseURL, tt.args.location, tt.args.disablePathNormalizing); got != tt.want {
t.Errorf("getRedirectURL() = %v, want %v", got, tt.want)
}
})
}
}
7 changes: 7 additions & 0 deletions http.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ type Request struct {

// Use Host header (request.Header.SetHost) instead of the host from SetRequestURI, SetHost, or URI().SetHost
UseHostHeader bool

// DisableRedirectPathNormalizing disables redirect path normalization when used with DoRedirects.
//
// By default redirect path values are normalized, i.e.
// extra slashes are removed, special characters are encoded.
DisableRedirectPathNormalizing bool
}

// Response represents HTTP response.
Expand Down Expand Up @@ -1080,6 +1086,7 @@ func (req *Request) Reset() {
req.resetSkipHeader()
req.timeout = 0
req.UseHostHeader = false
req.DisableRedirectPathNormalizing = false
}

func (req *Request) resetSkipHeader() {
Expand Down

0 comments on commit 42bd7bb

Please sign in to comment.