mime: add client reader
Add `mime` client reader. Encapsulates reading from mime parts, getting their length, rewinding and unpausing. - remove special mime handling from sendf.c and easy.c - add general "unpause" method to client readers - use new reader in http/imap/smtp - make some mime functions static that are now only used internally In addition: - remove flag 'forbidchunk' as no longer needed Closes #13039
This commit is contained in:
parent
6c632b216b
commit
0ba47146f7
@ -1110,9 +1110,10 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
|
|||||||
/* Unpause parts in active mime tree. */
|
/* Unpause parts in active mime tree. */
|
||||||
if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
|
if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
|
||||||
(data->mstate == MSTATE_PERFORMING ||
|
(data->mstate == MSTATE_PERFORMING ||
|
||||||
data->mstate == MSTATE_RATELIMITING) &&
|
data->mstate == MSTATE_RATELIMITING)) {
|
||||||
data->state.fread_func == (curl_read_callback) Curl_mime_read) {
|
result = Curl_creader_unpause(data);
|
||||||
Curl_mime_unpause(data->state.in);
|
if(result)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put it back in the keepon */
|
/* put it back in the keepon */
|
||||||
|
|||||||
66
lib/http.c
66
lib/http.c
@ -2030,47 +2030,41 @@ static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_MIME
|
|
||||||
if(data->state.mimepost) {
|
|
||||||
const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
|
|
||||||
|
|
||||||
/* Read and seek 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(data->state.mimepost->kind == MIMEKIND_MULTIPART)
|
|
||||||
cthdr = "multipart/form-data";
|
|
||||||
|
|
||||||
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(data->state.mimepost, NULL, 0);
|
|
||||||
if(!result)
|
|
||||||
result = Curl_mime_rewind(data->state.mimepost);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
postsize = Curl_mime_size(data->state.mimepost);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch(httpreq) {
|
switch(httpreq) {
|
||||||
case HTTPREQ_POST_FORM:
|
case HTTPREQ_POST_FORM:
|
||||||
case HTTPREQ_POST_MIME:
|
case HTTPREQ_POST_MIME:
|
||||||
/* This is form posting using mime data. */
|
/* This is form posting using mime data. */
|
||||||
data->state.infilesize = postsize;
|
#ifndef CURL_DISABLE_MIME
|
||||||
if(!postsize)
|
if(data->state.mimepost) {
|
||||||
result = Curl_creader_set_null(data);
|
const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
|
||||||
else {
|
|
||||||
/* Read from mime structure. We could do a special client reader
|
/* Read and seek body only. */
|
||||||
* for this, but replacing the callback seems to work fine. */
|
data->state.mimepost->flags |= MIME_BODY_ONLY;
|
||||||
data->state.fread_func = (curl_read_callback) Curl_mime_read;
|
|
||||||
data->state.in = (void *) data->state.mimepost;
|
/* Prepare the mime structure headers & set content type. */
|
||||||
result = Curl_creader_set_fread(data, postsize);
|
|
||||||
|
if(cthdr)
|
||||||
|
for(cthdr += 13; *cthdr == ' '; cthdr++)
|
||||||
|
;
|
||||||
|
else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
|
||||||
|
cthdr = "multipart/form-data";
|
||||||
|
|
||||||
|
curl_mime_headers(data->state.mimepost, data->set.headers, 0);
|
||||||
|
result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
|
||||||
|
NULL, MIMESTRATEGY_FORM);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
curl_mime_headers(data->state.mimepost, NULL, 0);
|
||||||
|
result = Curl_creader_set_mime(data, data->state.mimepost);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
result = Curl_creader_set_null(data);
|
||||||
|
}
|
||||||
|
data->state.infilesize = Curl_creader_total_length(data);
|
||||||
return result;
|
return result;
|
||||||
default:
|
default:
|
||||||
if(!postsize)
|
if(!postsize)
|
||||||
|
|||||||
@ -643,6 +643,7 @@ const struct Curl_crtype Curl_httpchunk_encoder = {
|
|||||||
cr_chunked_total_length,
|
cr_chunked_total_length,
|
||||||
Curl_creader_def_resume_from,
|
Curl_creader_def_resume_from,
|
||||||
Curl_creader_def_rewind,
|
Curl_creader_def_rewind,
|
||||||
|
Curl_creader_def_unpause,
|
||||||
sizeof(struct chunked_reader)
|
sizeof(struct chunked_reader)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
17
lib/imap.c
17
lib/imap.c
@ -786,20 +786,19 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
|
|||||||
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
|
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
|
||||||
"Mime-Version: 1.0");
|
"Mime-Version: 1.0");
|
||||||
|
|
||||||
/* Make sure we will read the entire mime structure. */
|
|
||||||
if(!result)
|
if(!result)
|
||||||
result = Curl_mime_rewind(&data->set.mimepost);
|
result = Curl_creader_set_mime(data, &data->set.mimepost);
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
data->state.infilesize = Curl_creader_client_length(data);
|
||||||
data->state.infilesize = Curl_mime_size(&data->set.mimepost);
|
|
||||||
|
|
||||||
/* Read from mime structure. */
|
|
||||||
data->state.fread_func = (curl_read_callback) Curl_mime_read;
|
|
||||||
data->state.in = (void *) &data->set.mimepost;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
result = Curl_creader_set_fread(data, data->state.infilesize);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check we know the size of the upload */
|
/* Check we know the size of the upload */
|
||||||
if(data->state.infilesize < 0) {
|
if(data->state.infilesize < 0) {
|
||||||
|
|||||||
226
lib/mime.c
226
lib/mime.c
@ -74,6 +74,7 @@ static curl_off_t encoder_base64_size(curl_mimepart *part);
|
|||||||
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
|
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
|
||||||
curl_mimepart *part);
|
curl_mimepart *part);
|
||||||
static curl_off_t encoder_qp_size(curl_mimepart *part);
|
static curl_off_t encoder_qp_size(curl_mimepart *part);
|
||||||
|
static curl_off_t mime_size(curl_mimepart *part);
|
||||||
|
|
||||||
static const struct mime_encoder encoders[] = {
|
static const struct mime_encoder encoders[] = {
|
||||||
{"binary", encoder_nop_read, encoder_nop_size},
|
{"binary", encoder_nop_read, encoder_nop_size},
|
||||||
@ -1602,7 +1603,7 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Rewind mime stream. */
|
/* Rewind mime stream. */
|
||||||
CURLcode Curl_mime_rewind(curl_mimepart *part)
|
static CURLcode mime_rewind(curl_mimepart *part)
|
||||||
{
|
{
|
||||||
return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
|
return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
|
||||||
CURLE_OK: CURLE_SEND_FAIL_REWIND;
|
CURLE_OK: CURLE_SEND_FAIL_REWIND;
|
||||||
@ -1634,7 +1635,7 @@ static curl_off_t multipart_size(curl_mime *mime)
|
|||||||
size = boundarysize; /* Final boundary - CRLF after headers. */
|
size = boundarysize; /* Final boundary - CRLF after headers. */
|
||||||
|
|
||||||
for(part = mime->firstpart; part; part = part->nextpart) {
|
for(part = mime->firstpart; part; part = part->nextpart) {
|
||||||
curl_off_t sz = Curl_mime_size(part);
|
curl_off_t sz = mime_size(part);
|
||||||
|
|
||||||
if(sz < 0)
|
if(sz < 0)
|
||||||
size = sz;
|
size = sz;
|
||||||
@ -1647,7 +1648,7 @@ static curl_off_t multipart_size(curl_mime *mime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get/compute mime size. */
|
/* Get/compute mime size. */
|
||||||
curl_off_t Curl_mime_size(curl_mimepart *part)
|
static curl_off_t mime_size(curl_mimepart *part)
|
||||||
{
|
{
|
||||||
curl_off_t size;
|
curl_off_t size;
|
||||||
|
|
||||||
@ -1896,7 +1897,7 @@ CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Recursively reset paused status in the given part. */
|
/* Recursively reset paused status in the given part. */
|
||||||
void Curl_mime_unpause(curl_mimepart *part)
|
static void mime_unpause(curl_mimepart *part)
|
||||||
{
|
{
|
||||||
if(part) {
|
if(part) {
|
||||||
if(part->lastreadstatus == CURL_READFUNC_PAUSE)
|
if(part->lastreadstatus == CURL_READFUNC_PAUSE)
|
||||||
@ -1908,12 +1909,227 @@ void Curl_mime_unpause(curl_mimepart *part)
|
|||||||
curl_mimepart *subpart;
|
curl_mimepart *subpart;
|
||||||
|
|
||||||
for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
|
for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
|
||||||
Curl_mime_unpause(subpart);
|
mime_unpause(subpart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cr_mime_ctx {
|
||||||
|
struct Curl_creader super;
|
||||||
|
curl_mimepart *part;
|
||||||
|
curl_off_t total_len;
|
||||||
|
curl_off_t read_len;
|
||||||
|
CURLcode error_result;
|
||||||
|
BIT(seen_eos);
|
||||||
|
BIT(errored);
|
||||||
|
};
|
||||||
|
|
||||||
|
static CURLcode cr_mime_init(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
(void)data;
|
||||||
|
ctx->total_len = -1;
|
||||||
|
ctx->read_len = 0;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Real client reader to installed client callbacks. */
|
||||||
|
static CURLcode cr_mime_read(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader,
|
||||||
|
char *buf, size_t blen,
|
||||||
|
size_t *pnread, bool *peos)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
size_t nread;
|
||||||
|
|
||||||
|
/* Once we have errored, we will return the same error forever */
|
||||||
|
if(ctx->errored) {
|
||||||
|
*pnread = 0;
|
||||||
|
*peos = FALSE;
|
||||||
|
return ctx->error_result;
|
||||||
|
}
|
||||||
|
if(ctx->seen_eos) {
|
||||||
|
*pnread = 0;
|
||||||
|
*peos = TRUE;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
/* respect length limitations */
|
||||||
|
if(ctx->total_len >= 0) {
|
||||||
|
curl_off_t remain = ctx->total_len - ctx->read_len;
|
||||||
|
if(remain <= 0)
|
||||||
|
blen = 0;
|
||||||
|
else if(remain < (curl_off_t)blen)
|
||||||
|
blen = (size_t)remain;
|
||||||
|
}
|
||||||
|
nread = 0;
|
||||||
|
if(blen) {
|
||||||
|
nread = Curl_mime_read(buf, 1, blen, ctx->part);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(nread) {
|
||||||
|
case 0:
|
||||||
|
if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
|
||||||
|
failf(data, "client mime read EOF fail, only "
|
||||||
|
"only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
|
||||||
|
" of needed bytes read", ctx->read_len, ctx->total_len);
|
||||||
|
return CURLE_READ_ERROR;
|
||||||
|
}
|
||||||
|
*pnread = 0;
|
||||||
|
*peos = TRUE;
|
||||||
|
ctx->seen_eos = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURL_READFUNC_ABORT:
|
||||||
|
failf(data, "operation aborted by callback");
|
||||||
|
*pnread = 0;
|
||||||
|
*peos = FALSE;
|
||||||
|
ctx->errored = TRUE;
|
||||||
|
ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
return CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
|
||||||
|
case CURL_READFUNC_PAUSE:
|
||||||
|
/* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
|
||||||
|
data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
|
||||||
|
*pnread = 0;
|
||||||
|
*peos = FALSE;
|
||||||
|
break; /* nothing was read */
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(nread > blen) {
|
||||||
|
/* the read function returned a too large value */
|
||||||
|
failf(data, "read function returned funny value");
|
||||||
|
*pnread = 0;
|
||||||
|
*peos = FALSE;
|
||||||
|
ctx->errored = TRUE;
|
||||||
|
ctx->error_result = CURLE_READ_ERROR;
|
||||||
|
return CURLE_READ_ERROR;
|
||||||
|
}
|
||||||
|
ctx->read_len += nread;
|
||||||
|
if(ctx->total_len >= 0)
|
||||||
|
ctx->seen_eos = (ctx->read_len >= ctx->total_len);
|
||||||
|
*pnread = nread;
|
||||||
|
*peos = ctx->seen_eos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DEBUGF(infof(data, "cr_mime_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
|
||||||
|
", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, %zu, %d",
|
||||||
|
blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos));
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cr_mime_needs_rewind(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
(void)data;
|
||||||
|
return ctx->read_len > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static curl_off_t cr_mime_total_length(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
(void)data;
|
||||||
|
return ctx->total_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode cr_mime_resume_from(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader,
|
||||||
|
curl_off_t offset)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
|
||||||
|
if(offset > 0) {
|
||||||
|
curl_off_t passed = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
char scratch[4*1024];
|
||||||
|
size_t readthisamountnow =
|
||||||
|
(offset - passed > (curl_off_t)sizeof(scratch)) ?
|
||||||
|
sizeof(scratch) :
|
||||||
|
curlx_sotouz(offset - passed);
|
||||||
|
size_t nread;
|
||||||
|
|
||||||
|
nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
|
||||||
|
passed += (curl_off_t)nread;
|
||||||
|
if((nread == 0) || (nread > readthisamountnow)) {
|
||||||
|
/* this checks for greater-than only to make sure that the
|
||||||
|
CURL_READFUNC_ABORT return code still aborts */
|
||||||
|
failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
|
||||||
|
" bytes from the mime post", passed);
|
||||||
|
return CURLE_READ_ERROR;
|
||||||
|
}
|
||||||
|
} while(passed < offset);
|
||||||
|
|
||||||
|
/* now, decrease the size of the read */
|
||||||
|
if(ctx->total_len > 0) {
|
||||||
|
ctx->total_len -= offset;
|
||||||
|
|
||||||
|
if(ctx->total_len <= 0) {
|
||||||
|
failf(data, "Mime post already completely uploaded");
|
||||||
|
return CURLE_PARTIAL_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* we've passed, proceed as normal */
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode cr_mime_rewind(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
CURLcode result = mime_rewind(ctx->part);
|
||||||
|
if(result)
|
||||||
|
failf(data, "Cannot rewind mime/post data");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode cr_mime_unpause(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader)
|
||||||
|
{
|
||||||
|
struct cr_mime_ctx *ctx = (struct cr_mime_ctx *)reader;
|
||||||
|
(void)data;
|
||||||
|
mime_unpause(ctx->part);
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct Curl_crtype cr_mime = {
|
||||||
|
"cr-mime",
|
||||||
|
cr_mime_init,
|
||||||
|
cr_mime_read,
|
||||||
|
Curl_creader_def_close,
|
||||||
|
cr_mime_needs_rewind,
|
||||||
|
cr_mime_total_length,
|
||||||
|
cr_mime_resume_from,
|
||||||
|
cr_mime_rewind,
|
||||||
|
cr_mime_unpause,
|
||||||
|
sizeof(struct cr_mime_ctx)
|
||||||
|
};
|
||||||
|
|
||||||
|
CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
|
||||||
|
{
|
||||||
|
struct Curl_creader *r;
|
||||||
|
struct cr_mime_ctx *ctx;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
ctx = (struct cr_mime_ctx *)r;
|
||||||
|
ctx->part = part;
|
||||||
|
/* Make sure we will read the entire mime structure. */
|
||||||
|
result = mime_rewind(ctx->part);
|
||||||
|
if(result) {
|
||||||
|
Curl_creader_free(data, r);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ctx->total_len = mime_size(ctx->part);
|
||||||
|
|
||||||
|
return Curl_creader_set(data, r);
|
||||||
|
}
|
||||||
|
|
||||||
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
|
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
|
||||||
!CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
|
!CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
|
||||||
|
|||||||
13
lib/mime.h
13
lib/mime.h
@ -151,12 +151,15 @@ CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
|
|||||||
const char *contenttype,
|
const char *contenttype,
|
||||||
const char *disposition,
|
const char *disposition,
|
||||||
enum mimestrategy strategy);
|
enum mimestrategy strategy);
|
||||||
curl_off_t Curl_mime_size(struct curl_mimepart *part);
|
|
||||||
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
|
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
|
||||||
void *instream);
|
void *instream);
|
||||||
CURLcode Curl_mime_rewind(struct curl_mimepart *part);
|
|
||||||
const char *Curl_mime_contenttype(const char *filename);
|
const char *Curl_mime_contenttype(const char *filename);
|
||||||
void Curl_mime_unpause(struct curl_mimepart *part);
|
|
||||||
|
/**
|
||||||
|
* Install a client reader as upload source that reads the given
|
||||||
|
* mime part.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* if disabled */
|
/* if disabled */
|
||||||
@ -165,10 +168,8 @@ void Curl_mime_unpause(struct curl_mimepart *part);
|
|||||||
#define Curl_mime_duppart(x,y,z) 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_set_subparts(a,b,c) CURLE_NOT_BUILT_IN
|
||||||
#define Curl_mime_prepare_headers(a,b,c,d,e) 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_read NULL
|
||||||
#define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN)
|
#define Curl_creader_set_mime(x,y) ((void)x, CURLE_NOT_BUILT_IN)
|
||||||
#define Curl_mime_unpause(x)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -139,7 +139,6 @@ void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data)
|
|||||||
req->ignore_cl = FALSE;
|
req->ignore_cl = FALSE;
|
||||||
req->upload_chunky = FALSE;
|
req->upload_chunky = FALSE;
|
||||||
req->getheader = FALSE;
|
req->getheader = FALSE;
|
||||||
req->forbidchunk = FALSE;
|
|
||||||
req->no_body = data->set.opt_no_body;
|
req->no_body = data->set.opt_no_body;
|
||||||
req->authneg = FALSE;
|
req->authneg = FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,9 +139,6 @@ struct SingleRequest {
|
|||||||
BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
|
BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
|
||||||
on upload */
|
on upload */
|
||||||
BIT(getheader); /* TRUE if header parsing is wanted */
|
BIT(getheader); /* TRUE if header parsing is wanted */
|
||||||
BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
|
|
||||||
specific upload buffers. See readmoredata() in http.c
|
|
||||||
for details. */
|
|
||||||
BIT(no_body); /* the response has no body */
|
BIT(no_body); /* the response has no body */
|
||||||
BIT(authneg); /* TRUE when the auth phase has started, which means
|
BIT(authneg); /* TRUE when the auth phase has started, which means
|
||||||
that we are creating a request with an auth header,
|
that we are creating a request with an auth header,
|
||||||
|
|||||||
@ -571,8 +571,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RTSP never allows chunked transfer */
|
|
||||||
data->req.forbidchunk = TRUE;
|
|
||||||
/* Finish the request buffer */
|
/* Finish the request buffer */
|
||||||
result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n"));
|
result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n"));
|
||||||
if(result)
|
if(result)
|
||||||
|
|||||||
124
lib/sendf.c
124
lib/sendf.c
@ -553,6 +553,14 @@ CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)reader;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct cr_in_ctx {
|
struct cr_in_ctx {
|
||||||
struct Curl_creader super;
|
struct Curl_creader super;
|
||||||
curl_read_callback read_cb;
|
curl_read_callback read_cb;
|
||||||
@ -753,37 +761,11 @@ static CURLcode cr_in_rewind(struct Curl_easy *data,
|
|||||||
struct Curl_creader *reader)
|
struct Curl_creader *reader)
|
||||||
{
|
{
|
||||||
struct cr_in_ctx *ctx = (struct cr_in_ctx *)reader;
|
struct cr_in_ctx *ctx = (struct cr_in_ctx *)reader;
|
||||||
/* TODO: I wonder if we should rather give mime its own client
|
|
||||||
* reader type. This is messy. */
|
|
||||||
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
|
|
||||||
curl_mimepart *mimepart = &data->set.mimepost;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* If we never invoked the callback, there is noting to rewind */
|
/* If we never invoked the callback, there is noting to rewind */
|
||||||
if(!ctx->has_used_cb)
|
if(!ctx->has_used_cb)
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
|
||||||
/* We have sent away data. If not using CURLOPT_POSTFIELDS or
|
|
||||||
CURLOPT_HTTPPOST, call app to rewind
|
|
||||||
*/
|
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
|
|
||||||
if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
|
|
||||||
if(data->state.mimepost)
|
|
||||||
mimepart = data->state.mimepost;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
|
|
||||||
if(ctx->read_cb == (curl_read_callback)Curl_mime_read) {
|
|
||||||
CURLcode result = Curl_mime_rewind(mimepart);
|
|
||||||
DEBUGF(infof(data, "cr_in, rewind mime/post data -> %d", result));
|
|
||||||
if(result) {
|
|
||||||
failf(data, "Cannot rewind mime/post data");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* With mime out of the way, handle "normal" fread callbacks */
|
|
||||||
if(data->set.seek_func) {
|
if(data->set.seek_func) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -839,6 +821,7 @@ static const struct Curl_crtype cr_in = {
|
|||||||
cr_in_total_length,
|
cr_in_total_length,
|
||||||
cr_in_resume_from,
|
cr_in_resume_from,
|
||||||
cr_in_rewind,
|
cr_in_rewind,
|
||||||
|
Curl_creader_def_unpause,
|
||||||
sizeof(struct cr_in_ctx)
|
sizeof(struct cr_in_ctx)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -985,6 +968,7 @@ static const struct Curl_crtype cr_lc = {
|
|||||||
cr_lc_total_length,
|
cr_lc_total_length,
|
||||||
Curl_creader_def_resume_from,
|
Curl_creader_def_resume_from,
|
||||||
Curl_creader_def_rewind,
|
Curl_creader_def_rewind,
|
||||||
|
Curl_creader_def_unpause,
|
||||||
sizeof(struct cr_lc_ctx)
|
sizeof(struct cr_lc_ctx)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1004,18 +988,18 @@ static CURLcode cr_lc_add(struct Curl_easy *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode do_init_reader_stack(struct Curl_easy *data,
|
static CURLcode do_init_reader_stack(struct Curl_easy *data,
|
||||||
const struct Curl_crtype *crt,
|
struct Curl_creader *r)
|
||||||
struct Curl_creader **preader,
|
|
||||||
curl_off_t clen)
|
|
||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result = CURLE_OK;
|
||||||
|
curl_off_t clen;
|
||||||
|
|
||||||
|
DEBUGASSERT(r);
|
||||||
|
DEBUGASSERT(r->crt);
|
||||||
|
DEBUGASSERT(r->phase == CURL_CR_CLIENT);
|
||||||
DEBUGASSERT(!data->req.reader_stack);
|
DEBUGASSERT(!data->req.reader_stack);
|
||||||
result = Curl_creader_create(preader, data, crt, CURL_CR_CLIENT);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
data->req.reader_stack = *preader;
|
|
||||||
|
|
||||||
|
data->req.reader_stack = r;
|
||||||
|
clen = r->crt->total_length(data, r);
|
||||||
/* if we do not have 0 length init, and crlf conversion is wanted,
|
/* if we do not have 0 length init, and crlf conversion is wanted,
|
||||||
* add the reader for it */
|
* add the reader for it */
|
||||||
if(clen && (data->set.crlf
|
if(clen && (data->set.crlf
|
||||||
@ -1035,15 +1019,16 @@ CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
|
|||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct Curl_creader *r;
|
struct Curl_creader *r;
|
||||||
|
struct cr_in_ctx *ctx;
|
||||||
|
|
||||||
|
result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
ctx = (struct cr_in_ctx *)r;
|
||||||
|
ctx->total_len = len;
|
||||||
|
|
||||||
cl_reset_reader(data);
|
cl_reset_reader(data);
|
||||||
result = do_init_reader_stack(data, &cr_in, &r, len);
|
return do_init_reader_stack(data, r);
|
||||||
if(!result && r) {
|
|
||||||
struct cr_in_ctx *ctx = (struct cr_in_ctx *)r;
|
|
||||||
DEBUGASSERT(r->crt == &cr_in);
|
|
||||||
ctx->total_len = len;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_creader_add(struct Curl_easy *data,
|
CURLcode Curl_creader_add(struct Curl_easy *data,
|
||||||
@ -1067,6 +1052,21 @@ CURLcode Curl_creader_add(struct Curl_easy *data,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
DEBUGASSERT(r);
|
||||||
|
DEBUGASSERT(r->crt);
|
||||||
|
DEBUGASSERT(r->phase == CURL_CR_CLIENT);
|
||||||
|
|
||||||
|
cl_reset_reader(data);
|
||||||
|
result = do_init_reader_stack(data, r);
|
||||||
|
if(result)
|
||||||
|
Curl_creader_free(data, r);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
|
CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
|
||||||
size_t *nread, bool *eos)
|
size_t *nread, bool *eos)
|
||||||
{
|
{
|
||||||
@ -1132,15 +1132,21 @@ static const struct Curl_crtype cr_null = {
|
|||||||
cr_null_total_length,
|
cr_null_total_length,
|
||||||
Curl_creader_def_resume_from,
|
Curl_creader_def_resume_from,
|
||||||
Curl_creader_def_rewind,
|
Curl_creader_def_rewind,
|
||||||
|
Curl_creader_def_unpause,
|
||||||
sizeof(struct Curl_creader)
|
sizeof(struct Curl_creader)
|
||||||
};
|
};
|
||||||
|
|
||||||
CURLcode Curl_creader_set_null(struct Curl_easy *data)
|
CURLcode Curl_creader_set_null(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
struct Curl_creader *r;
|
struct Curl_creader *r;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
result = Curl_creader_create(&r, data, &cr_null, CURL_CR_CLIENT);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
cl_reset_reader(data);
|
cl_reset_reader(data);
|
||||||
return do_init_reader_stack(data, &cr_null, &r, 0);
|
return do_init_reader_stack(data, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cr_buf_ctx {
|
struct cr_buf_ctx {
|
||||||
@ -1222,6 +1228,7 @@ static const struct Curl_crtype cr_buf = {
|
|||||||
cr_buf_total_length,
|
cr_buf_total_length,
|
||||||
cr_buf_resume_from,
|
cr_buf_resume_from,
|
||||||
Curl_creader_def_rewind,
|
Curl_creader_def_rewind,
|
||||||
|
Curl_creader_def_unpause,
|
||||||
sizeof(struct cr_buf_ctx)
|
sizeof(struct cr_buf_ctx)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1230,17 +1237,18 @@ CURLcode Curl_creader_set_buf(struct Curl_easy *data,
|
|||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct Curl_creader *r;
|
struct Curl_creader *r;
|
||||||
|
struct cr_buf_ctx *ctx;
|
||||||
|
|
||||||
|
result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
ctx = (struct cr_buf_ctx *)r;
|
||||||
|
ctx->buf = buf;
|
||||||
|
ctx->blen = blen;
|
||||||
|
ctx->index = 0;
|
||||||
|
|
||||||
cl_reset_reader(data);
|
cl_reset_reader(data);
|
||||||
result = do_init_reader_stack(data, &cr_buf, &r, blen);
|
return do_init_reader_stack(data, r);
|
||||||
if(!result && r) {
|
|
||||||
struct cr_buf_ctx *ctx = (struct cr_buf_ctx *)r;
|
|
||||||
DEBUGASSERT(r->crt == &cr_buf);
|
|
||||||
ctx->buf = buf;
|
|
||||||
ctx->blen = blen;
|
|
||||||
ctx->index = 0;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_off_t Curl_creader_total_length(struct Curl_easy *data)
|
curl_off_t Curl_creader_total_length(struct Curl_easy *data)
|
||||||
@ -1264,3 +1272,17 @@ CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
|
|||||||
r = r->next;
|
r = r->next;
|
||||||
return r? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
|
return r? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_creader_unpause(struct Curl_easy *data)
|
||||||
|
{
|
||||||
|
struct Curl_creader *reader = data->req.reader_stack;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
while(reader) {
|
||||||
|
result = reader->crt->unpause(data, reader);
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
reader = reader->next;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
17
lib/sendf.h
17
lib/sendf.h
@ -187,6 +187,7 @@ void Curl_cwriter_def_close(struct Curl_easy *data,
|
|||||||
struct Curl_cwriter *writer);
|
struct Curl_cwriter *writer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Client Reader Type, provides the implementation */
|
/* Client Reader Type, provides the implementation */
|
||||||
struct Curl_crtype {
|
struct Curl_crtype {
|
||||||
const char *name; /* writer name. */
|
const char *name; /* writer name. */
|
||||||
@ -200,6 +201,7 @@ struct Curl_crtype {
|
|||||||
CURLcode (*resume_from)(struct Curl_easy *data,
|
CURLcode (*resume_from)(struct Curl_easy *data,
|
||||||
struct Curl_creader *reader, curl_off_t offset);
|
struct Curl_creader *reader, curl_off_t offset);
|
||||||
CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
|
CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
|
||||||
|
CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader);
|
||||||
size_t creader_size; /* sizeof() allocated struct Curl_creader */
|
size_t creader_size; /* sizeof() allocated struct Curl_creader */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -236,6 +238,8 @@ CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
|
|||||||
curl_off_t offset);
|
curl_off_t offset);
|
||||||
CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
|
CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
|
||||||
struct Curl_creader *reader);
|
struct Curl_creader *reader);
|
||||||
|
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
|
||||||
|
struct Curl_creader *reader);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for calling `reader->do_read()` that
|
* Convenience method for calling `reader->do_read()` that
|
||||||
@ -268,6 +272,14 @@ void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader);
|
|||||||
CURLcode Curl_creader_add(struct Curl_easy *data,
|
CURLcode Curl_creader_add(struct Curl_easy *data,
|
||||||
struct Curl_creader *reader);
|
struct Curl_creader *reader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given reader, which needs to be of type CURL_CR_CLIENT,
|
||||||
|
* as the new first reader. Discard any installed readers and init
|
||||||
|
* the reader chain anew.
|
||||||
|
* The function takes ownership of `r`.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read at most `blen` bytes at `buf` from the client.
|
* Read at most `blen` bytes at `buf` from the client.
|
||||||
* @param date the transfer to read client bytes for
|
* @param date the transfer to read client bytes for
|
||||||
@ -328,6 +340,11 @@ curl_off_t Curl_creader_client_length(struct Curl_easy *data);
|
|||||||
*/
|
*/
|
||||||
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);
|
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpause all installed readers.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_creader_unpause(struct Curl_easy *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the client reader to provide 0 bytes, immediate EOS.
|
* Set the client reader to provide 0 bytes, immediate EOS.
|
||||||
*/
|
*/
|
||||||
|
|||||||
22
lib/smtp.c
22
lib/smtp.c
@ -705,20 +705,19 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
|||||||
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
|
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
|
||||||
"Mime-Version: 1.0");
|
"Mime-Version: 1.0");
|
||||||
|
|
||||||
/* Make sure we will read the entire mime structure. */
|
|
||||||
if(!result)
|
if(!result)
|
||||||
result = Curl_mime_rewind(&data->set.mimepost);
|
result = Curl_creader_set_mime(data, &data->set.mimepost);
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
data->state.infilesize = Curl_creader_total_length(data);
|
||||||
data->state.infilesize = Curl_mime_size(&data->set.mimepost);
|
|
||||||
|
|
||||||
/* Read from mime structure. */
|
|
||||||
data->state.fread_func = (curl_read_callback) Curl_mime_read;
|
|
||||||
data->state.in = (void *) &data->set.mimepost;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
result = Curl_creader_set_fread(data, data->state.infilesize);
|
||||||
|
if(result)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate the optional SIZE parameter */
|
/* Calculate the optional SIZE parameter */
|
||||||
if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
|
if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
|
||||||
@ -747,10 +746,6 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup client reader for size and EOB conversion */
|
|
||||||
result = Curl_creader_set_fread(data, data->state.infilesize);
|
|
||||||
if(result)
|
|
||||||
goto out;
|
|
||||||
/* Add the client reader doing STMP EOB escaping */
|
/* Add the client reader doing STMP EOB escaping */
|
||||||
result = cr_eob_add(data);
|
result = cr_eob_add(data);
|
||||||
if(result)
|
if(result)
|
||||||
@ -1927,6 +1922,7 @@ static const struct Curl_crtype cr_eob = {
|
|||||||
cr_eob_total_length,
|
cr_eob_total_length,
|
||||||
Curl_creader_def_resume_from,
|
Curl_creader_def_resume_from,
|
||||||
Curl_creader_def_rewind,
|
Curl_creader_def_rewind,
|
||||||
|
Curl_creader_def_unpause,
|
||||||
sizeof(struct cr_eob_ctx)
|
sizeof(struct cr_eob_ctx)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user