- 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:
8
CHANGES
8
CHANGES
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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! */
|
||||||
|
|||||||
21
lib/url.c
21
lib/url.c
@@ -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) {
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
29
src/main.c
29
src/main.c
@@ -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();
|
||||||
|
|||||||
@@ -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
79
tests/data/test1076
Normal 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>
|
||||||
Reference in New Issue
Block a user