- 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.
This commit is contained in:
Daniel Stenberg
2008-09-05 16:13:20 +00:00
parent 4c9768565e
commit 18110b519c
10 changed files with 161 additions and 22 deletions

View File

@@ -7,6 +7,14 @@
Changelog Changelog
Daniel Stenberg (5 Sep 2008) 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 - Introducing CURLOPT_CERTINFO and the corresponding CURLINFO_CERTINFO. By
enabling this feature with CURLOPT_CERTINFO for a request using SSL (HTTPS 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 or FTPS), libcurl will gather lots of server certificate info and that info

View File

@@ -1,7 +1,7 @@
Curl and libcurl 7.19.1 Curl and libcurl 7.19.1
Public curl releases: 107 Public curl releases: 107
Command line options: 127 Command line options: 128
curl_easy_setopt() options: 154 curl_easy_setopt() options: 154
Public functions in libcurl: 58 Public functions in libcurl: 58
Known libcurl bindings: 36 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 pkg-config can now show supported_protocols and supported_features
o Added CURLOPT_CERTINFO and CURLINFO_CERTINFO o Added CURLOPT_CERTINFO and CURLINFO_CERTINFO
o Added CURLOPT_POSTREDIR
This release includes the following bugfixes: 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: advice from friends like these:
Keith Mok, Yang Tse, Daniel Fandrich, Guenter Knauf, Dmitriy Sergeyev, 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) Thanks! (and sorry if I forgot to mention someone)

View File

@@ -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 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 a redirection. This option is meaningful only when using \fI-L/--location\fP
(Added in 7.17.1) (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" .IP "--proxy-anyauth"
Tells curl to pick a suitable authentication method when communicating with Tells curl to pick a suitable authentication method when communicating with
the given proxy. This might cause an extra request/response round-trip. (Added the given proxy. This might cause an extra request/response round-trip. (Added

View File

@@ -1103,8 +1103,9 @@ typedef enum {
CINIT(NEW_FILE_PERMS, LONG, 159), CINIT(NEW_FILE_PERMS, LONG, 159),
CINIT(NEW_DIRECTORY_PERMS, LONG, 160), CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
/* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */ /* Set the behaviour of POST when redirecting. Values must be set to one
CINIT(POST301, LONG, 161), 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 */ /* used by scp/sftp to verify the host's public key */
CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
@@ -1147,6 +1148,11 @@ typedef enum {
the obsolete stuff removed! */ the obsolete stuff removed! */
/* Backwards compatibility with older names */ /* 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 */ /* These are scheduled to disappear by 2009 */
/* The following were added in 7.17.0 */ /* The following were added in 7.17.0 */
@@ -1211,6 +1217,14 @@ enum {
CURL_SSLVERSION_LAST /* never use, keep last */ 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 { typedef enum {
CURL_TIMECOND_NONE, CURL_TIMECOND_NONE,

View File

@@ -2286,7 +2286,7 @@ CURLcode Curl_follow(struct SessionHandle *data,
* libcurl gets the page that most user agents would get, libcurl has to * libcurl gets the page that most user agents would get, libcurl has to
* force GET. * force GET.
* *
* This behaviour can be overridden with CURLOPT_POST301. * This behaviour can be overridden with CURLOPT_POSTREDIR.
*/ */
if( (data->set.httpreq == HTTPREQ_POST if( (data->set.httpreq == HTTPREQ_POST
|| data->set.httpreq == HTTPREQ_POST_FORM) || 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 status. When interoperability with such clients is a concern, the
302 status code may be used instead, since most user agents react 302 status code may be used instead, since most user agents react
to a 302 response as described here for 303. 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 */ case 303: /* See Other */
/* Disable both types of POSTs, since doing a second POST when /* Disable both types of POSTs, since doing a second POST when
* following isn't what anyone would want! */ * following isn't what anyone would want! */

View File

@@ -1028,12 +1028,21 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
data->set.maxredirs = va_arg(param, long); data->set.maxredirs = va_arg(param, long);
break; 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)); long postRedir = va_arg(param, long);
break; data->set.post301 = (postRedir & CURL_REDIR_POST_301)?1:0;
data->set.post302 = (postRedir & CURL_REDIR_POST_302)?1:0;
}
break;
case CURLOPT_POST: case CURLOPT_POST:
/* Does this option serve a purpose anymore? Yes it does, when /* 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) { if (has_host_ntlm) {
data->state.authhost.done = FALSE; data->state.authhost.done = FALSE;
data->state.authhost.picked = data->state.authhost.picked =
data->state.authhost.want; data->state.authhost.want;
} }
if (has_proxy_ntlm) { if (has_proxy_ntlm) {
data->state.authproxy.done = FALSE; data->state.authproxy.done = FALSE;
data->state.authproxy.picked = data->state.authproxy.picked =
data->state.authproxy.want; data->state.authproxy.want;
} }
if (has_host_ntlm || has_proxy_ntlm) { if (has_host_ntlm || has_proxy_ntlm) {

View File

@@ -1358,6 +1358,7 @@ struct UserDefined {
for infinity */ for infinity */
bool post301; /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a bool post301; /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a
301 */ 301 */
bool post302; /* keep POSTs as POSTs after a 302 */
bool free_referer; /* set TRUE if 'referer' points to a string we bool free_referer; /* set TRUE if 'referer' points to a string we
allocated */ allocated */
void *postfields; /* if POST, set the fields' values here */ void *postfields; /* if POST, set the fields' values here */

View File

@@ -557,6 +557,7 @@ struct Configurable {
char *libcurl; /* output libcurl code to this file name */ char *libcurl; /* output libcurl code to this file name */
bool raw; bool raw;
bool post301; bool post301;
bool post302;
bool nokeepalive; /* for keepalive needs */ bool nokeepalive; /* for keepalive needs */
long alivetime; long alivetime;
@@ -780,6 +781,7 @@ static void help(void)
" -o/--output <file> Write output to <file> instead of stdout", " -o/--output <file> Write output to <file> instead of stdout",
" --pass <pass> Pass phrase for the private key (SSL/SSH)", " --pass <pass> Pass phrase for the private key (SSL/SSH)",
" --post301 Do not switch to GET after following a 301 redirect (H)", " --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", " -#/--progress-bar Display transfer progress as a progress bar",
" -x/--proxy <host[:port]> Use HTTP proxy on given port", " -x/--proxy <host[:port]> Use HTTP proxy on given port",
" --proxy-anyauth Pick \"any\" proxy authentication method (H)", " --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 */ {"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */
{"$2", "socks5-hostname", TRUE}, {"$2", "socks5-hostname", TRUE},
{"$3", "keepalive-time", TRUE}, {"$3", "keepalive-time", TRUE},
{"$4", "post302", FALSE},
{"0", "http1.0", FALSE}, {"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE}, {"1", "tlsv1", FALSE},
@@ -2177,6 +2180,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
if(str2num(&config->alivetime, nextarg)) if(str2num(&config->alivetime, nextarg))
return PARAM_BAD_NUMERIC; return PARAM_BAD_NUMERIC;
break; break;
case '4': /* --post302 */
config->post302 = toggle;
break;
} }
break; break;
case '#': /* --progress-bar */ 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 */ /* default is to output the letter after the backslash */
switch(out = *line) { switch(out = *line) {
case '\0': case '\0':
continue; /* this'll break out of the loop */ continue; /* this'll break out of the loop */
case 't': case 't':
out='\t'; out='\t';
break; break;
case 'n': case 'n':
out='\n'; out='\n';
break; break;
case 'r': case 'r':
out='\r'; out='\r';
break; break;
case 'v': case 'v':
out='\v'; out='\v';
break; break;
} }
*param++=out; *param++=out;
line++; line++;
@@ -4777,12 +4783,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
} }
/* curl 7.17.1 */ /* curl 7.17.1 */
my_setopt(curl, CURLOPT_POST301, config->post301);
if (!config->nokeepalive) { if (!config->nokeepalive) {
my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback); my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
my_setopt(curl, CURLOPT_SOCKOPTDATA, config); 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; retry_numretries = config->req_retry;
retrystart = cutil_tvnow(); retrystart = cutil_tvnow();

View File

@@ -57,7 +57,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test1048 test1049 test1050 test1051 test1052 test1053 test1054 test1055 \ test1048 test1049 test1050 test1051 test1052 test1053 test1054 test1055 \
test1056 test1057 test1058 test1059 test1060 test1061 test1062 test1063 \ test1056 test1057 test1058 test1059 test1060 test1061 test1062 test1063 \
test1064 test1065 test1066 test1067 test1068 test1069 test1070 test1071 \ test1064 test1065 test1066 test1067 test1068 test1069 test1070 test1071 \
test1072 test1073 test1074 test1075 test1072 test1073 test1074 test1075 test1076
filecheck: filecheck:
@mkdir test-place; \ @mkdir test-place; \

79
tests/data/test1076 Normal file
View File

@@ -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>