From 028e8fadde7943900563d11e7c8a685ef4a232f3 Mon Sep 17 00:00:00 2001
From: Andrei Cipu <acipu@ixiacom.com>
Date: Fri, 30 Mar 2012 10:40:04 +0300
Subject: [PATCH] Allow the user to ask for a POST after a previous POST
 request returned 303.

As it turns out, some people do want that after all.
---
 include/curl/curl.h |    9 ++++++---
 lib/transfer.c      |    7 ++++---
 lib/url.c           |    4 +++-
 lib/urldata.h       |    1 +
 4 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/include/curl/curl.h b/include/curl/curl.h
index f2501cd..f3166d9 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1624,13 +1624,16 @@ enum CURL_TLSAUTH {
 };
 
 /* 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 */
+   CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
+   can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
+   | CURL_REDIR_POST_303 == 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)
+#define CURL_REDIR_POST_303 4
+#define CURL_REDIR_POST_ALL \
+    (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
 
 typedef enum {
   CURL_TIMECOND_NONE,
diff --git a/lib/transfer.c b/lib/transfer.c
index d6061be..6790ab2 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -1900,9 +1900,10 @@ CURLcode Curl_follow(struct SessionHandle *data,
     break;
 
   case 303: /* See Other */
-    /* Disable both types of POSTs, since doing a second POST when
-     * following isn't what anyone would want! */
-    if(data->set.httpreq != HTTPREQ_GET) {
+    /* Disable both types of POSTs, unless the user explicitely
+       asks for POST after POST */
+    if(data->set.httpreq != HTTPREQ_GET
+      && !data->set.post303) {
       data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
       infof(data, "Disables POST, goes with %s\n",
             data->set.opt_no_body?"HEAD":"GET");
diff --git a/lib/url.c b/lib/url.c
index 01e217c..492765e 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1111,12 +1111,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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
+     * CURL_REDIR_POST_303 - POST is kept as POST after 303
+     * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
      * other - POST is kept as POST after 301 and 302
      */
     long postRedir = va_arg(param, long);
     data->set.post301 = (postRedir & CURL_REDIR_POST_301)?TRUE:FALSE;
     data->set.post302 = (postRedir & CURL_REDIR_POST_302)?TRUE:FALSE;
+    data->set.post303 = (postRedir & CURL_REDIR_POST_303)?TRUE:FALSE;
   }
   break;
 
diff --git a/lib/urldata.h b/lib/urldata.h
index 7830686..4f82497 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1370,6 +1370,7 @@ struct UserDefined {
   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 post303;      /* keep POSTs as POSTs after a 303 */
   bool free_referer; /* set TRUE if 'referer' points to a string we
                         allocated */
   void *postfields;  /* if POST, set the fields' values here */
-- 
1.7.7

