Commit c3b9650c authored by Andrew Balholm's avatar Andrew Balholm Committed by David Symonds

net/http: parse CONNECT requests

Fixes #2755

R=dsymonds, rsc
CC=golang-dev
https://golang.org/cl/5571052
parent 03ea8b1c
......@@ -171,6 +171,75 @@ var reqTests = []reqTest{
},
noError,
},
// CONNECT request with domain name:
{
"CONNECT www.google.com:443 HTTP/1.1\r\n\r\n",
&Request{
Method: "CONNECT",
URL: &url.URL{
Host: "www.google.com:443",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: Header{},
Close: false,
ContentLength: 0,
Host: "www.google.com:443",
},
noBody,
noTrailer,
noError,
},
// CONNECT request with IP address:
{
"CONNECT 127.0.0.1:6060 HTTP/1.1\r\n\r\n",
&Request{
Method: "CONNECT",
URL: &url.URL{
Host: "127.0.0.1:6060",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: Header{},
Close: false,
ContentLength: 0,
Host: "127.0.0.1:6060",
},
noBody,
noTrailer,
noError,
},
// CONNECT request for RPC:
{
"CONNECT /_goRPC_ HTTP/1.1\r\n\r\n",
&Request{
Method: "CONNECT",
URL: &url.URL{
Path: "/_goRPC_",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: Header{},
Close: false,
ContentLength: 0,
Host: "",
},
noBody,
noTrailer,
noError,
},
}
func TestReadRequest(t *testing.T) {
......
......@@ -305,6 +305,9 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
ruri := req.URL.RequestURI()
if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" {
ruri = req.URL.Scheme + "://" + host + ruri
} else if req.Method == "CONNECT" && req.URL.Path == "" {
// CONNECT requests normally give just the host and port, not a full URL.
ruri = host
}
// TODO(bradfitz): escape at least newlines in ruri?
......@@ -463,10 +466,29 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
return nil, &badStringError{"malformed HTTP version", req.Proto}
}
// CONNECT requests are used two different ways, and neither uses a full URL:
// The standard use is to tunnel HTTPS through an HTTP proxy.
// It looks like "CONNECT www.google.com:443 HTTP/1.1", and the parameter is
// just the authority section of a URL. This information should go in req.URL.Host.
//
// The net/rpc package also uses CONNECT, but there the parameter is a path
// that starts with a slash. It can be parsed with the regular URL parser,
// and the path will end up in req.URL.Path, where it needs to be in order for
// RPC to work.
justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/")
if justAuthority {
rawurl = "http://" + rawurl
}
if req.URL, err = url.ParseRequest(rawurl); err != nil {
return nil, err
}
if justAuthority {
// Strip the bogus "http://" back off.
req.URL.Scheme = ""
}
// Subsequent lines: Key: value.
mimeHeader, err := tp.ReadMIMEHeader()
if err != nil {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment