http: on 303, switch to GET
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -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 \ | |
| @@ -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> |
| @@ -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> |