mirror of
https://github.com/golang/go
synced 2024-11-19 21:14:43 -07:00
http: make HEAD client request follow redirects
HEAD requests should in my opinion have the ability to follow redirects like the implementation of GET requests does. My use case is polling several thousand severs to check if they respond with 200 status codes. Using GET requests is neither efficient in running time of the task nor for bandwidth consumption. This suggested patch changes the return signature of http.Head() to match that of http.Get(), providing the final URL in a redirect chain. `curl -IL http://google.com` follows redirects with HEAD requests just fine. Fixes #1806. R=golang-dev, bradfitz, rsc CC=golang-dev https://golang.org/cl/4517058
This commit is contained in:
parent
404d49154b
commit
092f34feca
@ -144,6 +144,10 @@ func Get(url string) (r *Response, err os.Error) {
|
|||||||
//
|
//
|
||||||
// Caller should close r.Body when done reading from it.
|
// Caller should close r.Body when done reading from it.
|
||||||
func (c *Client) Get(url string) (r *Response, err os.Error) {
|
func (c *Client) Get(url string) (r *Response, err os.Error) {
|
||||||
|
return c.sendFollowingRedirects("GET", url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) sendFollowingRedirects(method, url string) (r *Response, err os.Error) {
|
||||||
// TODO: if/when we add cookie support, the redirected request shouldn't
|
// TODO: if/when we add cookie support, the redirected request shouldn't
|
||||||
// necessarily supply the same cookies as the original.
|
// necessarily supply the same cookies as the original.
|
||||||
var base *URL
|
var base *URL
|
||||||
@ -155,7 +159,7 @@ func (c *Client) Get(url string) (r *Response, err os.Error) {
|
|||||||
|
|
||||||
for redirect := 0; ; redirect++ {
|
for redirect := 0; ; redirect++ {
|
||||||
var req Request
|
var req Request
|
||||||
req.Method = "GET"
|
req.Method = method
|
||||||
req.Header = make(Header)
|
req.Header = make(Header)
|
||||||
if base == nil {
|
if base == nil {
|
||||||
req.URL, err = ParseURL(url)
|
req.URL, err = ParseURL(url)
|
||||||
@ -195,7 +199,7 @@ func (c *Client) Get(url string) (r *Response, err os.Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = &URLError{"Get", url, err}
|
err = &URLError{method[0:1] + strings.ToLower(method[1:]), url, err}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,19 +287,28 @@ func urlencode(data map[string]string) (b *bytes.Buffer) {
|
|||||||
return bytes.NewBuffer([]byte(EncodeQuery(m)))
|
return bytes.NewBuffer([]byte(EncodeQuery(m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head issues a HEAD to the specified URL.
|
// Head issues a HEAD to the specified URL. If the response is one of the
|
||||||
|
// following redirect codes, Head follows the redirect after calling the
|
||||||
|
// Client's CheckRedirect function.
|
||||||
|
//
|
||||||
|
// 301 (Moved Permanently)
|
||||||
|
// 302 (Found)
|
||||||
|
// 303 (See Other)
|
||||||
|
// 307 (Temporary Redirect)
|
||||||
//
|
//
|
||||||
// Head is a wrapper around DefaultClient.Head
|
// Head is a wrapper around DefaultClient.Head
|
||||||
func Head(url string) (r *Response, err os.Error) {
|
func Head(url string) (r *Response, err os.Error) {
|
||||||
return DefaultClient.Head(url)
|
return DefaultClient.Head(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head issues a HEAD to the specified URL.
|
// Head issues a HEAD to the specified URL. If the response is one of the
|
||||||
|
// following redirect codes, Head follows the redirect after calling the
|
||||||
|
// Client's CheckRedirect function.
|
||||||
|
//
|
||||||
|
// 301 (Moved Permanently)
|
||||||
|
// 302 (Found)
|
||||||
|
// 303 (See Other)
|
||||||
|
// 307 (Temporary Redirect)
|
||||||
func (c *Client) Head(url string) (r *Response, err os.Error) {
|
func (c *Client) Head(url string) (r *Response, err os.Error) {
|
||||||
var req Request
|
return c.sendFollowingRedirects("HEAD", url)
|
||||||
req.Method = "HEAD"
|
|
||||||
if req.URL, err = ParseURL(url); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return send(&req, c.Transport)
|
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,12 @@ func TestRedirects(t *testing.T) {
|
|||||||
t.Errorf("with default client, expected error %q, got %q", e, g)
|
t.Errorf("with default client, expected error %q, got %q", e, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HEAD request should also have the ability to follow redirects.
|
||||||
|
_, err = c.Head(ts.URL)
|
||||||
|
if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
|
||||||
|
t.Errorf("with default client, expected error %q, got %q", e, g)
|
||||||
|
}
|
||||||
|
|
||||||
var checkErr os.Error
|
var checkErr os.Error
|
||||||
var lastVia []*Request
|
var lastVia []*Request
|
||||||
c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
|
c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
|
||||||
|
Loading…
Reference in New Issue
Block a user