- Martin Drasar provided the CURLOPT_POSTREDIR patch. It renames
authorDaniel Stenberg <daniel@haxx.se>
Fri, 5 Sep 2008 16:13:20 +0000 (16:13 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 5 Sep 2008 16:13:20 +0000 (16:13 +0000)
  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.

CHANGES
RELEASE-NOTES
docs/curl.1
include/curl/curl.h
lib/transfer.c
lib/url.c
lib/urldata.h
src/main.c
tests/data/Makefile.am
tests/data/test1076 [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 1908387..66ca25c 100644 (file)
--- 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
index c1f3bfc..8b3d204 100644 (file)
@@ -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)
index 57cb79d..0ce5c9f 100644 (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
 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
index 2b574c9..d93fd67 100644 (file)
@@ -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,
index 2fd6d4c..ddacb44 100644 (file)
@@ -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! */
index d6dec0d..a51ba43 100644 (file)
--- 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) {
index f1a001a..a8a7555 100644 (file)
@@ -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 */
index e9f9d30..81f1dfd 100644 (file)
@@ -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();
index 185d385..a33e3d2 100644 (file)
@@ -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 (file)
index 0000000..ad079eb
--- /dev/null
@@ -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\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=/10760002 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>