-
Notifications
You must be signed in to change notification settings - Fork 17.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net/http: make Server validate Host headers
Fixes #11206 (that we accept invalid bytes) Fixes #13624 (that we don't require a Host header in HTTP/1.1 per spec) Change-Id: I4138281d513998789163237e83bb893aeda43336 Reviewed-on: https://go-review.googlesource.com/17892 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
- Loading branch information
Showing
3 changed files
with
139 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -686,7 +686,7 @@ func (c *conn) readRequest() (w *response, err error) { | |
peek, _ := c.bufr.Peek(4) // ReadRequest will get err below | ||
c.bufr.Discard(numLeadingCRorLF(peek)) | ||
} | ||
req, err := ReadRequest(c.bufr) | ||
req, err := readRequest(c.bufr, false) | ||
c.mu.Unlock() | ||
if err != nil { | ||
if c.r.hitReadLimit() { | ||
|
@@ -697,6 +697,18 @@ func (c *conn) readRequest() (w *response, err error) { | |
c.lastMethod = req.Method | ||
c.r.setInfiniteReadLimit() | ||
|
||
hosts, haveHost := req.Header["Host"] | ||
if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) { | ||
return nil, badRequestError("missing required Host header") | ||
} | ||
if len(hosts) > 1 { | ||
return nil, badRequestError("too many Host headers") | ||
} | ||
if len(hosts) == 1 && !validHostHeader(hosts[0]) { | ||
return nil, badRequestError("malformed Host header") | ||
} | ||
delete(req.Header, "Host") | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
bradfitz
Author
Contributor
|
||
|
||
req.RemoteAddr = c.remoteAddr | ||
req.TLS = c.tlsState | ||
if body, ok := req.Body.(*body); ok { | ||
|
@@ -1334,6 +1346,13 @@ func (c *conn) setState(nc net.Conn, state ConnState) { | |
} | ||
} | ||
|
||
// badRequestError is a literal string (used by in the server in HTML, | ||
// unescaped) to tell the user why their request was bad. It should | ||
// be plain text without user info or other embeddded errors. | ||
type badRequestError string | ||
|
||
func (e badRequestError) Error() string { return "Bad Request: " + string(e) } | ||
|
||
// Serve a new connection. | ||
func (c *conn) serve() { | ||
c.remoteAddr = c.rwc.RemoteAddr().String() | ||
|
@@ -1399,7 +1418,11 @@ func (c *conn) serve() { | |
if neterr, ok := err.(net.Error); ok && neterr.Timeout() { | ||
return // don't reply | ||
} | ||
io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request") | ||
var publicErr string | ||
if v, ok := err.(badRequestError); ok { | ||
publicErr = ": " + string(v) | ||
} | ||
io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr) | ||
return | ||
} | ||
|
||
|
@bradfitz Why delete
Host
Header at http server side? I am working on code to logHost
Header but found out that it was deleted when read request