mime: relax easy/mime structures binding
Deprecation and removal of codeset conversion support from the library have released the strict need for an early binding of mime structures to an easy handle (https://github.com/curl/curl/commit/2610142). This constraint currently forces to create the handle before the mime structure and the latter cannot be attached to another handle once created (see https://curl.se/mail/lib-2022-08/0027.html). This commit removes the handle pointers from the mime structures allowing more flexibility on their use. When an easy handle is duplicated, bound mime structures must however still be duplicated too as their components hold send-time dynamic information. Closes #9927
This commit is contained in:
Родитель
383fb29da1
Коммит
eb559c8056
|
@ -31,11 +31,14 @@ curl_mime_init - create a mime handle
|
|||
curl_mime *curl_mime_init(CURL *easy_handle);
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
\fIcurl_mime_init(3)\fP creates a handle to a new empty mime structure
|
||||
intended to be used with \fIeasy_handle\fP. This mime structure can be
|
||||
subsequently filled using the mime API, then attached to \fIeasy_handle\fP
|
||||
using option \fICURLOPT_MIMEPOST(3)\fP within a \fIcurl_easy_setopt(3)\fP
|
||||
call.
|
||||
\fIcurl_mime_init(3)\fP creates a handle to a new empty mime structure,
|
||||
This mime structure can be subsequently filled using the mime API, then
|
||||
attached to some easy handle using option \fICURLOPT_MIMEPOST(3)\fP within
|
||||
a \fIcurl_easy_setopt(3)\fP call or added as a multipart in another mime
|
||||
handle's part using \fIcurl_mime_subparts(3)\fP.
|
||||
|
||||
\fIeasy_handle\fP is used for part separator randomization and error
|
||||
reporting. It does not need to be the final target handle.
|
||||
|
||||
Using a mime handle is the recommended way to post an HTTP form, format and
|
||||
send a multi-part email with SMTP or upload such an email to an IMAP server.
|
||||
|
@ -65,5 +68,6 @@ As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.
|
|||
A mime struct handle, or NULL upon failure.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_mime_addpart "(3),"
|
||||
.BR curl_mime_subparts "(3),"
|
||||
.BR curl_mime_free "(3),"
|
||||
.BR CURLOPT_MIMEPOST "(3)"
|
||||
|
|
|
@ -828,7 +828,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
|
|||
/* Copy src->set into dst->set first, then deal with the strings
|
||||
afterwards */
|
||||
dst->set = src->set;
|
||||
Curl_mime_initpart(&dst->set.mimepost, dst);
|
||||
Curl_mime_initpart(&dst->set.mimepost);
|
||||
|
||||
/* clear all string pointers first */
|
||||
memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
|
||||
|
@ -862,7 +862,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
|
|||
}
|
||||
|
||||
/* Duplicate mime data. */
|
||||
result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
|
||||
result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost);
|
||||
|
||||
if(src->set.resolve)
|
||||
dst->state.resolve = dst->set.resolve;
|
||||
|
|
|
@ -715,10 +715,10 @@ int curl_formget(struct curl_httppost *form, void *arg,
|
|||
CURLcode result;
|
||||
curl_mimepart toppart;
|
||||
|
||||
Curl_mime_initpart(&toppart, NULL); /* default form is empty */
|
||||
Curl_mime_initpart(&toppart); /* default form is empty */
|
||||
result = Curl_getformdata(NULL, &toppart, form, NULL);
|
||||
if(!result)
|
||||
result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
|
||||
result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
|
||||
NULL, MIMESTRATEGY_FORM);
|
||||
|
||||
while(!result) {
|
||||
|
|
|
@ -265,7 +265,7 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
|
|||
if(!http)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
Curl_mime_initpart(&http->form, data);
|
||||
Curl_mime_initpart(&http->form);
|
||||
data->req.p.http = http;
|
||||
|
||||
if(data->state.httpwant == CURL_HTTP_VERSION_3) {
|
||||
|
@ -2303,7 +2303,7 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
|
|||
cthdr = "multipart/form-data";
|
||||
|
||||
curl_mime_headers(http->sendit, data->set.headers, 0);
|
||||
result = Curl_mime_prepare_headers(http->sendit, cthdr,
|
||||
result = Curl_mime_prepare_headers(data, http->sendit, cthdr,
|
||||
NULL, MIMESTRATEGY_FORM);
|
||||
curl_mime_headers(http->sendit, NULL, 0);
|
||||
if(!result)
|
||||
|
|
|
@ -777,7 +777,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
|
|||
|
||||
/* Add external headers and mime version. */
|
||||
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
|
||||
result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
|
||||
result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
|
||||
NULL, MIMESTRATEGY_MAIL);
|
||||
|
||||
if(!result)
|
||||
|
|
32
lib/mime.c
32
lib/mime.c
|
@ -1175,7 +1175,7 @@ void Curl_mime_cleanpart(curl_mimepart *part)
|
|||
Curl_safefree(part->mimetype);
|
||||
Curl_safefree(part->name);
|
||||
Curl_safefree(part->filename);
|
||||
Curl_mime_initpart(part, part->easy);
|
||||
Curl_mime_initpart(part);
|
||||
}
|
||||
|
||||
/* Recursively delete a mime handle and its parts. */
|
||||
|
@ -1195,7 +1195,8 @@ void curl_mime_free(curl_mime *mime)
|
|||
}
|
||||
}
|
||||
|
||||
CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
|
||||
CURLcode Curl_mime_duppart(struct Curl_easy *data,
|
||||
curl_mimepart *dst, const curl_mimepart *src)
|
||||
{
|
||||
curl_mime *mime;
|
||||
curl_mimepart *d;
|
||||
|
@ -1224,13 +1225,13 @@ CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
|
|||
case MIMEKIND_MULTIPART:
|
||||
/* No one knows about the cloned subparts, thus always attach ownership
|
||||
to the part. */
|
||||
mime = curl_mime_init(dst->easy);
|
||||
mime = curl_mime_init(data);
|
||||
res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Duplicate subparts. */
|
||||
for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
|
||||
d = curl_mime_addpart(mime);
|
||||
res = d? Curl_mime_duppart(d, s): CURLE_OUT_OF_MEMORY;
|
||||
res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
break;
|
||||
default: /* Invalid kind: should not occur. */
|
||||
|
@ -1282,7 +1283,6 @@ curl_mime *curl_mime_init(struct Curl_easy *easy)
|
|||
mime = (curl_mime *) malloc(sizeof(*mime));
|
||||
|
||||
if(mime) {
|
||||
mime->easy = easy;
|
||||
mime->parent = NULL;
|
||||
mime->firstpart = NULL;
|
||||
mime->lastpart = NULL;
|
||||
|
@ -1302,10 +1302,9 @@ curl_mime *curl_mime_init(struct Curl_easy *easy)
|
|||
}
|
||||
|
||||
/* Initialize a mime part. */
|
||||
void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
|
||||
void Curl_mime_initpart(curl_mimepart *part)
|
||||
{
|
||||
memset((char *) part, 0, sizeof(*part));
|
||||
part->easy = easy;
|
||||
part->lastreadstatus = 1; /* Successful read status. */
|
||||
mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
|
||||
}
|
||||
|
@ -1321,7 +1320,7 @@ curl_mimepart *curl_mime_addpart(curl_mime *mime)
|
|||
part = (curl_mimepart *) malloc(sizeof(*part));
|
||||
|
||||
if(part) {
|
||||
Curl_mime_initpart(part, mime->easy);
|
||||
Curl_mime_initpart(part);
|
||||
part->parent = mime;
|
||||
|
||||
if(mime->lastpart)
|
||||
|
@ -1551,10 +1550,6 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part,
|
|||
cleanup_part_content(part);
|
||||
|
||||
if(subparts) {
|
||||
/* Must belong to the same data handle. */
|
||||
if(part->easy && subparts->easy && part->easy != subparts->easy)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
/* Should not have been attached already. */
|
||||
if(subparts->parent)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
@ -1565,8 +1560,7 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part,
|
|||
while(root->parent && root->parent->parent)
|
||||
root = root->parent->parent;
|
||||
if(subparts == root) {
|
||||
if(part->easy)
|
||||
failf(part->easy, "Can't add itself as a subpart");
|
||||
/* Can't add as a subpart of itself. */
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
@ -1766,7 +1760,8 @@ static bool content_type_match(const char *contenttype,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
|
||||
CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
|
||||
curl_mimepart *part,
|
||||
const char *contenttype,
|
||||
const char *disposition,
|
||||
enum mimestrategy strategy)
|
||||
|
@ -1835,12 +1830,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
|
|||
char *filename = NULL;
|
||||
|
||||
if(part->name) {
|
||||
name = escape_string(part->easy, part->name, strategy);
|
||||
name = escape_string(data, part->name, strategy);
|
||||
if(!name)
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(!ret && part->filename) {
|
||||
filename = escape_string(part->easy, part->filename, strategy);
|
||||
filename = escape_string(data, part->filename, strategy);
|
||||
if(!filename)
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -1897,7 +1892,8 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
|
|||
if(content_type_match(contenttype, STRCONST("multipart/form-data")))
|
||||
disposition = "form-data";
|
||||
for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
|
||||
ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
|
||||
ret = Curl_mime_prepare_headers(data, subpart, NULL,
|
||||
disposition, strategy);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
16
lib/mime.h
16
lib/mime.h
|
@ -99,7 +99,6 @@ struct mime_state {
|
|||
|
||||
/* A mime multipart. */
|
||||
struct curl_mime {
|
||||
struct Curl_easy *easy; /* The associated easy handle. */
|
||||
curl_mimepart *parent; /* Parent part. */
|
||||
curl_mimepart *firstpart; /* First part. */
|
||||
curl_mimepart *lastpart; /* Last part. */
|
||||
|
@ -109,7 +108,6 @@ struct curl_mime {
|
|||
|
||||
/* A mime part. */
|
||||
struct curl_mimepart {
|
||||
struct Curl_easy *easy; /* The associated easy handle. */
|
||||
curl_mime *parent; /* Parent mime structure. */
|
||||
curl_mimepart *nextpart; /* Forward linked list. */
|
||||
enum mimekind kind; /* The part kind. */
|
||||
|
@ -139,14 +137,16 @@ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
|
|||
!defined(CURL_DISABLE_IMAP))
|
||||
|
||||
/* Prototypes. */
|
||||
void Curl_mime_initpart(struct curl_mimepart *part, struct Curl_easy *easy);
|
||||
void Curl_mime_initpart(struct curl_mimepart *part);
|
||||
void Curl_mime_cleanpart(struct curl_mimepart *part);
|
||||
CURLcode Curl_mime_duppart(struct curl_mimepart *dst,
|
||||
CURLcode Curl_mime_duppart(struct Curl_easy *data,
|
||||
struct curl_mimepart *dst,
|
||||
const curl_mimepart *src);
|
||||
CURLcode Curl_mime_set_subparts(struct curl_mimepart *part,
|
||||
struct curl_mime *subparts,
|
||||
int take_ownership);
|
||||
CURLcode Curl_mime_prepare_headers(struct curl_mimepart *part,
|
||||
CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
|
||||
struct curl_mimepart *part,
|
||||
const char *contenttype,
|
||||
const char *disposition,
|
||||
enum mimestrategy strategy);
|
||||
|
@ -159,11 +159,11 @@ void Curl_mime_unpause(struct curl_mimepart *part);
|
|||
|
||||
#else
|
||||
/* if disabled */
|
||||
#define Curl_mime_initpart(x,y)
|
||||
#define Curl_mime_initpart(x)
|
||||
#define Curl_mime_cleanpart(x)
|
||||
#define Curl_mime_duppart(x,y) CURLE_OK /* Nothing to duplicate. Succeed */
|
||||
#define Curl_mime_duppart(x,y,z) CURLE_OK /* Nothing to duplicate. Succeed */
|
||||
#define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN
|
||||
#define Curl_mime_prepare_headers(a,b,c,d) CURLE_NOT_BUILT_IN
|
||||
#define Curl_mime_prepare_headers(a,b,c,d,e) CURLE_NOT_BUILT_IN
|
||||
#define Curl_mime_size(x) (curl_off_t) -1
|
||||
#define Curl_mime_read NULL
|
||||
#define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN)
|
||||
|
|
|
@ -697,7 +697,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
|||
|
||||
/* Add external headers and mime version. */
|
||||
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
|
||||
result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
|
||||
result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
|
||||
NULL, MIMESTRATEGY_MAIL);
|
||||
|
||||
if(!result)
|
||||
|
|
|
@ -560,7 +560,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
|
|||
/* make libcurl quiet by default: */
|
||||
set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
|
||||
|
||||
Curl_mime_initpart(&set->mimepost, data);
|
||||
Curl_mime_initpart(&set->mimepost);
|
||||
|
||||
/*
|
||||
* libcurl 7.10 introduced SSL verification *by default*! This needs to be
|
||||
|
|
Загрузка…
Ссылка в новой задаче