Commit a734a855 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: require valid methods in NewRequest and Transport.RoundTrip

Fixes #12078

Change-Id: If09c927fae639ec4ed3894a2b393a87c1e677803
Reviewed-on: https://go-review.googlesource.com/16829
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarAndrew Gerrand <adg@golang.org>
parent 0b314e1a
...@@ -547,6 +547,23 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) { ...@@ -547,6 +547,23 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
return major, minor, true return major, minor, true
} }
func validMethod(method string) bool {
/*
Method = "OPTIONS" ; Section 9.2
| "GET" ; Section 9.3
| "HEAD" ; Section 9.4
| "POST" ; Section 9.5
| "PUT" ; Section 9.6
| "DELETE" ; Section 9.7
| "TRACE" ; Section 9.8
| "CONNECT" ; Section 9.9
| extension-method
extension-method = token
token = 1*<any CHAR except CTLs or separators>
*/
return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1
}
// NewRequest returns a new Request given a method, URL, and optional body. // NewRequest returns a new Request given a method, URL, and optional body.
// //
// If the provided body is also an io.Closer, the returned // If the provided body is also an io.Closer, the returned
...@@ -560,6 +577,9 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) { ...@@ -560,6 +577,9 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
// type's documentation for the difference between inbound and outbound // type's documentation for the difference between inbound and outbound
// request fields. // request fields.
func NewRequest(method, urlStr string, body io.Reader) (*Request, error) { func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
if !validMethod(method) {
return nil, fmt.Errorf("net/http: invalid method %q", method)
}
u, err := url.Parse(urlStr) u, err := url.Parse(urlStr)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -355,6 +355,22 @@ func TestNewRequestHost(t *testing.T) { ...@@ -355,6 +355,22 @@ func TestNewRequestHost(t *testing.T) {
} }
} }
func TestRequestInvalidMethod(t *testing.T) {
_, err := NewRequest("bad method", "http://foo.com/", nil)
if err == nil {
t.Error("expected error from NewRequest with invalid method")
}
req, err := NewRequest("GET", "http://foo.example/", nil)
if err != nil {
t.Fatal(err)
}
req.Method = "bad method"
_, err = DefaultClient.Do(req)
if err == nil || !strings.Contains(err.Error(), "invalid method") {
t.Errorf("Transport error = %v; want invalid method", err)
}
}
func TestNewRequestContentLength(t *testing.T) { func TestNewRequestContentLength(t *testing.T) {
readByte := func(r io.Reader) io.Reader { readByte := func(r io.Reader) io.Reader {
var b [1]byte var b [1]byte
......
...@@ -237,6 +237,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { ...@@ -237,6 +237,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
req.closeBody() req.closeBody()
return nil, &badStringError{"unsupported protocol scheme", s} return nil, &badStringError{"unsupported protocol scheme", s}
} }
if !validMethod(req.Method) {
return nil, fmt.Errorf("net/http: invalid method %q", req.Method)
}
if req.URL.Host == "" { if req.URL.Host == "" {
req.closeBody() req.closeBody()
return nil, errors.New("http: no Host in request URL") return nil, errors.New("http: no Host in request URL")
......
...@@ -1775,6 +1775,7 @@ func TestTransportNoHost(t *testing.T) { ...@@ -1775,6 +1775,7 @@ func TestTransportNoHost(t *testing.T) {
defer afterTest(t) defer afterTest(t)
tr := &Transport{} tr := &Transport{}
_, err := tr.RoundTrip(&Request{ _, err := tr.RoundTrip(&Request{
Method: "GET",
Header: make(Header), Header: make(Header),
URL: &url.URL{ URL: &url.URL{
Scheme: "http", Scheme: "http",
......
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