diff --git a/lib/http.c b/lib/http.c index 40ccd51df9..efd367b9e4 100644 --- a/lib/http.c +++ b/lib/http.c @@ -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 */ diff --git a/lib/http.h b/lib/http.h index 4f511d1f41..619fadc415 100644 --- a/lib/http.h +++ b/lib/http.h @@ -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 */ diff --git a/lib/mime.c b/lib/mime.c index 0a57e1e8a0..842b2da7e6 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -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. */ diff --git a/lib/multi.c b/lib/multi.c index c0d9175132..503bfdf0fb 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -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)) diff --git a/lib/setopt.c b/lib/setopt.c index 75e8cc4a3f..e2e3d8560c 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -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; diff --git a/lib/url.c b/lib/url.c index 32a64c81d2..38a6012254 100644 --- 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); diff --git a/lib/urldata.h b/lib/urldata.h index 6651147d20..d86bd9d5c0 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 */ diff --git a/tests/data/test650 b/tests/data/test650 index e034e1cef9..cb3f72cf84 100644 --- a/tests/data/test650 +++ b/tests/data/test650 @@ -10,15 +10,26 @@ FORM # # Server-side - -HTTP/1.1 200 OK + +HTTP/1.1 301 OK Date: Tue, 09 Nov 2010 14:49:00 GMT Server: test-server/fake swsclose Connection: close Content-Type: text/html +Location: /%TESTNUMBER0002 hello + +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- + # Client-side @@ -35,7 +46,7 @@ lib%TESTNUMBER -HTTP formpost using form API +HTTP formpost using form API - with redirect and re-POST Some data from stdin @@ -134,6 +145,90 @@ Content-Disposition: form-data; name="standardinput" Content-Type: application/octet-stream +16 + Some data from stdin + +30 + +-------------------------------- + +0 + +POST /%TESTNUMBER0002 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Transfer-Encoding: chunked +Content-Type: multipart/form-data; boundary=---------------------------- +Expect: 100-continue + +361 +------------------------------ +Content-Disposition: form-data; name="fieldname" +Content-Type: text/plain +X-customheader-1: Header 1 data +X-customheader-2: Header 2 data + +this is what we post to the silly web server +------------------------------ +Content-Disposition: form-data; name="fieldnam" + +uhis is what we post to the silly web serve +------------------------------ +Content-Disposition: form-data; name="multifile" +Content-Type: multipart/mixed; boundary=---------------------------- + +------------------------------ +Content-Disposition: attachment; filename="test%TESTNUMBER.filedata" +Content-Type: application/octet-stream + +This is data from a file. + +------------------------------ +Content-Disposition: attachment; filename="test%TESTNUMBER.filedata" +Content-Type: text/whatever + + +%if hyper +A5 +%else +a5 +%endif +This is data from a file. + +------------------------------ +Content-Disposition: attachment; filename="test%TESTNUMBER.filedata" +Content-Type: text/whatever + + +%if hyper +AF +%else +af +%endif +This is data from a file. + +-------------------------------- + +------------------------------ +Content-Disposition: form-data; name="filecontents" + + +%if hyper +10F +%else +10f +%endif +This is data from a file. + +------------------------------ +Content-Disposition: form-data; name="formlength" + +1367 +------------------------------ +Content-Disposition: form-data; name="standardinput" +Content-Type: application/octet-stream + + 16 Some data from stdin diff --git a/tests/libtest/lib650.c b/tests/libtest/lib650.c index 853029f1fe..14c79e94bc 100644 --- a/tests/libtest/lib650.c +++ b/tests/libtest/lib650.c @@ -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);