aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rw-r--r--RELEASE-NOTES5
-rw-r--r--docs/curl.17
-rw-r--r--include/curl/curl.h18
-rw-r--r--lib/transfer.c13
-rw-r--r--lib/url.c21
-rw-r--r--lib/urldata.h1
-rw-r--r--src/main.c29
-rw-r--r--tests/data/Makefile.am2
-rw-r--r--tests/data/test107679
10 files changed, 161 insertions, 22 deletions
diff --git a/CHANGES b/CHANGES
index 1908387ce..66ca25c50 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,14 @@
Changelog
Daniel Stenberg (5 Sep 2008)
+- Martin Drasar provided the CURLOPT_POSTREDIR patch. It renames
+ CURLOPT_POST301 (but adds a define for backwards compatibility for you who
+ don't define CURL_NO_OLDIES). This option allows you to now also change the
+ libcurl behavior for a HTTP response 302 after a POST to not use GET in the
+ subsequent request (when CURLOPT_FOLLOWLOCATION is enabled). I edited the
+ patch somewhat before commit. The curl tool got a matching --post302
+ option. Test case 1076 was added to verify this.
+
- Introducing CURLOPT_CERTINFO and the corresponding CURLINFO_CERTINFO. By
enabling this feature with CURLOPT_CERTINFO for a request using SSL (HTTPS
or FTPS), libcurl will gather lots of server certificate info and that info
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index c1f3bfcca..8b3d204da 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -1,7 +1,7 @@
Curl and libcurl 7.19.1
Public curl releases: 107
- Command line options: 127
+ Command line options: 128
curl_easy_setopt() options: 154
Public functions in libcurl: 58
Known libcurl bindings: 36
@@ -11,6 +11,7 @@ This release includes the following changes:
o pkg-config can now show supported_protocols and supported_features
o Added CURLOPT_CERTINFO and CURLINFO_CERTINFO
+ o Added CURLOPT_POSTREDIR
This release includes the following bugfixes:
@@ -30,6 +31,6 @@ This release would not have looked like this without help, code, reports and
advice from friends like these:
Keith Mok, Yang Tse, Daniel Fandrich, Guenter Knauf, Dmitriy Sergeyev,
- Linus Nielsen Feltzing
+ Linus Nielsen Feltzing, Martin Drasar
Thanks! (and sorry if I forgot to mention someone)
diff --git a/docs/curl.1 b/docs/curl.1
index 57cb79dde..0ce5c9fbf 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -870,6 +870,13 @@ in web browsers, so curl does the conversion by default to maintain
consistency. However, a server may requires a POST to remain a POST after such
a redirection. This option is meaningful only when using \fI-L/--location\fP
(Added in 7.17.1)
+.IP "--post302"
+Tells curl to respect RFC 2616/10.3.2 and not convert POST requests into GET
+requests when following a 302 redirection. The non-RFC behaviour is ubiquitous
+in web browsers, so curl does the conversion by default to maintain
+consistency. However, a server may requires a POST to remain a POST after such
+a redirection. This option is meaningful only when using \fI-L/--location\fP
+(Added in 7.19.1)
.IP "--proxy-anyauth"
Tells curl to pick a suitable authentication method when communicating with
the given proxy. This might cause an extra request/response round-trip. (Added
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 2b574c9d7..d93fd6764 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1103,8 +1103,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),
+ /* Set the behaviour of POST when redirecting. Values must be set to one
+ of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
+ CINIT(POSTREDIR, LONG, 161),
/* used by scp/sftp to verify the host's public key */
CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
@@ -1147,6 +1148,11 @@ typedef enum {
the obsolete stuff removed! */
/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2011 */
+
+/* This was added in version 7.19.1 */
+#define CURLOPT_POST301 CURLOPT_POSTREDIR
+
/* These are scheduled to disappear by 2009 */
/* The following were added in 7.17.0 */
@@ -1211,6 +1217,14 @@ enum {
CURL_SSLVERSION_LAST /* never use, keep last */
};
+/* symbols to use with CURLOPT_POSTREDIR.
+ CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that
+ CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */
+
+#define CURL_REDIR_GET_ALL 0
+#define CURL_REDIR_POST_301 1
+#define CURL_REDIR_POST_302 2
+#define CURL_REDIR_POST_ALL (CURL_REDIR_POST_301|CURL_REDIR_POST_302)
typedef enum {
CURL_TIMECOND_NONE,
diff --git a/lib/transfer.c b/lib/transfer.c
index 2fd6d4cf3..ddacb442a 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -2286,7 +2286,7 @@ CURLcode Curl_follow(struct SessionHandle *data,
* libcurl gets the page that most user agents would get, libcurl has to
* force GET.
*
- * This behaviour can be overridden with CURLOPT_POST301.
+ * This behaviour can be overridden with CURLOPT_POSTREDIR.
*/
if( (data->set.httpreq == HTTPREQ_POST
|| data->set.httpreq == HTTPREQ_POST_FORM)
@@ -2313,7 +2313,18 @@ CURLcode Curl_follow(struct SessionHandle *data,
status. When interoperability with such clients is a concern, the
302 status code may be used instead, since most user agents react
to a 302 response as described here for 303.
+
+ This behaviour can be overriden with CURLOPT_POSTREDIR
*/
+ if( (data->set.httpreq == HTTPREQ_POST
+ || data->set.httpreq == HTTPREQ_POST_FORM)
+ && !data->set.post302) {
+ infof(data,
+ "Violate RFC 2616/10.3.3 and switch from POST to GET\n");
+ data->set.httpreq = HTTPREQ_GET;
+ }
+ break;
+
case 303: /* See Other */
/* Disable both types of POSTs, since doing a second POST when
* following isn't what anyone would want! */
diff --git a/lib/url.c b/lib/url.c
index d6dec0d0a..a51ba4394 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1028,12 +1028,21 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
data->set.maxredirs = va_arg(param, long);
break;
- case CURLOPT_POST301:
+ case CURLOPT_POSTREDIR:
+ {
/*
- * Obey RFC 2616/10.3.2 and resubmit a POST as a POST after a 301.
+ * Set the behaviour of POST when redirecting
+ * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+ * CURL_REDIR_POST_301 - POST is kept as POST after 301
+ * CURL_REDIR_POST_302 - POST is kept as POST after 302
+ * CURL_REDIR_POST_ALL - POST is kept as POST after 301 and 302
+ * other - POST is kept as POST after 301 and 302
*/
- data->set.post301 = (bool)(0 != va_arg(param, long));
- break;
+ long postRedir = va_arg(param, long);
+ data->set.post301 = (postRedir & CURL_REDIR_POST_301)?1:0;
+ data->set.post302 = (postRedir & CURL_REDIR_POST_302)?1:0;
+ }
+ break;
case CURLOPT_POST:
/* Does this option serve a purpose anymore? Yes it does, when
@@ -2200,13 +2209,13 @@ CURLcode Curl_disconnect(struct connectdata *conn)
if (has_host_ntlm) {
data->state.authhost.done = FALSE;
data->state.authhost.picked =
- data->state.authhost.want;
+ data->state.authhost.want;
}
if (has_proxy_ntlm) {
data->state.authproxy.done = FALSE;
data->state.authproxy.picked =
- data->state.authproxy.want;
+ data->state.authproxy.want;
}
if (has_host_ntlm || has_proxy_ntlm) {
diff --git a/lib/urldata.h b/lib/urldata.h
index f1a001aa0..a8a7555aa 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1358,6 +1358,7 @@ struct UserDefined {
for infinity */
bool post301; /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a
301 */
+ bool post302; /* keep POSTs as POSTs after a 302 */
bool free_referer; /* set TRUE if 'referer' points to a string we
allocated */
void *postfields; /* if POST, set the fields' values here */
diff --git a/src/main.c b/src/main.c
index e9f9d30a2..81f1dfd9c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -557,6 +557,7 @@ struct Configurable {
char *libcurl; /* output libcurl code to this file name */
bool raw;
bool post301;
+ bool post302;
bool nokeepalive; /* for keepalive needs */
long alivetime;
@@ -780,6 +781,7 @@ static void help(void)
" -o/--output <file> Write output to <file> instead of stdout",
" --pass <pass> Pass phrase for the private key (SSL/SSH)",
" --post301 Do not switch to GET after following a 301 redirect (H)",
+ " --post302 Do not switch to GET after following a 302 redirect (H)",
" -#/--progress-bar Display transfer progress as a progress bar",
" -x/--proxy <host[:port]> Use HTTP proxy on given port",
" --proxy-anyauth Pick \"any\" proxy authentication method (H)",
@@ -1669,6 +1671,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */
{"$2", "socks5-hostname", TRUE},
{"$3", "keepalive-time", TRUE},
+ {"$4", "post302", FALSE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
@@ -2177,6 +2180,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
if(str2num(&config->alivetime, nextarg))
return PARAM_BAD_NUMERIC;
break;
+ case '4': /* --post302 */
+ config->post302 = toggle;
+ break;
}
break;
case '#': /* --progress-bar */
@@ -2946,19 +2952,19 @@ static const char *unslashquote(const char *line, char *param)
/* default is to output the letter after the backslash */
switch(out = *line) {
case '\0':
- continue; /* this'll break out of the loop */
+ continue; /* this'll break out of the loop */
case 't':
- out='\t';
- break;
+ out='\t';
+ break;
case 'n':
- out='\n';
- break;
+ out='\n';
+ break;
case 'r':
- out='\r';
- break;
+ out='\r';
+ break;
case 'v':
- out='\v';
- break;
+ out='\v';
+ break;
}
*param++=out;
line++;
@@ -4777,12 +4783,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
}
/* curl 7.17.1 */
- my_setopt(curl, CURLOPT_POST301, config->post301);
if (!config->nokeepalive) {
my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
}
+ /* curl 7.19.1 (the 301 version existed in 7.18.2) */
+ my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
+ (config->post302 ? CURL_REDIR_POST_302 : FALSE));
+
retry_numretries = config->req_retry;
retrystart = cutil_tvnow();
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 185d385e9..a33e3d2e1 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -57,7 +57,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test1048 test1049 test1050 test1051 test1052 test1053 test1054 test1055 \
test1056 test1057 test1058 test1059 test1060 test1061 test1062 test1063 \
test1064 test1065 test1066 test1067 test1068 test1069 test1070 test1071 \
- test1072 test1073 test1074 test1075
+ test1072 test1073 test1074 test1075 test1076
filecheck:
@mkdir test-place; \
diff --git a/tests/data/test1076 b/tests/data/test1076
new file mode 100644
index 000000000..ad079eb94
--- /dev/null
+++ b/tests/data/test1076
@@ -0,0 +1,79 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP POST
+followlocation
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 302 OK swsclose
+Location: moo.html&testcase=/10760002
+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 302 OK swsclose
+Location: moo.html&testcase=/10760002
+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 302 redirect and --post302
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/blah/1076 -L -d "moo" --post302
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol nonewline="yes">
+POST /blah/1076 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 3
+Content-Type: application/x-www-form-urlencoded
+
+mooPOST /blah/moo.html&testcase=/10760002 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>