From ad6d128614269a4d621e74b3d8cd31d9f549583e Mon Sep 17 00:00:00 2001 From: Erik Dubbelboer Date: Sun, 3 Oct 2021 10:30:20 +0200 Subject: [PATCH] URI.Parse should never change it's input Decode the URI in place, but use the bytes of the URI instead of the bytes of the input parameter. --- uri.go | 11 ++++++++--- uri_test.go | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/uri.go b/uri.go index 061e11edf8..2285f45d0d 100644 --- a/uri.go +++ b/uri.go @@ -305,11 +305,12 @@ func (u *URI) parse(host, uri []byte, isTLS bool) error { } } - host, err := parseHost(host) - if err != nil { + u.host = append(u.host, host...) + if parsedHost, err := parseHost(u.host); err != nil { return err + } else { + u.host = parsedHost } - u.host = append(u.host, host...) lowercaseBytes(u.host) b := uri @@ -353,6 +354,8 @@ func (u *URI) parse(host, uri []byte, isTLS bool) error { // information. That is, as host[:port]. // // Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L619 +// +// The host is parsed and unescaped in place overwriting the contents of the host parameter. func parseHost(host []byte) ([]byte, error) { if len(host) > 0 && host[0] == '[' { // Parse an IP-Literal in RFC 3986 and RFC 6874. @@ -425,6 +428,8 @@ func (e InvalidHostError) Error() string { // which section of the URL string is being unescaped. // // Based on https://github.com/golang/go/blob/8ac5cbe05d61df0a7a7c9a38ff33305d4dcfea32/src/net/url/url.go#L199 +// +// Unescapes in place overwriting the contents of s and returning it. func unescape(s []byte, mode encoding) ([]byte, error) { // Count %, check that they're well-formed. n := 0 diff --git a/uri_test.go b/uri_test.go index 481b51a98d..fc0b2ef0cd 100644 --- a/uri_test.go +++ b/uri_test.go @@ -427,3 +427,23 @@ func TestInvalidUrl(t *testing.T) { t.Fail() } } + +func TestNoOverwriteInput(t *testing.T) { + str := `//%AA` + url := []byte(str) + + u := AcquireURI() + defer ReleaseURI(u) + + if err := u.Parse(nil, url); err != nil { + t.Error(err) + } + + if string(url) != str { + t.Error() + } + + if u.String() != "http://\xaa/" { + t.Errorf("%q", u.String()) + } +}