Skip to content

Commit

Permalink
fix(gateway): question marks in url.Path when redirecting (#313)
Browse files Browse the repository at this point in the history
Co-authored-by: Marcin Rataj <[email protected]>
  • Loading branch information
hacdias and lidel authored Jun 2, 2023
1 parent 1464d19 commit 20e2aae
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 30 deletions.
45 changes: 16 additions & 29 deletions gateway/hostname.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,24 +328,10 @@ func toDNSLinkFQDN(dnsLabel string) (fqdn string) {

// Converts a hostname/path to a subdomain-based URL, if applicable.
func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool, api IPFSBackend) (redirURL string, err error) {
var scheme, ns, rootID, rest string
var ns, rootID, rest string

query := r.URL.RawQuery
parts := strings.SplitN(path, "/", 4)
isHTTPS := isHTTPSRequest(r)
safeRedirectURL := func(in string) (out string, err error) {
safeURI, err := url.ParseRequestURI(in)
if err != nil {
return "", err
}
return safeURI.String(), nil
}

if isHTTPS {
scheme = "https:"
} else {
scheme = "http:"
}

switch len(parts) {
case 4:
Expand All @@ -362,11 +348,6 @@ func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool,
return "", nil
}

// add prefix if query is present
if query != "" {
query = "?" + query
}

// Normalize problematic PeerIDs (eg. ed25519+identity) to CID representation
if isPeerIDNamespace(ns) && !isDomainNameAndNotPeerID(rootID) {
peerID, err := peer.Decode(rootID)
Expand Down Expand Up @@ -452,15 +433,21 @@ func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool,
return "", nil
}

return safeRedirectURL(fmt.Sprintf(
"%s//%s.%s.%s/%s%s",
scheme,
rootID,
ns,
hostname,
rest,
query,
))
// Produce subdomain redirect URL in a way that preserves any
// percent-encoded paths and query parameters
u, err := url.Parse(fmt.Sprintf("http://%s.%s.%s/", rootID, ns, hostname))
if err != nil {
return "", err
}
u.RawFragment = r.URL.RawFragment
u.RawQuery = r.URL.RawQuery
if rest != "" {
u.Path = rest
}
if isHTTPS {
u.Scheme = "https"
}
return u.String(), nil
}

func hasPrefix(path string, prefixes ...string) bool {
Expand Down
4 changes: 3 additions & 1 deletion gateway/hostname_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func TestToSubdomainURL(t *testing.T) {
url string
err error
}{

// DNSLink
{httpRequest, "localhost", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost/", nil},
// Hostname with port
Expand All @@ -56,6 +55,9 @@ func TestToSubdomainURL(t *testing.T) {
// HTTP requests can also be converted to fit into a single DNS label - https://github.com/ipfs/kubo/issues/9243
{httpRequest, "localhost", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.localhost/", nil},
{httpRequest, "dweb.link", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.dweb.link/", nil},
// Correctly redirects paths when there is a ? (question mark) character - https://github.com/ipfs/kubo/issues/9882
{httpRequest, "localhost", false, "/ipns/example.com/this is a file with some spaces . dots and - but also a ?.png", "http://example.com.ipns.localhost/this%20is%20a%20file%20with%20some%20spaces%20.%20dots%20and%20-%20but%20also%20a%20%3F.png", nil},
{httpRequest, "localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n/this is a file with some spaces . dots and - but also a ?.png", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.localhost/this%20is%20a%20file%20with%20some%20spaces%20.%20dots%20and%20-%20but%20also%20a%20%3F.png", nil},
} {
testName := fmt.Sprintf("%s, %v, %s", test.gwHostname, test.inlineDNSLink, test.path)
t.Run(testName, func(t *testing.T) {
Expand Down

0 comments on commit 20e2aae

Please sign in to comment.