]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
lib: move mimepost data from ->req.p.http to ->state
authorDaniel Stenberg <daniel@haxx.se>
Wed, 16 Aug 2023 08:43:02 +0000 (10:43 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 17 Aug 2023 21:49:57 +0000 (23:49 +0200)
When the legacy CURLOPT_HTTPPOST option is used, it gets converted into
the modem mimpost struct at first use. This data is (now) kept for the
entire transfer and not only per single HTTP request. This re-enables
rewind in the beginning of the second request instead of in end of the
first, as brought by 1b39731.

The request struct is per-request data only.

Extend test 650 to verify.

Fixes #11680
Reported-by: yushicheng7788 on github
Closes #11682

lib/http.c
lib/http.h
lib/mime.c
lib/multi.c
lib/setopt.c
lib/url.c
lib/urldata.h
tests/data/test650
tests/libtest/lib650.c

index 40ccd51df917c80c00fa4cadfe13f6e8f752abc8..efd367b9e4c9f996ca0def7720d9aa70a121f139 100644 (file)
@@ -233,7 +233,6 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
   if(!http)
     return CURLE_OUT_OF_MEMORY;
 
-  Curl_mime_initpart(&http->form);
   data->req.p.http = http;
   connkeep(conn, "HTTP default");
 
@@ -1577,7 +1576,6 @@ CURLcode Curl_http_done(struct Curl_easy *data,
     return CURLE_OK;
 
   Curl_dyn_free(&http->send_buffer);
-  Curl_mime_cleanpart(&http->form);
   Curl_dyn_reset(&data->state.headerb);
   Curl_hyper_done(data);
   Curl_ws_done(data);
@@ -2375,47 +2373,53 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
 
   switch(httpreq) {
   case HTTPREQ_POST_MIME:
-    http->sendit = &data->set.mimepost;
+    data->state.mimepost = &data->set.mimepost;
     break;
 #ifndef CURL_DISABLE_FORM_API
   case HTTPREQ_POST_FORM:
-    /* Convert the form structure into a mime structure. */
-    Curl_mime_cleanpart(&http->form);
-    result = Curl_getformdata(data, &http->form, data->set.httppost,
-                              data->state.fread_func);
-    if(result)
-      return result;
-    http->sendit = &http->form;
+    /* Convert the form structure into a mime structure, then keep
+       the conversion */
+    if(!data->state.formp) {
+      data->state.formp = calloc(sizeof(curl_mimepart), 1);
+      if(!data->state.formp)
+        return CURLE_OUT_OF_MEMORY;
+      Curl_mime_cleanpart(data->state.formp);
+      result = Curl_getformdata(data, data->state.formp, data->set.httppost,
+                                data->state.fread_func);
+      if(result)
+        return result;
+      data->state.mimepost = data->state.formp;
+    }
     break;
 #endif
   default:
-    http->sendit = NULL;
+    data->state.mimepost = NULL;
   }
 
 #ifndef CURL_DISABLE_MIME
-  if(http->sendit) {
+  if(data->state.mimepost) {
     const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
 
     /* Read and seek body only. */
-    http->sendit->flags |= MIME_BODY_ONLY;
+    data->state.mimepost->flags |= MIME_BODY_ONLY;
 
     /* Prepare the mime structure headers & set content type. */
 
     if(cthdr)
       for(cthdr += 13; *cthdr == ' '; cthdr++)
         ;
-    else if(http->sendit->kind == MIMEKIND_MULTIPART)
+    else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
       cthdr = "multipart/form-data";
 
-    curl_mime_headers(http->sendit, data->set.headers, 0);
-    result = Curl_mime_prepare_headers(data, http->sendit, cthdr,
+    curl_mime_headers(data->state.mimepost, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
                                        NULL, MIMESTRATEGY_FORM);
-    curl_mime_headers(http->sendit, NULL, 0);
+    curl_mime_headers(data->state.mimepost, NULL, 0);
     if(!result)
-      result = Curl_mime_rewind(http->sendit);
+      result = Curl_mime_rewind(data->state.mimepost);
     if(result)
       return result;
-    http->postsize = Curl_mime_size(http->sendit);
+    http->postsize = Curl_mime_size(data->state.mimepost);
   }
 #endif
 
@@ -2571,7 +2575,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
     {
       struct curl_slist *hdr;
 
-      for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
+      for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
         result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
         if(result)
           return result;
@@ -2606,7 +2610,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
 
     /* Read from mime structure. */
     data->state.fread_func = (curl_read_callback) Curl_mime_read;
-    data->state.in = (void *) http->sendit;
+    data->state.in = (void *) data->state.mimepost;
     http->sending = HTTPSEND_BODY;
 
     /* this sends the buffer and frees all the buffer resources */
index 4f511d1f412ed4bfbf5fe7004cf6b0d331f58b21..619fadc415504b187d8d428f8db1e929d67c725f 100644 (file)
@@ -198,13 +198,8 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
  * HTTP unique setup
  ***************************************************************************/
 struct HTTP {
-  curl_mimepart *sendit;
   curl_off_t postsize; /* off_t to handle large file sizes */
   const char *postdata;
-
-  /* For FORM posting */
-  curl_mimepart form;
-
   struct back {
     curl_read_callback fread_func; /* backup storage for fread pointer */
     void *fread_in;           /* backup storage for fread_in pointer */
index 0a57e1e8a0c1b7a943d9ac9e958f64a689aaceb9..842b2da7e60b5344f8f33434fa26abbcd375d740 100644 (file)
@@ -1167,14 +1167,16 @@ static void mime_subparts_unbind(void *ptr)
 
 void Curl_mime_cleanpart(curl_mimepart *part)
 {
-  cleanup_part_content(part);
-  curl_slist_free_all(part->curlheaders);
-  if(part->flags & MIME_USERHEADERS_OWNER)
-    curl_slist_free_all(part->userheaders);
-  Curl_safefree(part->mimetype);
-  Curl_safefree(part->name);
-  Curl_safefree(part->filename);
-  Curl_mime_initpart(part);
+  if(part) {
+    cleanup_part_content(part);
+    curl_slist_free_all(part->curlheaders);
+    if(part->flags & MIME_USERHEADERS_OWNER)
+      curl_slist_free_all(part->userheaders);
+    Curl_safefree(part->mimetype);
+    Curl_safefree(part->name);
+    Curl_safefree(part->filename);
+    Curl_mime_initpart(part);
+  }
 }
 
 /* Recursively delete a mime handle and its parts. */
index c0d9175132a7ac2dc65bee5d626af0f12d719204..503bfdf0fbdb9399d3077504ad21b176cb0baab4 100644 (file)
@@ -1799,9 +1799,8 @@ static CURLcode protocol_connect(struct Curl_easy *data,
  */
 static CURLcode readrewind(struct Curl_easy *data)
 {
-  struct connectdata *conn = data->conn;
   curl_mimepart *mimepart = &data->set.mimepost;
-  DEBUGASSERT(conn);
+  DEBUGASSERT(data->conn);
 
   data->state.rewindbeforesend = FALSE; /* we rewind now */
 
@@ -1814,12 +1813,12 @@ static CURLcode readrewind(struct Curl_easy *data)
   /* We have sent away data. If not using CURLOPT_POSTFIELDS or
      CURLOPT_HTTPPOST, call app to rewind
   */
-  if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
-    struct HTTP *http = data->req.p.http;
-
-    if(http->sendit)
-      mimepart = http->sendit;
+#ifndef CURL_DISABLE_HTTP
+  if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
+    if(data->state.mimepost)
+      mimepart = data->state.mimepost;
   }
+#endif
   if(data->set.postfields ||
      (data->state.httpreq == HTTPREQ_GET) ||
      (data->state.httpreq == HTTPREQ_HEAD))
index 75e8cc4a3f816b9c15f4a1da0bf0d3d2a16dbe4d..e2e3d8560ca47785712789518cc467f80dc1e01f 100644 (file)
@@ -669,11 +669,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 #ifndef CURL_DISABLE_FORM_API
   case CURLOPT_HTTPPOST:
     /*
-     * Set to make us do HTTP POST
+     * Set to make us do HTTP POST. Legacy API-style.
      */
     data->set.httppost = va_arg(param, struct curl_httppost *);
     data->set.method = HTTPREQ_POST_FORM;
     data->set.opt_no_body = FALSE; /* this is implied */
+    Curl_mime_cleanpart(data->state.formp);
+    Curl_safefree(data->state.formp);
     break;
 #endif
 
@@ -985,6 +987,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     if(!result) {
       data->set.method = HTTPREQ_POST_MIME;
       data->set.opt_no_body = FALSE; /* this is implied */
+#ifndef CURL_DISABLE_FORM_API
+      Curl_mime_cleanpart(data->state.formp);
+      Curl_safefree(data->state.formp);
+#endif
     }
     break;
 
index 32a64c81d2e4a76472f623fb873b9de7cf652e29..38a60122540dc50c740489ec699529dcea8648e5 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -457,6 +457,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
   }
 #endif
 
+  Curl_mime_cleanpart(data->state.formp);
+#ifndef CURL_DISABLE_HTTP
+  Curl_safefree(data->state.formp);
+#endif
+
   /* destruct wildcard structures if it is needed */
   Curl_wildcard_dtor(&data->wildcard);
   Curl_freeset(data);
index 6651147d20d06b10b066ce46becd6f0d9909e6b0..d86bd9d5c0dcc492a0cf4e0b69bf501763a309c7 100644 (file)
@@ -1405,6 +1405,9 @@ struct UrlState {
   struct curl_slist *resolve; /* set to point to the set.resolve list when
                                  this should be dealt with in pretransfer */
 #ifndef CURL_DISABLE_HTTP
+  curl_mimepart *mimepost;
+  curl_mimepart *formp; /* storage for old API form-posting, alloced on
+                           demand */
   size_t trailers_bytes_sent;
   struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
                                  headers */
index e034e1cef934b945add1bd01500a67a25addfb9b..cb3f72cf8469e25e6ae2b731ced16434bb3f84a0 100644 (file)
@@ -10,15 +10,26 @@ FORM
 #
 # Server-side
 <reply>
-<data>
-HTTP/1.1 200 OK\r
+<data nocheck="yes">
+HTTP/1.1 301 OK\r
 Date: Tue, 09 Nov 2010 14:49:00 GMT\r
 Server: test-server/fake swsclose\r
 Connection: close\r
 Content-Type: text/html\r
+Location: /%TESTNUMBER0002
 \r
 hello
 </data>
+<data2 crlf="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-foo-
+</data>
 </reply>
 
 # Client-side
@@ -35,7 +46,7 @@ lib%TESTNUMBER
 </tool>
 
  <name>
-HTTP formpost using form API
+HTTP formpost using form API - with redirect and re-POST
  </name>
 <stdin>
  Some data from stdin
@@ -134,6 +145,90 @@ Content-Disposition: form-data; name="standardinput"
 Content-Type: application/octet-stream\r
 \r
 \r
+16\r
+ Some data from stdin
+\r
+30\r
+\r
+--------------------------------\r
+\r
+0\r
+\r
+POST /%TESTNUMBER0002 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+Transfer-Encoding: chunked\r
+Content-Type: multipart/form-data; boundary=----------------------------\r
+Expect: 100-continue\r
+\r
+361\r
+------------------------------\r
+Content-Disposition: form-data; name="fieldname"\r
+Content-Type: text/plain\r
+X-customheader-1: Header 1 data\r
+X-customheader-2: Header 2 data\r
+\r
+this is what we post to the silly web server\r
+------------------------------\r
+Content-Disposition: form-data; name="fieldnam"\r
+\r
+uhis is what we post to the silly web serve\r
+------------------------------\r
+Content-Disposition: form-data; name="multifile"\r
+Content-Type: multipart/mixed; boundary=----------------------------\r
+\r
+------------------------------\r
+Content-Disposition: attachment; filename="test%TESTNUMBER.filedata"\r
+Content-Type: application/octet-stream\r
+\r
+This is data from a file.
+\r
+------------------------------\r
+Content-Disposition: attachment; filename="test%TESTNUMBER.filedata"\r
+Content-Type: text/whatever\r
+\r
+\r
+%if hyper
+A5\r
+%else
+a5\r
+%endif
+This is data from a file.
+\r
+------------------------------\r
+Content-Disposition: attachment; filename="test%TESTNUMBER.filedata"\r
+Content-Type: text/whatever\r
+\r
+\r
+%if hyper
+AF\r
+%else
+af\r
+%endif
+This is data from a file.
+\r
+--------------------------------\r
+\r
+------------------------------\r
+Content-Disposition: form-data; name="filecontents"\r
+\r
+\r
+%if hyper
+10F\r
+%else
+10f\r
+%endif
+This is data from a file.
+\r
+------------------------------\r
+Content-Disposition: form-data; name="formlength"\r
+\r
+1367\r
+------------------------------\r
+Content-Disposition: form-data; name="standardinput"\r
+Content-Type: application/octet-stream\r
+\r
+\r
 16\r
  Some data from stdin
 \r
index 853029f1fefc8e6b522226a97edc9aeec034d3fb..14c79e94bc6e3c10ff20f8da91d1bc5650a13eb1 100644 (file)
@@ -189,6 +189,9 @@ int test(char *URL)
   /* get verbose debug output please */
   test_setopt(curl, CURLOPT_VERBOSE, 1L);
 
+  test_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+  test_setopt(curl, CURLOPT_POSTREDIR, (long)CURL_REDIR_POST_301);
+
   /* include headers in the output */
   test_setopt(curl, CURLOPT_HEADER, 1L);