Skip to content

Commit a887119

Browse files
committed
net/http: preserve original HTTP method when possible
In Go1.7, a 301, 302, or 303 redirect on a HEAD method, would still cause the following redirects to still use a HEAD. In CL/29852 this behavior was changed such that those codes always caused a redirect with the GET method. Fix this such that both GET and HEAD will preserve the method. Fixes #18570 Change-Id: I4bfe69872a30799419e3fad9178f907fe439b449 Reviewed-on: https://go-review.googlesource.com/34981 Run-TryBot: Joe Tsai <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent ffedff7 commit a887119

File tree

2 files changed

+17
-11
lines changed

2 files changed

+17
-11
lines changed

src/net/http/client.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -413,19 +413,26 @@ func (c *Client) checkRedirect(req *Request, via []*Request) error {
413413

414414
// redirectBehavior describes what should happen when the
415415
// client encounters a 3xx status code from the server
416-
func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirectMethod string, shouldRedirect bool) {
416+
func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect bool) {
417417
switch resp.StatusCode {
418418
case 301, 302, 303:
419-
redirectMethod = "GET"
419+
redirectMethod = reqMethod
420420
shouldRedirect = true
421+
422+
// RFC 2616 allowed automatic redirection only with GET and
423+
// HEAD requests. RFC 7231 lifts this restriction, but we still
424+
// restrict other methods to GET to maintain compatibility.
425+
// See Issue 18570.
426+
if reqMethod != "GET" && reqMethod != "HEAD" {
427+
redirectMethod = "GET"
428+
}
421429
case 307, 308:
422430
redirectMethod = reqMethod
423431
shouldRedirect = true
424432

425433
// Treat 307 and 308 specially, since they're new in
426434
// Go 1.8, and they also require re-sending the request body.
427-
loc := resp.Header.Get("Location")
428-
if loc == "" {
435+
if resp.Header.Get("Location") == "" {
429436
// 308s have been observed in the wild being served
430437
// without Location headers. Since Go 1.7 and earlier
431438
// didn't follow these codes, just stop here instead
@@ -434,7 +441,6 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
434441
shouldRedirect = false
435442
break
436443
}
437-
ireq := via[0]
438444
if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
439445
// We had a request body, and 307/308 require
440446
// re-sending it, but GetBody is not defined. So just
@@ -443,7 +449,6 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
443449
shouldRedirect = false
444450
}
445451
}
446-
447452
return redirectMethod, shouldRedirect
448453
}
449454

@@ -474,7 +479,8 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
474479
// If the server replies with a redirect, the Client first uses the
475480
// CheckRedirect function to determine whether the redirect should be
476481
// followed. If permitted, a 301, 302, or 303 redirect causes
477-
// subsequent requests to use HTTP method "GET", with no body.
482+
// subsequent requests to use HTTP method GET
483+
// (or HEAD if the original request was HEAD), with no body.
478484
// A 307 or 308 redirect preserves the original HTTP method and body,
479485
// provided that the Request.GetBody function is defined.
480486
// The NewRequest function automatically sets GetBody for common
@@ -592,7 +598,7 @@ func (c *Client) Do(req *Request) (*Response, error) {
592598
}
593599

594600
var shouldRedirect bool
595-
redirectMethod, shouldRedirect = redirectBehavior(req.Method, resp, reqs)
601+
redirectMethod, shouldRedirect = redirectBehavior(req.Method, resp, reqs[0])
596602
if !shouldRedirect {
597603
return resp, nil
598604
}

src/net/http/client_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,9 +1665,9 @@ func TestClientRedirectTypes(t *testing.T) {
16651665
3: {method: "POST", serverStatus: 307, wantMethod: "POST"},
16661666
4: {method: "POST", serverStatus: 308, wantMethod: "POST"},
16671667

1668-
5: {method: "HEAD", serverStatus: 301, wantMethod: "GET"},
1669-
6: {method: "HEAD", serverStatus: 302, wantMethod: "GET"},
1670-
7: {method: "HEAD", serverStatus: 303, wantMethod: "GET"},
1668+
5: {method: "HEAD", serverStatus: 301, wantMethod: "HEAD"},
1669+
6: {method: "HEAD", serverStatus: 302, wantMethod: "HEAD"},
1670+
7: {method: "HEAD", serverStatus: 303, wantMethod: "HEAD"},
16711671
8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"},
16721672
9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"},
16731673

0 commit comments

Comments
 (0)