Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: Redirect HTML encodes path rather than URL encoding #14115

Closed
MartinLenord opened this issue Jan 27, 2016 · 4 comments

Comments

Projects
None yet
4 participants
@MartinLenord
Copy link

commented Jan 27, 2016

Go Version: go version go1.5.1 darwin/amd64
OS X Yosemite: 10.10.5

In the http.Redirect method, there is a fallback for browsers that don't support 301/307 redirects by providing them with a link. Currently the path is encoded using htmlEscape
https://github.com/golang/go/blame/master/src/net/http/server.go#L1716

note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[code] + "</a>.\n"
fmt.Fprintln(w, note)

This causes urlStr to not be encoded properly when output as shown below:

Example code:

package main

import "net/http"

func main() {
    http.HandleFunc("/test/", func(w http.ResponseWriter, r *http.Request) {
        http.Redirect(w, r, r.URL.Path[5:], 301)
    })
    panic(http.ListenAndServe(":8080", nil))
}

Example Output:

mlenord~$  curl -i -X GET http://localhost:8080/test/\<\\
HTTP/1.1 301 Moved Permanently
Location: /<\
Date: Wed, 27 Jan 2016 11:14:36 GMT
Content-Length: 41
Content-Type: text/html; charset=utf-8

<a href="/&lt;\">Moved Permanently</a>.

This is putting a outputting < as &lt; rather than %3C as well as adding an unescaped \ at the end of the path causing it to escape the " that comes after it.
This could be fixed with something along the lines of:

u, _ := url.Parse(urlStr)
fmt.Fprintf(w, "<a href=\"%s\">%s</a>.\n", u.String(), statusText[code])

at https://github.com/golang/go/blame/master/src/net/http/server.go#L1716

Hope this helps

Martin Lenord

@ianlancetaylor ianlancetaylor changed the title http.Redirect HTML encodes path rather than URL encoding net/http: Redirect HTML encodes path rather than URL encoding Jan 27, 2016

@ianlancetaylor ianlancetaylor added this to the Go1.7 milestone Jan 27, 2016

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jan 27, 2016

@bradfitz

This comment has been minimized.

Copy link
Member

commented Jan 27, 2016

I think the code is fine as-is.

We're not interpreting the Location string the user sends. We're just wrapping it in HTML, which is working as designed.

I think the backslash issue you're seeing is because your shell is interpreting \ as a single , which then works its way through the functions and the HTML correctly.

I guess I just don't see the problem here.

@MartinLenord

This comment has been minimized.

Copy link
Author

commented Jan 28, 2016

The issue is that html encoding is being used where url encoding is supposed to be.
For example the way the link is output for a directory list is correct
https://github.com/golang/go/blob/master/src/net/http/fs.go#L93
using url encoding for the path and html encoding for the link text

Most modern browsers can cope with an incorrectly escaped " so it doesn't cause an issue from that respect, but for consistency of expected behaviour URL encoding seems like the right thing to do

@bradfitz

This comment has been minimized.

Copy link
Member

commented Jan 28, 2016

Why are we still talking about an "incorrectly escaped ""? A backslash is not an escape character in HTML.

It's okay to write <a href="&lt;"> to link to <. Browsers will send %3C.

func main() {
    log.Fatal(http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path == "/" {
            http.Redirect(w, r, "/<", http.StatusFound)
            return
        }
        fmt.Fprintf(w, "Got a %#v\n\n%#v", r, r.URL)
    })))
}

I don't want to add more URL parsing in this code. That will only open the door to new bugs. The escaping is fine as-is. It's HTML-escaped in an HTML attribute. It doesn't need to be URL escaped. The fs.go code is URL escaping for historical reasons (I think HTML escaping would've been fine there too), but I'm not inclined to change it at this point.

Unless you can find an example that actually produces invalid HTML or invalid HTTP and is thus a security problem of some sort, I'm not inclined to change anything.

@bradfitz bradfitz closed this Jan 28, 2016

@golang golang locked and limited conversation to collaborators Feb 3, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.