Skip to content

net/http/httputil: NewSingleHostReverseProxy doesn't overwrite req.Host #7618

Closed
@gopherbot

Description

@gopherbot

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}
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions