mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
http: on 303, switch to GET
... unless it is a POST and the user explicitly asked to keep doing POST. Add test1983/1984: verify --follow with 303 and PUT + custom GET Fixes #20715 Reported-by: Dan Arnfield Closes #21280
This commit is contained in:
parent
bb3670f929
commit
e5087ac9fc
@ -94,8 +94,9 @@ change PUT etc - and therefore also not when libcurl issues a custom PUT. A
|
||||
(except for HEAD).
|
||||
|
||||
To control for which of the 301/302/303 status codes libcurl should *not*
|
||||
switch back to GET for when doing a custom POST, and instead keep the custom
|
||||
method, use CURLOPT_POSTREDIR(3).
|
||||
switch back to GET for when doing a custom POST (a POST transfer using a
|
||||
modified method), and instead keep the custom method, use
|
||||
CURLOPT_POSTREDIR(3).
|
||||
|
||||
If you prefer a custom POST method to be reset to exactly the method `POST`,
|
||||
use CURLFOLLOW_FIRSTONLY instead.
|
||||
|
||||
@ -32,19 +32,22 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTREDIR,
|
||||
|
||||
Pass a bitmask to control how libcurl acts on redirects after POSTs that get a
|
||||
301, 302 or 303 response back. A parameter with bit 0 set (value
|
||||
**CURL_REDIR_POST_301**) tells the library to respect RFC 7231 (section
|
||||
6.4.2 to 6.4.4) and not convert POST requests into GET requests when following
|
||||
a 301 redirection. Setting bit 1 (value **CURL_REDIR_POST_302**) makes
|
||||
libcurl maintain the request method after a 302 redirect whilst setting bit 2
|
||||
(value **CURL_REDIR_POST_303**) makes libcurl maintain the request method
|
||||
after a 303 redirect. The value **CURL_REDIR_POST_ALL** is a convenience
|
||||
define that sets all three bits.
|
||||
**CURL_REDIR_POST_301**) tells the library to not convert POST requests into
|
||||
GET requests when following a 301 redirection. Setting bit 1 (value
|
||||
**CURL_REDIR_POST_302**) makes libcurl maintain the request method after a 302
|
||||
redirect whilst setting bit 2 (value **CURL_REDIR_POST_303**) makes libcurl
|
||||
maintain the request method after a 303 redirect. The value
|
||||
**CURL_REDIR_POST_ALL** is a convenience define that sets all three bits.
|
||||
|
||||
The non-RFC behavior is ubiquitous in web browsers, so the library does the
|
||||
conversion by default to maintain consistency. A server may require a POST to
|
||||
remain a POST after such a redirection. This option is meaningful only when
|
||||
setting CURLOPT_FOLLOWLOCATION(3).
|
||||
|
||||
This option affects transfers where libcurl has been told to use HTTP POST
|
||||
using for example CURLOPT_POST(3) or CURLOPT_MIMEPOST(3) and not if the
|
||||
method has merely been modified with CURLOPT_CUSTOMREQUEST(3).
|
||||
|
||||
# DEFAULT
|
||||
|
||||
0
|
||||
|
||||
22
lib/http.c
22
lib/http.c
@ -1115,6 +1115,11 @@ static void http_switch_to_get(struct Curl_easy *data, int code)
|
||||
Curl_creader_set_rewind(data, FALSE);
|
||||
}
|
||||
|
||||
#define HTTPREQ_IS_POST(data) \
|
||||
((data)->state.httpreq == HTTPREQ_POST || \
|
||||
(data)->state.httpreq == HTTPREQ_POST_FORM || \
|
||||
(data)->state.httpreq == HTTPREQ_POST_MIME)
|
||||
|
||||
CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
|
||||
followtype type)
|
||||
{
|
||||
@ -1323,10 +1328,7 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
|
||||
* This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
|
||||
* can be overridden with CURLOPT_POSTREDIR.
|
||||
*/
|
||||
if((data->state.httpreq == HTTPREQ_POST ||
|
||||
data->state.httpreq == HTTPREQ_POST_FORM ||
|
||||
data->state.httpreq == HTTPREQ_POST_MIME) &&
|
||||
!data->set.post301) {
|
||||
if(HTTPREQ_IS_POST(data) && !data->set.post301) {
|
||||
http_switch_to_get(data, 301);
|
||||
switch_to_get = TRUE;
|
||||
}
|
||||
@ -1348,10 +1350,7 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
|
||||
* This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
|
||||
* can be overridden with CURLOPT_POSTREDIR.
|
||||
*/
|
||||
if((data->state.httpreq == HTTPREQ_POST ||
|
||||
data->state.httpreq == HTTPREQ_POST_FORM ||
|
||||
data->state.httpreq == HTTPREQ_POST_MIME) &&
|
||||
!data->set.post302) {
|
||||
if(HTTPREQ_IS_POST(data) && !data->set.post302) {
|
||||
http_switch_to_get(data, 302);
|
||||
switch_to_get = TRUE;
|
||||
}
|
||||
@ -1361,13 +1360,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
|
||||
/* 'See Other' location is not the resource but a substitute for the
|
||||
* resource. In this case we switch the method to GET/HEAD, unless the
|
||||
* method is POST and the user specified to keep it as POST.
|
||||
* https://github.com/curl/curl/issues/5237#issuecomment-614641049
|
||||
*/
|
||||
if(data->state.httpreq != HTTPREQ_GET &&
|
||||
((data->state.httpreq != HTTPREQ_POST &&
|
||||
data->state.httpreq != HTTPREQ_POST_FORM &&
|
||||
data->state.httpreq != HTTPREQ_POST_MIME) ||
|
||||
!data->set.post303)) {
|
||||
if(!HTTPREQ_IS_POST(data) || !data->set.post303) {
|
||||
http_switch_to_get(data, 303);
|
||||
switch_to_get = TRUE;
|
||||
}
|
||||
|
||||
@ -241,7 +241,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \
|
||||
test1955 test1956 test1957 test1958 test1959 test1960 test1964 test1965 \
|
||||
\
|
||||
test1970 test1971 test1972 test1973 test1974 test1975 test1976 test1977 \
|
||||
test1978 test1979 test1980 test1981 test1982 \
|
||||
test1978 test1979 test1980 test1981 test1982 test1983 test1984 \
|
||||
\
|
||||
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \
|
||||
test2008 \
|
||||
|
||||
71
tests/data/test1983
Normal file
71
tests/data/test1983
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<testcase>
|
||||
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP DELETE
|
||||
followlocation
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 303 OK swsclose
|
||||
Location: moo.html%AMPtestcase=/%TESTNUMBER0002
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
</data>
|
||||
<data2>
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</data2>
|
||||
<datacheck>
|
||||
HTTP/1.1 303 OK swsclose
|
||||
Location: moo.html%AMPtestcase=/%TESTNUMBER0002
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</datacheck>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP DELETE with --follow and 303 redirect
|
||||
</name>
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/blah/%TESTNUMBER --follow -X DELETE
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol crlf="yes">
|
||||
DELETE /blah/%TESTNUMBER HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
GET /blah/moo.html%AMPtestcase=/%TESTNUMBER0002 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
||||
76
tests/data/test1984
Normal file
76
tests/data/test1984
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<testcase>
|
||||
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP PUT
|
||||
followlocation
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 303 OK swsclose
|
||||
Location: moo.html%AMPtestcase=/%TESTNUMBER0002
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
</data>
|
||||
<data2>
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</data2>
|
||||
<datacheck>
|
||||
HTTP/1.1 303 OK swsclose
|
||||
Location: moo.html%AMPtestcase=/%TESTNUMBER0002
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</datacheck>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP PUT with 303 redirect and --follow
|
||||
</name>
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/blah/%TESTNUMBER --follow -T %LOGDIR/upload
|
||||
</command>
|
||||
<file name="%LOGDIR/upload">
|
||||
Except for responses to a HEAD request, the representation of a 303 response ought to contain a short hypertext note with a hyperlink to the same URI reference provided in the Location header field.
|
||||
</file>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol crlf="headers">
|
||||
PUT /blah/%TESTNUMBER HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
Content-Length: 199
|
||||
|
||||
Except for responses to a HEAD request, the representation of a 303 response ought to contain a short hypertext note with a hyperlink to the same URI reference provided in the Location header field.
|
||||
GET /blah/moo.html%AMPtestcase=/%TESTNUMBER0002 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
||||
Loading…
Reference in New Issue
Block a user