提交 80606a58 编写于 作者: M Mislav Marohnić

Follow 307 redirects in simpleApi, even for POST

HTTP client used to automatically follow GET redirects, or turn certain
POST redirects to GET when applicable, but for opening a new pull
request for a renamed repo, we need to repeat the POST against the
updated location.
上级 56fce4bc
......@@ -659,3 +659,37 @@ Feature: hub pull-request
"""
When I successfully run `hub pull-request -m hereyougo`
Then the output should contain exactly "the://url\n"
Scenario: Pull request with redirect
Given the "origin" remote has url "https://github.com/mislav/coral.git"
And I am on the "feature" branch pushed to "origin/feature"
Given the GitHub API server:
"""
post('/repos/mislav/coral/pulls') {
redirect 'https://api.github.com/repositories/12345', 307
}
post('/repositories/12345', :host_name => 'api.github.com') {
assert :base => 'master',
:head => 'mislav:feature',
:title => 'hereyougo'
json :html_url => "the://url"
}
"""
When I successfully run `hub pull-request -m hereyougo`
Then the output should contain exactly "the://url\n"
Scenario: Redirect to another host is not followed
Given the "origin" remote has url "https://github.com/mislav/coral.git"
And I am on the "feature" branch pushed to "origin/feature"
Given the GitHub API server:
"""
post('/repos/mislav/coral/pulls') {
redirect 'https://disney.com/mouse', 307
}
"""
When I run `hub pull-request -m hereyougo`
Then the stderr should contain exactly:
"""
Error creating pull request: Temporary Redirect (HTTP 307)
Refused to follow redirect to https://disney.com/mouse\n
"""
......@@ -714,6 +714,11 @@ func FormatError(action string, err error) (ee error) {
}
}
redirectLocation := e.Response.Header.Get("Location")
if statusCode >= 300 && statusCode < 400 && redirectLocation != "" {
errorSentences = append(errorSentences, fmt.Sprintf("Refused to follow redirect to %s", redirectLocation))
}
var errorMessage string
if len(errorSentences) > 0 {
errorMessage = strings.Join(errorSentences, "\n")
......
......@@ -206,13 +206,17 @@ type simpleClient struct {
accessToken string
}
func (c *simpleClient) performRequest(method, path string, body io.Reader, configure func(*http.Request)) (res *simpleResponse, err error) {
func (c *simpleClient) performRequest(method, path string, body io.Reader, configure func(*http.Request)) (*simpleResponse, error) {
url, err := url.Parse(path)
if err != nil {
return
if err == nil {
url = c.rootUrl.ResolveReference(url)
return c.performRequestUrl(method, url, body, configure, 2)
} else {
return nil, err
}
}
url = c.rootUrl.ResolveReference(url)
func (c *simpleClient) performRequestUrl(method string, url *url.URL, body io.Reader, configure func(*http.Request), redirectsRemaining int) (res *simpleResponse, err error) {
req, err := http.NewRequest(method, url.String(), body)
if err != nil {
return
......@@ -223,9 +227,24 @@ func (c *simpleClient) performRequest(method, path string, body io.Reader, confi
configure(req)
}
var bodyBackup io.ReadWriter
if req.Body != nil {
bodyBackup = &bytes.Buffer{}
req.Body = ioutil.NopCloser(io.TeeReader(req.Body, bodyBackup))
}
httpResponse, err := c.httpClient.Do(req)
if err == nil {
res = &simpleResponse{httpResponse}
if err != nil {
return
}
res = &simpleResponse{httpResponse}
if res.StatusCode == 307 && redirectsRemaining > 0 {
url, err = url.Parse(res.Header.Get("Location"))
if err != nil || url.Host != req.URL.Host || url.Scheme != req.URL.Scheme {
return
}
res, err = c.performRequestUrl(method, url, bodyBackup, configure, redirectsRemaining-1)
}
return
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册