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/httputil: NewSingleHostReverseProxy doesn't overwrite req.Host #7618

Closed
gopherbot opened this issue Mar 24, 2014 · 3 comments
Closed

Comments

@gopherbot
Copy link

by vitaly.dvd:

What does 'go version' print?
go version go1.2 linux/amd64

What steps reproduce the problem?

1. Write simple program on a proxyHost that should forward requests to a targetHost
censored.go:  (  http://play.golang.org/p/YXT3zso8Ff  )

package main
import (
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)
func main() {
    targetUrl, _ := url.Parse("http://navalny.livejournal.com";)
    log.Fatal(http.ListenAndServe(":49200", httputil.NewSingleHostReverseProxy(targetUrl)))
}


2. On a proxyHost (AWS instance in my case)
    run go program:
        go run censored.go 
    run tcpDump:
        sudo tcpdump -vvvs 1024 -l -A host navalny.livejournal.com

What happened?

The HOST header points to my proxy host instead of a target one

curl -v http://54.228.241.100:49200 > /dev/null
GET / HTTP/1.1
Host: 54.228.241.100:49200
User-Agent: curl/7.30.0
Accept: */*
X-Forwarded-For: 109.188.90.98
Accept-Encoding: gzip

As a result life journal returns HTTP redirect with Location:
http://navalny.livejournal.com   (the same target host)


What should have happened instead?
The host header should be set to targetHost,  navalny.livejournal.com in this case.

curl -v http://54.228.241.100:49200 > /dev/null
GET / HTTP/1.1
Host: navalny.livejournal.com
User-Agent: curl/7.30.0
Accept: */*


Please provide any additional information below.

fix is simple:  the req.Host should explicitly  rewrite req.Host in
NewSingleHostReverseProxy

// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
    targetQuery := target.RawQuery
    director := func(req *http.Request) {
        req.URL.Scheme = target.Scheme
        req.URL.Host = target.Host
+       req.Host = target.Host
        req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
        if targetQuery == "" || req.URL.RawQuery == "" {
            req.URL.RawQuery = targetQuery + req.URL.RawQuery
        } else {
            req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
        }
    }
    return &ReverseProxy{Director: director}
}
@gopherbot
Copy link
Author

Comment 1 by vitaly.dvd:

54.228.241.100 in the example above is a host where Go program is launched (aka
proxyHost)

@ianlancetaylor
Copy link
Contributor

Comment 2:

Labels changed: added repo-main, release-none.

@bradfitz
Copy link
Contributor

Comment 3:

This is working as intended.
Usually the Host is "correct" because the DNS is set to the reverse proxy, and then the
reverse proxy chooses the backends, passing along the correct hostname.
We can't change this behavior now even if we wanted to.
But NewSingleHostReverseProxy is just a tiny example function, showing how to use
ReverseProxy.  You can write your own Director function if you want different behavior.

Status changed to WorkingAsIntended.

This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants