Philip Langdale provided the new CURLOPT_POST301 option for
curl_easy_setopt() that alters how libcurl functions when following redirects. It makes libcurl obey the RFC2616 when a 301 response is received after a non-GET request is made. Default libcurl behaviour is to change method to GET in the subsequent request (like it does for response code 302 - because that's what many/most browsers do), but with this CURLOPT_POST301 option enabled it will do what the spec says and do the next request using the same method again. I.e keep POST after 301. The curl tool got this option as --post301 Test case 1011 and 1012 were added to verify.
This commit is contained in:
Родитель
a6315359d7
Коммит
fd4cf78f36
13
CHANGES
13
CHANGES
|
@ -7,6 +7,19 @@
|
|||
Changelog
|
||||
|
||||
Daniel S (26 September 2007)
|
||||
- Philip Langdale provided the new CURLOPT_POST301 option for
|
||||
curl_easy_setopt() that alters how libcurl functions when following
|
||||
redirects. It makes libcurl obey the RFC2616 when a 301 response is received
|
||||
after a non-GET request is made. Default libcurl behaviour is to change
|
||||
method to GET in the subsequent request (like it does for response code 302
|
||||
- because that's what many/most browsers do), but with this CURLOPT_POST301
|
||||
option enabled it will do what the spec says and do the next request using
|
||||
the same method again. I.e keep POST after 301.
|
||||
|
||||
The curl tool got this option as --post301
|
||||
|
||||
Test case 1011 and 1012 were added to verify.
|
||||
|
||||
- Max Katsev reported that when doing a libcurl FTP request with
|
||||
CURLOPT_NOBODY enabled but not CURLOPT_HEADER, libcurl wouldn't do TYPE
|
||||
before it does SIZE which makes it less useful. I walked over the code and
|
||||
|
|
|
@ -2,7 +2,7 @@ Curl and libcurl 7.17.1
|
|||
|
||||
Public curl release number: 102
|
||||
Releases counted from the very beginning: 128
|
||||
Available command line options: 119
|
||||
Available command line options: 120
|
||||
Available curl_easy_setopt() options: 143
|
||||
Number of public functions in libcurl: 55
|
||||
Amount of public web site mirrors: 42
|
||||
|
@ -14,6 +14,7 @@ This release includes the following changes:
|
|||
o automatically append ";type=<a|i>" when using HTTP proxies for FTP urls
|
||||
o improved NSS support
|
||||
o added --proxy-negotiate
|
||||
o added --post301 and CURLOPT_POST301
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
|
@ -42,6 +43,6 @@ This release would not have looked like this without help, code, reports and
|
|||
advice from friends like these:
|
||||
|
||||
Dan Fandrich, Michal Marek, Günter Knauf, Rob Crittenden, Immanuel Gregoire,
|
||||
Mark Davies, Max Katsev
|
||||
Mark Davies, Max Katsev, Philip Langdale
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
|
|
@ -1124,6 +1124,9 @@ typedef enum {
|
|||
CINIT(NEW_FILE_PERMS, LONG, 159),
|
||||
CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
|
||||
|
||||
/* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */
|
||||
CINIT(POST301, LONG, 161),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
|
|
|
@ -2257,10 +2257,13 @@ CURLcode Curl_follow(struct SessionHandle *data,
|
|||
* violation, many webservers expect this misbehavior. So these servers
|
||||
* often answers to a POST request with an error page. To be sure that
|
||||
* libcurl gets the page that most user agents would get, libcurl has to
|
||||
* force GET:
|
||||
* force GET.
|
||||
*
|
||||
* This behaviour can be overriden with CURLOPT_POST301.
|
||||
*/
|
||||
if( data->set.httpreq == HTTPREQ_POST
|
||||
|| data->set.httpreq == HTTPREQ_POST_FORM) {
|
||||
if( (data->set.httpreq == HTTPREQ_POST
|
||||
|| data->set.httpreq == HTTPREQ_POST_FORM)
|
||||
&& !data->set.post301) {
|
||||
infof(data,
|
||||
"Violate RFC 2616/10.3.2 and switch from POST to GET\n");
|
||||
data->set.httpreq = HTTPREQ_GET;
|
||||
|
|
|
@ -924,6 +924,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
|||
data->set.maxredirs = va_arg(param, long);
|
||||
break;
|
||||
|
||||
case CURLOPT_POST301:
|
||||
/*
|
||||
* Obey RFC 2616/10.3.2 and resubmit a POST as a POST after a 301.
|
||||
*/
|
||||
data->set.post301 = (bool)(0 != va_arg(param, long));
|
||||
break;
|
||||
|
||||
case CURLOPT_POST:
|
||||
/* Does this option serve a purpose anymore? Yes it does, when
|
||||
CURLOPT_POSTFIELDS isn't used and the POST data is read off the
|
||||
|
|
|
@ -1306,6 +1306,7 @@ struct UserDefined {
|
|||
long followlocation; /* as in HTTP Location: */
|
||||
long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1
|
||||
for infinity */
|
||||
bool post301; /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */
|
||||
bool free_referer; /* set TRUE if 'referer' points to a string we
|
||||
allocated */
|
||||
curl_off_t postfieldsize; /* if POST, this might have a size to use instead
|
||||
|
|
|
@ -723,6 +723,8 @@
|
|||
d c 00159
|
||||
d CURLOPT_NEW_DIRECTORY_PERMS...
|
||||
d c 00160
|
||||
d CURLOPT_POST301...
|
||||
d c 00161
|
||||
*
|
||||
d CURLFORMcode s 10i 0 based(######ptr######) Enum
|
||||
d CURL_FORMADD_OK...
|
||||
|
|
35
src/main.c
35
src/main.c
|
@ -478,6 +478,7 @@ struct Configurable {
|
|||
|
||||
char *libcurl; /* output libcurl code to this file name */
|
||||
bool raw;
|
||||
bool post301;
|
||||
struct OutStruct *outs;
|
||||
};
|
||||
|
||||
|
@ -687,6 +688,7 @@ static void help(void)
|
|||
" --no-sessionid Disable SSL session-ID reusing (SSL)",
|
||||
" -o/--output <file> Write output to <file> instead of stdout",
|
||||
" -O/--remote-name Write output to a file named as the remote file",
|
||||
" --post301 Do not switch to GET after following a 301 redirect (H)",
|
||||
" -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
|
||||
" --proxy-anyauth Pick \"any\" proxy authentication method (H)",
|
||||
" --proxy-basic Use Basic authentication on the proxy (H)",
|
||||
|
@ -1511,6 +1513,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
|||
{"$j", "ftp-ssl-ccc-mode", TRUE},
|
||||
{"$z", "libcurl", TRUE},
|
||||
{"$#", "raw", FALSE},
|
||||
{"$0", "post301", FALSE},
|
||||
|
||||
{"0", "http1.0", FALSE},
|
||||
{"1", "tlsv1", FALSE},
|
||||
|
@ -1962,6 +1965,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
|||
case '#': /* --raw */
|
||||
config->raw ^= TRUE;
|
||||
break;
|
||||
case '0': /* --post301 */
|
||||
config->post301 ^= TRUE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '#': /* --progress-bar */
|
||||
|
@ -2046,7 +2052,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
|||
|
||||
if(curlx_strequal("-", nextarg)) {
|
||||
file = stdin;
|
||||
if(subletter == 'b') /* forced binary */
|
||||
if(subletter == 'b') /* forced data-binary */
|
||||
SET_BINMODE(stdin);
|
||||
}
|
||||
else {
|
||||
|
@ -3801,7 +3807,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||
clean_getout(config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infiles = urlnode->infile;
|
||||
|
||||
|
@ -4022,17 +4028,17 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||
/* Free the list of remaining URLs and globbed upload files
|
||||
* to force curl to exit immediately
|
||||
*/
|
||||
if(urls) {
|
||||
glob_cleanup(urls);
|
||||
urls = NULL;
|
||||
}
|
||||
if(inglob) {
|
||||
glob_cleanup(inglob);
|
||||
inglob = NULL;
|
||||
}
|
||||
if(urls) {
|
||||
glob_cleanup(urls);
|
||||
urls = NULL;
|
||||
}
|
||||
if(inglob) {
|
||||
glob_cleanup(inglob);
|
||||
inglob = NULL;
|
||||
}
|
||||
|
||||
res = CURLE_READ_ERROR;
|
||||
goto quit_urls;
|
||||
res = CURLE_READ_ERROR;
|
||||
goto quit_urls;
|
||||
}
|
||||
infdfopen=TRUE;
|
||||
uploadfilesize=fileinfo.st_size;
|
||||
|
@ -4196,7 +4202,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||
my_setopt(curl, CURLOPT_SSLKEYTYPE, config->key_type);
|
||||
my_setopt(curl, CURLOPT_KEYPASSWD, config->key_passwd);
|
||||
|
||||
/* SSH private key uses the same command-line option as SSL private key */
|
||||
/* SSH private key uses the same command-line option as SSL private key */
|
||||
my_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
|
||||
my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
|
||||
|
||||
|
@ -4386,6 +4392,9 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||
my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
|
||||
}
|
||||
|
||||
/* curl 7.17.1 */
|
||||
my_setopt(curl, CURLOPT_POST301, config->post301);
|
||||
|
||||
retry_numretries = config->req_retry;
|
||||
|
||||
retrystart = cutil_tvnow();
|
||||
|
|
|
@ -44,4 +44,4 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
|
|||
test409 test613 test614 test700 test701 test702 test704 test705 test703 \
|
||||
test706 test707 test350 test351 test352 test353 test289 test540 test354 \
|
||||
test231 test1000 test1001 test1002 test1003 test1004 test1005 test1006 \
|
||||
test615 test1007 test541 test1010
|
||||
test615 test1007 test541 test1010 test1011 test1012
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP POST
|
||||
followlocation
|
||||
</keywords>
|
||||
</info>
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 301 OK swsclose
|
||||
Location: moo.html&testcase=/10110002
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
</data>
|
||||
<data2>
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</data2>
|
||||
<datacheck>
|
||||
HTTP/1.1 301 OK swsclose
|
||||
Location: moo.html&testcase=/10110002
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</datacheck>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP POST with 301 redirect
|
||||
</name>
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/blah/1011 -L -d "moo"
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
</strip>
|
||||
<protocol>
|
||||
POST /blah/1011 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
Content-Length: 3
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
mooGET /blah/moo.html&testcase=/10110002 HTTP/1.1
|
||||
User-Agent: curl/7.10 (i686-pc-linux-gnu) libcurl/7.10 OpenSSL/0.9.6c ipv6 zlib/1.1.3
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
|
@ -0,0 +1,79 @@
|
|||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP POST
|
||||
followlocation
|
||||
</keywords>
|
||||
</info>
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 301 OK swsclose
|
||||
Location: moo.html&testcase=/10120002
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
</data>
|
||||
<data2>
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</data2>
|
||||
<datacheck>
|
||||
HTTP/1.1 301 OK swsclose
|
||||
Location: moo.html&testcase=/10120002
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Location: this should be ignored
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Connection: close
|
||||
|
||||
body
|
||||
</datacheck>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP POST with 301 redirect and --post301
|
||||
</name>
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/blah/1012 -L -d "moo" --post301
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
</strip>
|
||||
<protocol nonewline="yes">
|
||||
POST /blah/1012 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
Content-Length: 3
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
mooPOST /blah/moo.html&testcase=/10120002 HTTP/1.1
|
||||
User-Agent: curl/7.10 (i686-pc-linux-gnu) libcurl/7.10 OpenSSL/0.9.6c ipv6 zlib/1.1.3
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
Content-Length: 3
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
moo
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
Загрузка…
Ссылка в новой задаче