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
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
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:
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)
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;
* 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;
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
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
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...
char *libcurl; /* output libcurl code to this file name */
bool raw;
+ bool post301;
struct OutStruct *outs;
};
" --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)",
{"$j", "ftp-ssl-ccc-mode", TRUE},
{"$z", "libcurl", TRUE},
{"$#", "raw", FALSE},
+ {"$0", "post301", FALSE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
case '#': /* --raw */
config->raw ^= TRUE;
break;
+ case '0': /* --post301 */
+ config->post301 ^= TRUE;
+ break;
}
break;
case '#': /* --progress-bar */
if(curlx_strequal("-", nextarg)) {
file = stdin;
- if(subletter == 'b') /* forced binary */
+ if(subletter == 'b') /* forced data-binary */
SET_BINMODE(stdin);
}
else {
clean_getout(config);
break;
}
- }
+ }
infiles = urlnode->infile;
/* 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;
- }
-
- res = CURLE_READ_ERROR;
- goto quit_urls;
+ if(urls) {
+ glob_cleanup(urls);
+ urls = NULL;
+ }
+ if(inglob) {
+ glob_cleanup(inglob);
+ inglob = NULL;
+ }
+
+ res = CURLE_READ_ERROR;
+ goto quit_urls;
}
infdfopen=TRUE;
uploadfilesize=fileinfo.st_size;
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);
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();
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
--- /dev/null
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP POST
+followlocation
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 301 OK swsclose\r
+Location: moo.html&testcase=/10110002\r
+Date: Thu, 09 Nov 2010 14:49:00 GMT\r
+Connection: close\r
+\r
+</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\r
+Location: moo.html&testcase=/10110002\r
+Date: Thu, 09 Nov 2010 14:49:00 GMT\r
+Connection: close\r
+\r
+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\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+Content-Length: 3\r
+Content-Type: application/x-www-form-urlencoded\r
+\r
+mooGET /blah/moo.html&testcase=/10110002 HTTP/1.1\r
+User-Agent: curl/7.10 (i686-pc-linux-gnu) libcurl/7.10 OpenSSL/0.9.6c ipv6 zlib/1.1.3\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP POST
+followlocation
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 301 OK swsclose\r
+Location: moo.html&testcase=/10120002\r
+Date: Thu, 09 Nov 2010 14:49:00 GMT\r
+Connection: close\r
+\r
+</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\r
+Location: moo.html&testcase=/10120002\r
+Date: Thu, 09 Nov 2010 14:49:00 GMT\r
+Connection: close\r
+\r
+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\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+Content-Length: 3\r
+Content-Type: application/x-www-form-urlencoded\r
+\r
+mooPOST /blah/moo.html&testcase=/10120002 HTTP/1.1\r
+User-Agent: curl/7.10 (i686-pc-linux-gnu) libcurl/7.10 OpenSSL/0.9.6c ipv6 zlib/1.1.3\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+Content-Length: 3\r
+Content-Type: application/x-www-form-urlencoded\r
+\r
+moo
+</protocol>
+</verify>
+</testcase>