mirror of
https://github.com/curl/curl.git
synced 2025-04-12 16:20:35 +08:00
lib: further send/upload handling polish
- Move all the "upload_done" handling to request.c - add possibility to abort sending of a request - add `Curl_req_done_sending()` for checks - transfer.c: readwrite_upload() now clean - removing data->state.ulbuf and data->req.upload_fromhere - as well as data->req.upload_present - set data->req.upload_done on having read all from the client and completely flushed the send buffer - tftp, remove setting of data->req.upload_fromhere - serves no purpose as `upload_present` is not set and the data itself is directly `sendto()` anyway - smtp, make upload EOB conversion a client reader - xfer_ulbuf addition - add xfer_ulbuf for borrowing, similar to xfer_buf - use in file upload - use in c-hyper body sending - h1-proxy, remove init of data->state.uilbuf that is never used - smb, add own send_buf instead of using data->state.ulbuf Closes #13010
This commit is contained in:
parent
46aea3d990
commit
e3905de819
@ -469,7 +469,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
|
||||
infof(data, "Got 417 while waiting for a 100");
|
||||
data->state.disableexpect = TRUE;
|
||||
data->req.newurl = strdup(data->state.url);
|
||||
Curl_done_sending(data, k);
|
||||
Curl_req_abort_sending(data);
|
||||
}
|
||||
|
||||
result = status_line(data, conn,
|
||||
@ -663,7 +663,10 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
|
||||
size_t fillcount;
|
||||
struct Curl_easy *data = (struct Curl_easy *)userdata;
|
||||
CURLcode result;
|
||||
char *xfer_ulbuf;
|
||||
size_t xfer_ulblen;
|
||||
bool eos;
|
||||
int rc = HYPER_POLL_ERROR;
|
||||
(void)ctx;
|
||||
|
||||
if(data->req.exp100 > EXP100_SEND_DATA) {
|
||||
@ -677,39 +680,44 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
|
||||
return HYPER_POLL_PENDING;
|
||||
}
|
||||
|
||||
result = Curl_client_read(data, data->state.ulbuf,
|
||||
data->set.upload_buffer_size,
|
||||
&fillcount, &eos);
|
||||
if(result) {
|
||||
data->state.hresult = result;
|
||||
return HYPER_POLL_ERROR;
|
||||
}
|
||||
result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &fillcount, &eos);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
if(fillcount) {
|
||||
hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
|
||||
hyper_buf *copy = hyper_buf_copy((uint8_t *)xfer_ulbuf, fillcount);
|
||||
if(copy)
|
||||
*chunk = copy;
|
||||
else {
|
||||
data->state.hresult = CURLE_OUT_OF_MEMORY;
|
||||
return HYPER_POLL_ERROR;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
/* increasing the writebytecount here is a little premature but we
|
||||
don't know exactly when the body is sent */
|
||||
data->req.writebytecount += fillcount;
|
||||
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
|
||||
return HYPER_POLL_READY;
|
||||
rc = HYPER_POLL_READY;
|
||||
}
|
||||
else if(eos) {
|
||||
*chunk = NULL;
|
||||
return HYPER_POLL_READY;
|
||||
rc = HYPER_POLL_READY;
|
||||
}
|
||||
else {
|
||||
/* paused, save a waker */
|
||||
if(data->hyp.send_body_waker)
|
||||
hyper_waker_free(data->hyp.send_body_waker);
|
||||
data->hyp.send_body_waker = hyper_context_waker(ctx);
|
||||
return HYPER_POLL_PENDING;
|
||||
rc = HYPER_POLL_PENDING;
|
||||
}
|
||||
|
||||
out:
|
||||
Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
|
||||
data->state.hresult = result;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -722,7 +730,6 @@ static CURLcode bodysend(struct Curl_easy *data,
|
||||
hyper_request *hyperreq,
|
||||
Curl_HttpReq httpreq)
|
||||
{
|
||||
struct HTTP *http = data->req.p.http;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct dynbuf req;
|
||||
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
|
||||
@ -731,21 +738,21 @@ static CURLcode bodysend(struct Curl_easy *data,
|
||||
hyper_body *body;
|
||||
Curl_dyn_init(&req, DYN_HTTP_REQUEST);
|
||||
result = Curl_http_req_complete(data, &req, httpreq);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(!result)
|
||||
/* if the "complete" above did produce more than the closing line,
|
||||
parse the added headers */
|
||||
if(Curl_dyn_len(&req) != 2 || strcmp(Curl_dyn_ptr(&req), "\r\n")) {
|
||||
result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
Curl_dyn_free(&req);
|
||||
|
||||
body = hyper_body_new();
|
||||
hyper_body_set_userdata(body, data);
|
||||
result = Curl_get_upload_buffer(data);
|
||||
if(result) {
|
||||
hyper_body_free(body);
|
||||
return result;
|
||||
}
|
||||
/* init the "upload from here" pointer */
|
||||
data->req.upload_fromhere = data->state.ulbuf;
|
||||
hyper_body_set_data_func(body, uploadstreamed);
|
||||
|
||||
if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
|
||||
@ -753,7 +760,6 @@ static CURLcode bodysend(struct Curl_easy *data,
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
http->sending = HTTPSEND_BODY;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -114,18 +114,12 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
|
||||
struct h1_tunnel_state **pts)
|
||||
{
|
||||
struct h1_tunnel_state *ts;
|
||||
CURLcode result;
|
||||
|
||||
if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
|
||||
failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
/* we might need the upload buffer for streaming a partial request */
|
||||
result = Curl_get_upload_buffer(data);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
ts = calloc(1, sizeof(*ts));
|
||||
if(!ts)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
16
lib/file.c
16
lib/file.c
@ -291,8 +291,8 @@ static CURLcode file_upload(struct Curl_easy *data)
|
||||
int fd;
|
||||
int mode;
|
||||
CURLcode result = CURLE_OK;
|
||||
char *xfer_buf;
|
||||
size_t xfer_blen;
|
||||
char *xfer_ulbuf;
|
||||
size_t xfer_ulblen;
|
||||
curl_off_t bytecount = 0;
|
||||
struct_stat file_stat;
|
||||
const char *sendbuf;
|
||||
@ -340,7 +340,7 @@ static CURLcode file_upload(struct Curl_easy *data)
|
||||
data->state.resume_from = (curl_off_t)file_stat.st_size;
|
||||
}
|
||||
|
||||
result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
|
||||
result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
@ -349,7 +349,7 @@ static CURLcode file_upload(struct Curl_easy *data)
|
||||
ssize_t nwrite;
|
||||
size_t readcount;
|
||||
|
||||
result = Curl_client_read(data, xfer_buf, xfer_blen, &readcount, &eos);
|
||||
result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &readcount, &eos);
|
||||
if(result)
|
||||
break;
|
||||
|
||||
@ -363,16 +363,16 @@ static CURLcode file_upload(struct Curl_easy *data)
|
||||
if((curl_off_t)nread <= data->state.resume_from) {
|
||||
data->state.resume_from -= nread;
|
||||
nread = 0;
|
||||
sendbuf = xfer_buf;
|
||||
sendbuf = xfer_ulbuf;
|
||||
}
|
||||
else {
|
||||
sendbuf = xfer_buf + data->state.resume_from;
|
||||
sendbuf = xfer_ulbuf + data->state.resume_from;
|
||||
nread -= (size_t)data->state.resume_from;
|
||||
data->state.resume_from = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
sendbuf = xfer_buf;
|
||||
sendbuf = xfer_ulbuf;
|
||||
|
||||
/* write the data to the target */
|
||||
nwrite = write(fd, sendbuf, nread);
|
||||
@ -395,7 +395,7 @@ static CURLcode file_upload(struct Curl_easy *data)
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
Curl_multi_xfer_buf_release(data, xfer_buf);
|
||||
Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
58
lib/http.c
58
lib/http.c
@ -1283,7 +1283,6 @@ CURLcode Curl_http_done(struct Curl_easy *data,
|
||||
if(!http)
|
||||
return CURLE_OK;
|
||||
|
||||
Curl_dyn_free(&http->send_buffer);
|
||||
Curl_dyn_reset(&data->state.headerb);
|
||||
Curl_hyper_done(data);
|
||||
Curl_ws_done(data);
|
||||
@ -2151,6 +2150,12 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
|
||||
CURLcode result = CURLE_OK;
|
||||
struct HTTP *http = data->req.p.http;
|
||||
|
||||
if(data->req.upload_chunky) {
|
||||
result = Curl_httpchunk_add_reader(data);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
DEBUGASSERT(data->conn);
|
||||
switch(httpreq) {
|
||||
case HTTPREQ_PUT: /* Let's PUT the data to the server! */
|
||||
@ -2252,7 +2257,6 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
|
||||
data->state.in = (void *) data->state.mimepost;
|
||||
result = Client_reader_set_fread(data, data->state.infilesize);
|
||||
}
|
||||
http->sending = HTTPSEND_BODY;
|
||||
break;
|
||||
#endif
|
||||
case HTTPREQ_POST:
|
||||
@ -2294,19 +2298,21 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
|
||||
goto out;
|
||||
|
||||
if(!http->postsize) {
|
||||
Curl_pgrsSetUploadSize(data, -1);
|
||||
Curl_pgrsSetUploadSize(data, 0);
|
||||
result = Client_reader_set_null(data);
|
||||
}
|
||||
else if(data->set.postfields) { /* we have the bytes */
|
||||
else if(data->set.postfields) {
|
||||
Curl_pgrsSetUploadSize(data, http->postsize);
|
||||
result = Client_reader_set_buf(data, data->set.postfields,
|
||||
(size_t)http->postsize);
|
||||
if(http->postsize > 0)
|
||||
result = Client_reader_set_buf(data, data->set.postfields,
|
||||
(size_t)http->postsize);
|
||||
else
|
||||
result = Client_reader_set_null(data);
|
||||
}
|
||||
else { /* we read the bytes from the callback */
|
||||
Curl_pgrsSetUploadSize(data, http->postsize);
|
||||
result = Client_reader_set_fread(data, http->postsize);
|
||||
}
|
||||
http->sending = HTTPSEND_BODY;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2647,7 +2653,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct HTTP *http;
|
||||
Curl_HttpReq httpreq;
|
||||
const char *te = ""; /* transfer-encoding */
|
||||
const char *request;
|
||||
@ -2699,9 +2704,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
||||
if(result)
|
||||
goto fail;
|
||||
|
||||
http = data->req.p.http;
|
||||
DEBUGASSERT(http);
|
||||
|
||||
result = Curl_http_host(data, conn);
|
||||
if(result)
|
||||
goto fail;
|
||||
@ -2880,7 +2882,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
||||
result = Curl_add_custom_headers(data, FALSE, &req);
|
||||
|
||||
if(!result) {
|
||||
http->postdata = NULL; /* nothing to post at this point */
|
||||
if((httpreq == HTTPREQ_GET) ||
|
||||
(httpreq == HTTPREQ_HEAD))
|
||||
Curl_pgrsSetUploadSize(data, 0); /* nothing */
|
||||
@ -2896,29 +2897,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
||||
if(result)
|
||||
goto fail;
|
||||
|
||||
if(data->req.writebytecount) {
|
||||
/* if a request-body has been sent off, we make sure this progress is noted
|
||||
properly */
|
||||
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
|
||||
if(Curl_pgrsUpdate(data))
|
||||
result = CURLE_ABORTED_BY_CALLBACK;
|
||||
|
||||
if(!http->postsize) {
|
||||
/* already sent the entire request body, mark the "upload" as
|
||||
complete */
|
||||
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
|
||||
" out of %" CURL_FORMAT_CURL_OFF_T " bytes",
|
||||
data->req.writebytecount, http->postsize);
|
||||
data->req.upload_done = TRUE;
|
||||
data->req.keepon &= ~KEEP_SEND; /* we're done writing */
|
||||
data->req.exp100 = EXP100_SEND_DATA; /* already sent */
|
||||
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if(data->req.upload_done)
|
||||
Curl_conn_ev_data_done_send(data);
|
||||
|
||||
if((conn->httpversion >= 20) && data->req.upload_chunky)
|
||||
/* upload_chunky was set above to set up the request in a chunky fashion,
|
||||
but is disabled here again to avoid that the chunked encoded version is
|
||||
@ -3782,7 +3760,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
||||
* connection for closure after we've read the entire response.
|
||||
*/
|
||||
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
||||
if(!k->upload_done) {
|
||||
if(!Curl_req_done_sending(data)) {
|
||||
if((k->httpcode == 417) && data->state.expect100header) {
|
||||
/* 417 Expectation Failed - try again without the Expect
|
||||
header */
|
||||
@ -3801,7 +3779,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
||||
data->state.disableexpect = TRUE;
|
||||
DEBUGASSERT(!data->req.newurl);
|
||||
data->req.newurl = strdup(data->state.url);
|
||||
Curl_done_sending(data, k);
|
||||
Curl_req_abort_sending(data);
|
||||
}
|
||||
else if(data->set.http_keep_sending_on_error) {
|
||||
infof(data, "HTTP error before end of send, keep sending");
|
||||
@ -3813,10 +3791,9 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
||||
else {
|
||||
infof(data, "HTTP error before end of send, stop sending");
|
||||
streamclose(conn, "Stop sending data before everything sent");
|
||||
result = Curl_done_sending(data, k);
|
||||
result = Curl_req_abort_sending(data);
|
||||
if(result)
|
||||
return result;
|
||||
k->upload_done = TRUE;
|
||||
if(data->state.expect100header)
|
||||
k->exp100 = EXP100_FAILED;
|
||||
}
|
||||
@ -3828,8 +3805,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
||||
}
|
||||
}
|
||||
|
||||
if(data->state.rewindbeforesend &&
|
||||
(conn->writesockfd != CURL_SOCKET_BAD)) {
|
||||
if(data->state.rewindbeforesend && !Curl_req_done_sending(data)) {
|
||||
/* We rewind before next send, continue sending now */
|
||||
infof(data, "Keep sending data to get tossed away");
|
||||
k->keepon |= KEEP_SEND;
|
||||
|
17
lib/http.h
17
lib/http.h
@ -189,27 +189,10 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
|
||||
***************************************************************************/
|
||||
struct HTTP {
|
||||
curl_off_t postsize; /* off_t to handle large file sizes */
|
||||
const char *postdata;
|
||||
struct back {
|
||||
curl_read_callback fread_func; /* backup storage for fread pointer */
|
||||
void *fread_in; /* backup storage for fread_in pointer */
|
||||
const char *postdata;
|
||||
curl_off_t postsize;
|
||||
struct Curl_easy *data;
|
||||
} backup;
|
||||
|
||||
enum {
|
||||
HTTPSEND_NADA, /* init */
|
||||
HTTPSEND_REQUEST, /* sending a request */
|
||||
HTTPSEND_BODY /* sending body */
|
||||
} sending;
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
void *h2_ctx; /* HTTP/2 implementation context */
|
||||
void *h3_ctx; /* HTTP/3 implementation context */
|
||||
struct dynbuf send_buffer; /* used if the request couldn't be sent in one
|
||||
chunk, points to an allocated send_buffer
|
||||
struct */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
66
lib/multi.c
66
lib/multi.c
@ -94,7 +94,7 @@ static CURLMcode add_next_timeout(struct curltime now,
|
||||
static CURLMcode multi_timeout(struct Curl_multi *multi,
|
||||
long *timeout_ms);
|
||||
static void process_pending_handles(struct Curl_multi *multi);
|
||||
static void multi_xfer_buf_free(struct Curl_multi *multi);
|
||||
static void multi_xfer_bufs_free(struct Curl_multi *multi);
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static const char * const multi_statename[]={
|
||||
@ -192,7 +192,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
|
||||
data->multi->num_alive--;
|
||||
if(!data->multi->num_alive) {
|
||||
/* free the transfer buffer when we have no more active transfers */
|
||||
multi_xfer_buf_free(data->multi);
|
||||
multi_xfer_bufs_free(data->multi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -716,8 +716,6 @@ static CURLcode multi_done(struct Curl_easy *data,
|
||||
if(!result)
|
||||
result = Curl_req_done(&data->req, data, premature);
|
||||
|
||||
Curl_safefree(data->state.ulbuf);
|
||||
|
||||
CONNCACHE_LOCK(data);
|
||||
Curl_detach_connection(data);
|
||||
if(CONN_INUSE(conn)) {
|
||||
@ -2900,7 +2898,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
||||
Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
|
||||
#endif
|
||||
|
||||
multi_xfer_buf_free(multi);
|
||||
multi_xfer_bufs_free(multi);
|
||||
free(multi);
|
||||
|
||||
return CURLM_OK;
|
||||
@ -3891,10 +3889,66 @@ void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
|
||||
data->multi->xfer_buf_borrowed = FALSE;
|
||||
}
|
||||
|
||||
static void multi_xfer_buf_free(struct Curl_multi *multi)
|
||||
CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
|
||||
char **pbuf, size_t *pbuflen)
|
||||
{
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->multi);
|
||||
*pbuf = NULL;
|
||||
*pbuflen = 0;
|
||||
if(!data->multi) {
|
||||
failf(data, "transfer has no multi handle");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
if(!data->set.upload_buffer_size) {
|
||||
failf(data, "transfer upload buffer size is 0");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
if(data->multi->xfer_ulbuf_borrowed) {
|
||||
failf(data, "attempt to borrow xfer_ulbuf when already borrowed");
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
|
||||
if(data->multi->xfer_ulbuf &&
|
||||
data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
|
||||
/* not large enough, get a new one */
|
||||
free(data->multi->xfer_ulbuf);
|
||||
data->multi->xfer_ulbuf = NULL;
|
||||
data->multi->xfer_ulbuf_len = 0;
|
||||
}
|
||||
|
||||
if(!data->multi->xfer_ulbuf) {
|
||||
data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
|
||||
if(!data->multi->xfer_ulbuf) {
|
||||
failf(data, "could not allocate xfer_ulbuf of %zu bytes",
|
||||
(size_t)data->set.upload_buffer_size);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
|
||||
}
|
||||
|
||||
data->multi->xfer_ulbuf_borrowed = TRUE;
|
||||
*pbuf = data->multi->xfer_ulbuf;
|
||||
*pbuflen = data->multi->xfer_ulbuf_len;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf)
|
||||
{
|
||||
(void)buf;
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->multi);
|
||||
DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
|
||||
data->multi->xfer_ulbuf_borrowed = FALSE;
|
||||
}
|
||||
|
||||
static void multi_xfer_bufs_free(struct Curl_multi *multi)
|
||||
{
|
||||
DEBUGASSERT(multi);
|
||||
Curl_safefree(multi->xfer_buf);
|
||||
multi->xfer_buf_len = 0;
|
||||
multi->xfer_buf_borrowed = FALSE;
|
||||
Curl_safefree(multi->xfer_ulbuf);
|
||||
multi->xfer_ulbuf_len = 0;
|
||||
multi->xfer_ulbuf_borrowed = FALSE;
|
||||
}
|
||||
|
@ -127,6 +127,9 @@ struct Curl_multi {
|
||||
/* buffer used for transfer data, lazy initialized */
|
||||
char *xfer_buf; /* the actual buffer */
|
||||
size_t xfer_buf_len; /* the allocated length */
|
||||
/* buffer used for upload data, lazy initialized */
|
||||
char *xfer_ulbuf; /* the actual buffer */
|
||||
size_t xfer_ulbuf_len; /* the allocated length */
|
||||
|
||||
#if defined(USE_SSL)
|
||||
struct multi_ssl_backend_data *ssl_backend_data;
|
||||
@ -176,6 +179,7 @@ struct Curl_multi {
|
||||
BIT(dead); /* a callback returned error, everything needs to crash and
|
||||
burn */
|
||||
BIT(xfer_buf_borrowed); /* xfer_buf is currently being borrowed */
|
||||
BIT(xfer_ulbuf_borrowed); /* xfer_buf is currently being borrowed */
|
||||
#ifdef DEBUGBUILD
|
||||
BIT(warned); /* true after user warned of DEBUGBUILD */
|
||||
#endif
|
||||
|
@ -118,4 +118,29 @@ CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
|
||||
*/
|
||||
void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf);
|
||||
|
||||
/**
|
||||
* Borrow the upload buffer from the multi, suitable
|
||||
* for the given transfer `data`. The buffer may only be used in one
|
||||
* multi processing of the easy handle. It MUST be returned to the
|
||||
* multi before it can be borrowed again.
|
||||
* Pointers into the buffer remain only valid as long as it is borrowed.
|
||||
*
|
||||
* @param data the easy handle
|
||||
* @param pbuf on return, the buffer to use or NULL on error
|
||||
* @param pbuflen on return, the size of *pbuf or 0 on error
|
||||
* @return CURLE_OK when buffer is available and is returned.
|
||||
* CURLE_OUT_OF_MEMORy on failure to allocate the buffer,
|
||||
* CURLE_FAILED_INIT if the easy handle is without multi.
|
||||
* CURLE_AGAIN if the buffer is borrowed already.
|
||||
*/
|
||||
CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
|
||||
char **pbuf, size_t *pbuflen);
|
||||
|
||||
/**
|
||||
* Release the borrowed upload buffer. All references into the buffer become
|
||||
* invalid after this.
|
||||
* @param buf the upload buffer pointer borrowed for coding error checks.
|
||||
*/
|
||||
void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf);
|
||||
|
||||
#endif /* HEADER_CURL_MULTIIF_H */
|
||||
|
130
lib/request.c
130
lib/request.c
@ -25,6 +25,7 @@
|
||||
#include "curl_setup.h"
|
||||
|
||||
#include "urldata.h"
|
||||
#include "cfilters.h"
|
||||
#include "dynbuf.h"
|
||||
#include "doh.h"
|
||||
#include "multiif.h"
|
||||
@ -67,12 +68,14 @@ CURLcode Curl_req_start(struct SingleRequest *req,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode req_flush(struct Curl_easy *data);
|
||||
|
||||
CURLcode Curl_req_done(struct SingleRequest *req,
|
||||
struct Curl_easy *data, bool aborted)
|
||||
{
|
||||
(void)req;
|
||||
if(!aborted)
|
||||
(void)Curl_req_flush(data);
|
||||
(void)req_flush(data);
|
||||
Curl_client_reset(data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
@ -129,9 +132,9 @@ void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
static CURLcode req_send(struct Curl_easy *data,
|
||||
const char *buf, size_t blen,
|
||||
size_t hds_len, size_t *pnwritten)
|
||||
static CURLcode xfer_send(struct Curl_easy *data,
|
||||
const char *buf, size_t blen,
|
||||
size_t hds_len, size_t *pnwritten)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@ -180,7 +183,7 @@ static CURLcode req_send_buffer_flush(struct Curl_easy *data)
|
||||
|
||||
while(Curl_bufq_peek(&data->req.sendbuf, &buf, &blen)) {
|
||||
size_t nwritten, hds_len = CURLMIN(data->req.sendbuf_hds_len, blen);
|
||||
result = req_send(data, (const char *)buf, blen, hds_len, &nwritten);
|
||||
result = xfer_send(data, (const char *)buf, blen, hds_len, &nwritten);
|
||||
if(result)
|
||||
break;
|
||||
|
||||
@ -206,7 +209,33 @@ static CURLcode req_send_buffer_flush(struct Curl_easy *data)
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_req_flush(struct Curl_easy *data)
|
||||
static CURLcode req_set_upload_done(struct Curl_easy *data)
|
||||
{
|
||||
DEBUGASSERT(!data->req.upload_done);
|
||||
data->req.upload_done = TRUE;
|
||||
data->req.keepon &= ~KEEP_SEND; /* we're done sending */
|
||||
|
||||
/* FIXME: http specific stuff, need to go somewhere else */
|
||||
data->req.exp100 = EXP100_SEND_DATA;
|
||||
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
||||
|
||||
if(data->req.upload_aborted) {
|
||||
if(data->req.writebytecount)
|
||||
infof(data, "abort upload after having sent %" CURL_FORMAT_CURL_OFF_T
|
||||
" bytes", data->req.writebytecount);
|
||||
else
|
||||
infof(data, "abort upload");
|
||||
}
|
||||
else if(data->req.writebytecount)
|
||||
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
|
||||
" bytes", data->req.writebytecount);
|
||||
else
|
||||
infof(data, "We are completely uploaded and fine");
|
||||
|
||||
return Curl_xfer_send_close(data);
|
||||
}
|
||||
|
||||
static CURLcode req_flush(struct Curl_easy *data)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
@ -221,9 +250,30 @@ CURLcode Curl_req_flush(struct Curl_easy *data)
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if(!data->req.upload_done && data->req.eos_read &&
|
||||
Curl_bufq_is_empty(&data->req.sendbuf)) {
|
||||
return req_set_upload_done(data);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static ssize_t add_from_client(void *reader_ctx,
|
||||
unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct Curl_easy *data = reader_ctx;
|
||||
size_t nread;
|
||||
bool eos;
|
||||
|
||||
*err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
|
||||
if(*err)
|
||||
return -1;
|
||||
if(eos)
|
||||
data->req.eos_read = TRUE;
|
||||
return (ssize_t)nread;
|
||||
}
|
||||
|
||||
#ifndef USE_HYPER
|
||||
|
||||
static CURLcode req_send_buffer_add(struct Curl_easy *data,
|
||||
@ -242,22 +292,6 @@ static CURLcode req_send_buffer_add(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static ssize_t add_from_client(void *reader_ctx,
|
||||
unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct Curl_easy *data = reader_ctx;
|
||||
size_t nread;
|
||||
bool eos;
|
||||
|
||||
*err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
|
||||
if(*err)
|
||||
return -1;
|
||||
if(eos)
|
||||
data->req.eos_read = TRUE;
|
||||
return (ssize_t)nread;
|
||||
}
|
||||
|
||||
CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf)
|
||||
{
|
||||
CURLcode result;
|
||||
@ -275,18 +309,7 @@ CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf)
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if((data->req.exp100 == EXP100_SEND_DATA) &&
|
||||
!Curl_bufq_is_full(&data->req.sendbuf)) {
|
||||
ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
|
||||
add_from_client, data, &result);
|
||||
if(nread < 0 && result != CURLE_AGAIN)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = req_send_buffer_flush(data);
|
||||
if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
return result;
|
||||
return Curl_req_send_more(data);
|
||||
}
|
||||
#endif /* !USE_HYPER */
|
||||
|
||||
@ -294,3 +317,42 @@ bool Curl_req_want_send(struct Curl_easy *data)
|
||||
{
|
||||
return data->req.sendbuf_init && !Curl_bufq_is_empty(&data->req.sendbuf);
|
||||
}
|
||||
|
||||
bool Curl_req_done_sending(struct Curl_easy *data)
|
||||
{
|
||||
if(data->req.upload_done) {
|
||||
DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CURLcode Curl_req_send_more(struct Curl_easy *data)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
/* Fill our send buffer if more from client can be read and
|
||||
* we are not in a "expect-100" situation. */
|
||||
if(!data->req.eos_read && !Curl_bufq_is_full(&data->req.sendbuf) &&
|
||||
(data->req.exp100 == EXP100_SEND_DATA)) {
|
||||
ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
|
||||
add_from_client, data, &result);
|
||||
if(nread < 0 && result != CURLE_AGAIN)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = req_flush(data);
|
||||
if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_req_abort_sending(struct Curl_easy *data)
|
||||
{
|
||||
if(!data->req.upload_done) {
|
||||
Curl_bufq_reset(&data->req.sendbuf);
|
||||
data->req.upload_aborted = TRUE;
|
||||
return req_set_upload_done(data);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
@ -100,16 +100,6 @@ struct SingleRequest {
|
||||
char *newurl; /* Set to the new URL to use when a redirect or a retry is
|
||||
wanted */
|
||||
|
||||
/* 'upload_present' is used to keep a byte counter of how much data there is
|
||||
still left in the buffer, aimed for upload. */
|
||||
size_t upload_present;
|
||||
|
||||
/* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
|
||||
buffer, so the next read should read from where this pointer points to,
|
||||
and the 'upload_present' contains the number of bytes available at this
|
||||
position */
|
||||
char *upload_fromhere;
|
||||
|
||||
/* Allocated protocol-specific data. Each protocol handler makes sure this
|
||||
points to data it needs. */
|
||||
union {
|
||||
@ -139,8 +129,9 @@ struct SingleRequest {
|
||||
BIT(download_done); /* set to TRUE when download is complete */
|
||||
BIT(eos_written); /* iff EOS has been written to client */
|
||||
BIT(eos_read); /* iff EOS has been read from the client */
|
||||
BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
|
||||
upload and we're uploading the last chunk */
|
||||
BIT(upload_done); /* set to TRUE when all request data has been sent */
|
||||
BIT(upload_aborted); /* set to TRUE when upload was aborted. Will also
|
||||
* show `upload_done` as TRUE. */
|
||||
BIT(ignorebody); /* we read a response-body but we ignore it! */
|
||||
BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
|
||||
204 or 304 */
|
||||
@ -206,15 +197,26 @@ CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf);
|
||||
#endif /* !USE_HYPER */
|
||||
|
||||
/**
|
||||
* Flush all buffered request bytes.
|
||||
* @return CURLE_OK on success, CURLE_AGAIN if sending was blocked,
|
||||
* or the error on the sending.
|
||||
* TRUE iff the request has sent all request headers and data.
|
||||
*/
|
||||
CURLcode Curl_req_flush(struct Curl_easy *data);
|
||||
bool Curl_req_done_sending(struct Curl_easy *data);
|
||||
|
||||
/*
|
||||
* Read more from client and flush all buffered request bytes.
|
||||
* @return CURLE_OK on success or the error on the sending.
|
||||
* Never returns CURLE_AGAIN.
|
||||
*/
|
||||
CURLcode Curl_req_send_more(struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* TRUE iff the request wants to send, e.g. has buffered bytes.
|
||||
*/
|
||||
bool Curl_req_want_send(struct Curl_easy *data);
|
||||
|
||||
/**
|
||||
* Stop sending any more request data to the server.
|
||||
* Will clear the send buffer and mark request sending as done.
|
||||
*/
|
||||
CURLcode Curl_req_abort_sending(struct Curl_easy *data);
|
||||
|
||||
#endif /* HEADER_CURL_REQUEST_H */
|
||||
|
@ -577,6 +577,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
|
||||
|
||||
/* issue the request */
|
||||
result = Curl_req_send(data, &req_buffer);
|
||||
if(result) {
|
||||
@ -584,8 +586,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
|
||||
goto out;
|
||||
}
|
||||
|
||||
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
|
||||
|
||||
/* Increment the CSeq on success */
|
||||
data->state.rtsp_next_client_CSeq++;
|
||||
|
||||
|
@ -576,8 +576,10 @@ static CURLcode cr_in_read(struct Curl_easy *data,
|
||||
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 = FALSE;
|
||||
*peos = ctx->seen_eos;
|
||||
break;
|
||||
}
|
||||
DEBUGF(infof(data, "cr_in_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
|
||||
@ -743,7 +745,7 @@ static CURLcode cr_lc_add(struct Curl_easy *data)
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_creader_create(&reader, data, &cr_lc,
|
||||
CURL_CR_TRANSFER_ENCODE);
|
||||
CURL_CR_CONTENT_ENCODE);
|
||||
if(!result)
|
||||
result = Curl_creader_add(data, reader);
|
||||
|
||||
|
@ -2239,7 +2239,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
||||
arg = UPLOADBUFFER_MIN;
|
||||
|
||||
data->set.upload_buffer_size = (unsigned int)arg;
|
||||
Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
|
||||
break;
|
||||
|
||||
case CURLOPT_NOSIGNAL:
|
||||
|
33
lib/smb.c
33
lib/smb.c
@ -456,6 +456,9 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
|
||||
smbc->recv_buf = malloc(MAX_MESSAGE_SIZE);
|
||||
if(!smbc->recv_buf)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
smbc->send_buf = malloc(MAX_MESSAGE_SIZE);
|
||||
if(!smbc->send_buf)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Multiple requests are allowed with this connection */
|
||||
connkeep(conn, "SMB default");
|
||||
@ -567,7 +570,7 @@ static CURLcode smb_send(struct Curl_easy *data, size_t len,
|
||||
size_t bytes_written;
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_xfer_send(data, data->state.ulbuf, len, &bytes_written);
|
||||
result = Curl_xfer_send(data, smbc->send_buf, len, &bytes_written);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@ -592,7 +595,7 @@ static CURLcode smb_flush(struct Curl_easy *data)
|
||||
if(!smbc->send_size)
|
||||
return CURLE_OK;
|
||||
|
||||
result = Curl_xfer_send(data, data->state.ulbuf + smbc->sent, len,
|
||||
result = Curl_xfer_send(data, smbc->send_buf + smbc->sent, len,
|
||||
&bytes_written);
|
||||
if(result)
|
||||
return result;
|
||||
@ -608,13 +611,13 @@ static CURLcode smb_flush(struct Curl_easy *data)
|
||||
static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd,
|
||||
const void *msg, size_t msg_len)
|
||||
{
|
||||
CURLcode result = Curl_get_upload_buffer(data);
|
||||
if(result)
|
||||
return result;
|
||||
smb_format_message(data, (struct smb_header *)data->state.ulbuf,
|
||||
struct connectdata *conn = data->conn;
|
||||
struct smb_conn *smbc = &conn->proto.smbc;
|
||||
|
||||
smb_format_message(data, (struct smb_header *)smbc->send_buf,
|
||||
cmd, msg_len);
|
||||
memcpy(data->state.ulbuf + sizeof(struct smb_header),
|
||||
msg, msg_len);
|
||||
DEBUGASSERT((sizeof(struct smb_header) + msg_len) <= MAX_MESSAGE_SIZE);
|
||||
memcpy(smbc->send_buf + sizeof(struct smb_header), msg, msg_len);
|
||||
|
||||
return smb_send(data, sizeof(struct smb_header) + msg_len, 0);
|
||||
}
|
||||
@ -772,15 +775,14 @@ static CURLcode smb_send_read(struct Curl_easy *data)
|
||||
|
||||
static CURLcode smb_send_write(struct Curl_easy *data)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
struct smb_conn *smbc = &conn->proto.smbc;
|
||||
struct smb_write *msg;
|
||||
struct smb_request *req = data->req.p.smb;
|
||||
curl_off_t offset = data->req.offset;
|
||||
curl_off_t upload_size = data->req.size - data->req.bytecount;
|
||||
CURLcode result = Curl_get_upload_buffer(data);
|
||||
if(result)
|
||||
return result;
|
||||
msg = (struct smb_write *)data->state.ulbuf;
|
||||
|
||||
msg = (struct smb_write *)smbc->send_buf;
|
||||
if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
|
||||
upload_size = MAX_PAYLOAD_SIZE - 1;
|
||||
|
||||
@ -809,11 +811,11 @@ static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
|
||||
|
||||
/* Check if there is data in the transfer buffer */
|
||||
if(!smbc->send_size && smbc->upload_size) {
|
||||
size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ?
|
||||
(size_t)data->set.upload_buffer_size : smbc->upload_size;
|
||||
size_t nread = smbc->upload_size > (size_t)MAX_MESSAGE_SIZE ?
|
||||
(size_t)MAX_MESSAGE_SIZE : smbc->upload_size;
|
||||
bool eos;
|
||||
|
||||
result = Curl_client_read(data, data->state.ulbuf, nread, &nread, &eos);
|
||||
result = Curl_client_read(data, smbc->send_buf, nread, &nread, &eos);
|
||||
if(result && result != CURLE_AGAIN)
|
||||
return result;
|
||||
if(!nread)
|
||||
@ -1131,6 +1133,7 @@ static CURLcode smb_disconnect(struct Curl_easy *data,
|
||||
Curl_safefree(smbc->share);
|
||||
Curl_safefree(smbc->domain);
|
||||
Curl_safefree(smbc->recv_buf);
|
||||
Curl_safefree(smbc->send_buf);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ struct smb_conn {
|
||||
unsigned int session_key;
|
||||
unsigned short uid;
|
||||
char *recv_buf;
|
||||
char *send_buf;
|
||||
size_t upload_size;
|
||||
size_t send_size;
|
||||
size_t sent;
|
||||
|
340
lib/smtp.c
340
lib/smtp.c
@ -111,6 +111,7 @@ static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *resp);
|
||||
static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
|
||||
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
|
||||
static CURLcode cr_eob_add(struct Curl_easy *data);
|
||||
|
||||
/*
|
||||
* SMTP protocol handler.
|
||||
@ -618,7 +619,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
|
||||
&address, &host);
|
||||
if(result)
|
||||
return result;
|
||||
goto out;
|
||||
|
||||
/* Establish whether we should report SMTPUTF8 to the server for this
|
||||
mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
|
||||
@ -642,8 +643,10 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
/* Null reverse-path, RFC-5321, sect. 3.6.3 */
|
||||
from = strdup("<>");
|
||||
|
||||
if(!from)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
if(!from) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Calculate the optional AUTH parameter */
|
||||
if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
|
||||
@ -655,10 +658,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
converting the host name to an IDN A-label if necessary */
|
||||
result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
|
||||
&address, &host);
|
||||
if(result) {
|
||||
free(from);
|
||||
return result;
|
||||
}
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* Establish whether we should report SMTPUTF8 to the server for this
|
||||
mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
|
||||
@ -676,17 +677,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
/* An invalid mailbox was provided but we'll simply let the server
|
||||
worry about it */
|
||||
auth = aprintf("<%s>", address);
|
||||
|
||||
free(address);
|
||||
}
|
||||
else
|
||||
/* Empty AUTH, RFC-2554, sect. 5 */
|
||||
auth = strdup("<>");
|
||||
|
||||
if(!auth) {
|
||||
free(from);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -710,12 +708,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
if(!result)
|
||||
result = Curl_mime_rewind(&data->set.mimepost);
|
||||
|
||||
if(result) {
|
||||
free(from);
|
||||
free(auth);
|
||||
|
||||
return result;
|
||||
}
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
data->state.infilesize = Curl_mime_size(&data->set.mimepost);
|
||||
|
||||
@ -730,10 +724,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
|
||||
|
||||
if(!size) {
|
||||
free(from);
|
||||
free(auth);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,6 +746,15 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup client reader for size and EOB conversion */
|
||||
result = Client_reader_set_fread(data, data->state.infilesize);
|
||||
if(result)
|
||||
goto out;
|
||||
/* Add the client reader doing STMP EOB escaping */
|
||||
result = cr_eob_add(data);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* Send the MAIL command */
|
||||
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
|
||||
"MAIL FROM:%s%s%s%s%s%s",
|
||||
@ -765,6 +766,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
utf8 ? " SMTPUTF8" /* Internationalised mailbox */
|
||||
: ""); /* included in our envelope */
|
||||
|
||||
out:
|
||||
free(from);
|
||||
free(auth);
|
||||
free(size);
|
||||
@ -1393,9 +1395,6 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
|
||||
CURLcode result = CURLE_OK;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct SMTP *smtp = data->req.p.smtp;
|
||||
struct pingpong *pp = &conn->proto.smtpc.pp;
|
||||
char *eob;
|
||||
size_t len, bytes_written;
|
||||
|
||||
(void)premature;
|
||||
|
||||
@ -1411,46 +1410,6 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
|
||||
}
|
||||
else if(!data->set.connect_only && data->set.mail_rcpt &&
|
||||
(data->state.upload || IS_MIME_POST(data))) {
|
||||
/* Calculate the EOB taking into account any terminating CRLF from the
|
||||
previous line of the email or the CRLF of the DATA command when there
|
||||
is "no mail data". RFC-5321, sect. 4.1.1.4.
|
||||
|
||||
Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
|
||||
fail when using a different pointer following a previous write, that
|
||||
returned CURLE_AGAIN, we duplicate the EOB now rather than when the
|
||||
bytes written doesn't equal len. */
|
||||
if(smtp->trailing_crlf || !data->state.infilesize) {
|
||||
eob = strdup(&SMTP_EOB[2]);
|
||||
len = SMTP_EOB_LEN - 2;
|
||||
}
|
||||
else {
|
||||
eob = strdup(SMTP_EOB);
|
||||
len = SMTP_EOB_LEN;
|
||||
}
|
||||
|
||||
if(!eob)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Send the end of block data */
|
||||
result = Curl_xfer_send(data, eob, len, &bytes_written);
|
||||
if(result) {
|
||||
free(eob);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(bytes_written != len) {
|
||||
/* The whole chunk was not sent so keep it around and adjust the
|
||||
pingpong structure accordingly */
|
||||
pp->sendthis = eob;
|
||||
pp->sendsize = len;
|
||||
pp->sendleft = len - bytes_written;
|
||||
}
|
||||
else {
|
||||
/* Successfully sent so adjust the response timeout relative to now */
|
||||
pp->response = Curl_now();
|
||||
|
||||
free(eob);
|
||||
}
|
||||
|
||||
smtp_state(data, SMTP_POSTDATA);
|
||||
|
||||
@ -1818,108 +1777,159 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
|
||||
const ssize_t nread,
|
||||
const ssize_t offset)
|
||||
struct cr_eob_ctx {
|
||||
struct Curl_creader super;
|
||||
struct bufq buf;
|
||||
size_t n_eob; /* how many EOB bytes we matched so far */
|
||||
size_t eob; /* Number of bytes of the EOB (End Of Body) that
|
||||
have been received so far */
|
||||
BIT(read_eos); /* we read an EOS from the next reader */
|
||||
BIT(eos); /* we have returned an EOS */
|
||||
};
|
||||
|
||||
static CURLcode cr_eob_init(struct Curl_easy *data,
|
||||
struct Curl_creader *reader)
|
||||
{
|
||||
/* When sending a SMTP payload we must detect CRLF. sequences making sure
|
||||
they are sent as CRLF.. instead, as a . on the beginning of a line will
|
||||
be deleted by the server when not part of an EOB terminator and a
|
||||
genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
|
||||
data by the server
|
||||
*/
|
||||
ssize_t i;
|
||||
ssize_t si;
|
||||
struct SMTP *smtp = data->req.p.smtp;
|
||||
char *scratch = data->state.scratch;
|
||||
char *newscratch = NULL;
|
||||
char *oldscratch = NULL;
|
||||
size_t eob_sent;
|
||||
|
||||
/* Do we need to allocate a scratch buffer? */
|
||||
if(!scratch || data->set.crlf) {
|
||||
oldscratch = scratch;
|
||||
|
||||
scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
|
||||
if(!newscratch) {
|
||||
failf(data, "Failed to alloc scratch buffer");
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
DEBUGASSERT((size_t)data->set.upload_buffer_size >= (size_t)nread);
|
||||
|
||||
/* Have we already sent part of the EOB? */
|
||||
eob_sent = smtp->eob;
|
||||
|
||||
/* This loop can be improved by some kind of Boyer-Moore style of
|
||||
approach but that is saved for later... */
|
||||
if(offset)
|
||||
memcpy(scratch, data->req.upload_fromhere, offset);
|
||||
for(i = offset, si = offset; i < nread; i++) {
|
||||
if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
|
||||
smtp->eob++;
|
||||
|
||||
/* Is the EOB potentially the terminating CRLF? */
|
||||
if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
|
||||
smtp->trailing_crlf = TRUE;
|
||||
else
|
||||
smtp->trailing_crlf = FALSE;
|
||||
}
|
||||
else if(smtp->eob) {
|
||||
/* A previous substring matched so output that first */
|
||||
memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
|
||||
si += smtp->eob - eob_sent;
|
||||
|
||||
/* Then compare the first byte */
|
||||
if(SMTP_EOB[0] == data->req.upload_fromhere[i])
|
||||
smtp->eob = 1;
|
||||
else
|
||||
smtp->eob = 0;
|
||||
|
||||
eob_sent = 0;
|
||||
|
||||
/* Reset the trailing CRLF flag as there was more data */
|
||||
smtp->trailing_crlf = FALSE;
|
||||
}
|
||||
|
||||
/* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
|
||||
if(SMTP_EOB_FIND_LEN == smtp->eob) {
|
||||
/* Copy the replacement data to the target buffer */
|
||||
memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
|
||||
SMTP_EOB_REPL_LEN - eob_sent);
|
||||
si += SMTP_EOB_REPL_LEN - eob_sent;
|
||||
smtp->eob = 0;
|
||||
eob_sent = 0;
|
||||
}
|
||||
else if(!smtp->eob)
|
||||
scratch[si++] = data->req.upload_fromhere[i];
|
||||
}
|
||||
|
||||
if(smtp->eob - eob_sent) {
|
||||
/* A substring matched before processing ended so output that now */
|
||||
memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
|
||||
si += smtp->eob - eob_sent;
|
||||
}
|
||||
|
||||
/* Only use the new buffer if we replaced something */
|
||||
if(si != nread) {
|
||||
/* Upload from the new (replaced) buffer instead */
|
||||
data->req.upload_fromhere = scratch;
|
||||
|
||||
/* Save the buffer so it can be freed later */
|
||||
data->state.scratch = scratch;
|
||||
|
||||
/* Free the old scratch buffer */
|
||||
free(oldscratch);
|
||||
|
||||
/* Set the new amount too */
|
||||
data->req.upload_present = si;
|
||||
}
|
||||
else
|
||||
free(newscratch);
|
||||
|
||||
struct cr_eob_ctx *ctx = (struct cr_eob_ctx *)reader;
|
||||
(void)data;
|
||||
/* The first char we read is the first on a line, as if we had
|
||||
* read CRLF just before */
|
||||
ctx->n_eob = 2;
|
||||
Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void cr_eob_close(struct Curl_easy *data, struct Curl_creader *reader)
|
||||
{
|
||||
struct cr_eob_ctx *ctx = (struct cr_eob_ctx *)reader;
|
||||
(void)data;
|
||||
Curl_bufq_free(&ctx->buf);
|
||||
}
|
||||
|
||||
/* this is the 5-bytes End-Of-Body marker for SMTP */
|
||||
#define SMTP_EOB "\r\n.\r\n"
|
||||
#define SMTP_EOB_FIND_LEN 3
|
||||
|
||||
/* client reader doing SMTP End-Of-Body escaping. */
|
||||
static CURLcode cr_eob_read(struct Curl_easy *data,
|
||||
struct Curl_creader *reader,
|
||||
char *buf, size_t blen,
|
||||
size_t *pnread, bool *peos)
|
||||
{
|
||||
struct cr_eob_ctx *ctx = (struct cr_eob_ctx *)reader;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t nread, i, start, n;
|
||||
bool eos;
|
||||
|
||||
if(!ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
|
||||
/* Get more and convert it when needed */
|
||||
result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
ctx->read_eos = eos;
|
||||
if(nread) {
|
||||
if(!ctx->n_eob && !memchr(buf, SMTP_EOB[0], nread)) {
|
||||
/* not in the middle of a match, no EOB start found, just pass */
|
||||
*pnread = nread;
|
||||
*peos = FALSE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
/* scan for EOB (continuation) and convert */
|
||||
for(i = start = 0; i < nread; ++i) {
|
||||
if(ctx->n_eob >= SMTP_EOB_FIND_LEN) {
|
||||
/* matched the EOB prefix and seeing additional char, add '.' */
|
||||
result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
|
||||
if(result)
|
||||
return result;
|
||||
result = Curl_bufq_cwrite(&ctx->buf, ".", 1, &n);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->n_eob = 0;
|
||||
start = i;
|
||||
if(data->state.infilesize > 0)
|
||||
data->state.infilesize++;
|
||||
}
|
||||
|
||||
if(buf[i] != SMTP_EOB[ctx->n_eob])
|
||||
ctx->n_eob = 0;
|
||||
|
||||
if(buf[i] == SMTP_EOB[ctx->n_eob]) {
|
||||
/* matching another char of the EOB */
|
||||
++ctx->n_eob;
|
||||
}
|
||||
}
|
||||
|
||||
/* add any remainder to buf */
|
||||
if(start < nread) {
|
||||
result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if(ctx->read_eos) {
|
||||
/* if we last matched a CRLF or if the data was empty, add ".\r\n"
|
||||
* to end the body. If we sent something and it did not end with "\r\n",
|
||||
* add "\r\n.\r\n" to end the body */
|
||||
const char *eob = SMTP_EOB;
|
||||
switch(ctx->n_eob) {
|
||||
case 2:
|
||||
/* seen a CRLF at the end, just add the remainder */
|
||||
eob = &SMTP_EOB[2];
|
||||
break;
|
||||
case 3:
|
||||
/* ended with '\r\n.', we should escpe the last '.' */
|
||||
eob = "." SMTP_EOB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
result = Curl_bufq_cwrite(&ctx->buf, eob, strlen(eob), &n);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
*peos = FALSE;
|
||||
if(!Curl_bufq_is_empty(&ctx->buf)) {
|
||||
result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
|
||||
}
|
||||
else
|
||||
*pnread = 0;
|
||||
|
||||
if(ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
|
||||
/* no more data, read all, done. */
|
||||
ctx->eos = TRUE;
|
||||
}
|
||||
*peos = ctx->eos;
|
||||
DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
|
||||
blen, result, *pnread, *peos));
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static const struct Curl_crtype cr_eob = {
|
||||
"cr-smtp-eob",
|
||||
cr_eob_init,
|
||||
cr_eob_read,
|
||||
cr_eob_close,
|
||||
Curl_creader_def_needs_rewind,
|
||||
sizeof(struct cr_eob_ctx)
|
||||
};
|
||||
|
||||
static CURLcode cr_eob_add(struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_creader *reader = NULL;
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_creader_create(&reader, data, &cr_eob,
|
||||
CURL_CR_CONTENT_ENCODE);
|
||||
if(!result)
|
||||
result = Curl_creader_add(data, reader);
|
||||
|
||||
if(result && reader)
|
||||
Curl_creader_free(data, reader);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* CURL_DISABLE_SMTP */
|
||||
|
13
lib/smtp.h
13
lib/smtp.h
@ -84,17 +84,4 @@ struct smtp_conn {
|
||||
extern const struct Curl_handler Curl_handler_smtp;
|
||||
extern const struct Curl_handler Curl_handler_smtps;
|
||||
|
||||
/* this is the 5-bytes End-Of-Body marker for SMTP */
|
||||
#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
|
||||
#define SMTP_EOB_LEN 5
|
||||
#define SMTP_EOB_FIND_LEN 3
|
||||
|
||||
/* if found in data, replace it with this string instead */
|
||||
#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
|
||||
#define SMTP_EOB_REPL_LEN 4
|
||||
|
||||
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
|
||||
const ssize_t nread,
|
||||
const ssize_t offset);
|
||||
|
||||
#endif /* HEADER_CURL_SMTP_H */
|
||||
|
@ -452,8 +452,6 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
|
||||
if(data->state.upload) {
|
||||
/* If we are uploading, send an WRQ */
|
||||
setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
|
||||
state->data->req.upload_fromhere =
|
||||
(char *)state->spacket.data + 4;
|
||||
if(data->state.infilesize != -1)
|
||||
Curl_pgrsSetUploadSize(data, data->state.infilesize);
|
||||
}
|
||||
|
202
lib/transfer.c
202
lib/transfer.c
@ -115,16 +115,6 @@ char *Curl_checkheaders(const struct Curl_easy *data,
|
||||
}
|
||||
#endif
|
||||
|
||||
CURLcode Curl_get_upload_buffer(struct Curl_easy *data)
|
||||
{
|
||||
if(!data->state.ulbuf) {
|
||||
data->state.ulbuf = malloc(data->set.upload_buffer_size);
|
||||
if(!data->state.ulbuf)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static int data_pending(struct Curl_easy *data)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
@ -330,17 +320,6 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_done_sending(struct Curl_easy *data,
|
||||
struct SingleRequest *k)
|
||||
{
|
||||
k->keepon &= ~KEEP_SEND; /* we're done writing */
|
||||
|
||||
/* These functions should be moved into the handler struct! */
|
||||
Curl_conn_ev_data_done_send(data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(USE_WINSOCK)
|
||||
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
|
||||
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
|
||||
@ -368,174 +347,37 @@ static void win_update_buffer_size(curl_socket_t sockfd)
|
||||
/*
|
||||
* Send data to upload to the server, when the socket is writable.
|
||||
*/
|
||||
static CURLcode readwrite_upload(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int *didwhat)
|
||||
static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
|
||||
{
|
||||
size_t bytes_written;
|
||||
CURLcode result;
|
||||
ssize_t nread; /* number of bytes read */
|
||||
struct SingleRequest *k = &data->req;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
(void)conn;
|
||||
*didwhat |= KEEP_SEND;
|
||||
if((data->req.keepon & KEEP_SEND_PAUSE))
|
||||
return CURLE_OK;
|
||||
|
||||
if(!(k->keepon & KEEP_SEND_PAUSE)) {
|
||||
result = Curl_req_flush(data);
|
||||
if(result == CURLE_AGAIN) /* unable to send all we have */
|
||||
return CURLE_OK;
|
||||
else if(result)
|
||||
return result;
|
||||
}
|
||||
/* We should not get here when the sending is already done. It
|
||||
* probably means that someone set `data-req.keepon |= KEEP_SEND`
|
||||
* when it should not. */
|
||||
DEBUGASSERT(!Curl_req_done_sending(data));
|
||||
|
||||
do {
|
||||
curl_off_t nbody;
|
||||
ssize_t offset = 0;
|
||||
bool eos;
|
||||
|
||||
if(0 != k->upload_present &&
|
||||
k->upload_present < curl_upload_refill_watermark(data) &&
|
||||
!k->upload_chunky &&/*(variable sized chunked header; append not safe)*/
|
||||
!k->upload_done && /*!(k->upload_done once k->upload_present sent)*/
|
||||
!(k->writebytecount + (curl_off_t)k->upload_present ==
|
||||
data->state.infilesize)) {
|
||||
offset = k->upload_present;
|
||||
}
|
||||
|
||||
/* only read more data if there's no upload data already
|
||||
present in the upload buffer, or if appending to upload buffer */
|
||||
if(0 == k->upload_present || offset) {
|
||||
result = Curl_get_upload_buffer(data);
|
||||
if(result)
|
||||
return result;
|
||||
if(offset && k->upload_fromhere != data->state.ulbuf)
|
||||
memmove(data->state.ulbuf, k->upload_fromhere, offset);
|
||||
/* init the "upload from here" pointer */
|
||||
k->upload_fromhere = data->state.ulbuf;
|
||||
|
||||
if(!k->upload_done) {
|
||||
/* HTTP pollution, this should be written nicer to become more
|
||||
protocol agnostic. */
|
||||
size_t fillcount;
|
||||
|
||||
if(k->exp100 == EXP100_SENDING_REQUEST) {
|
||||
/* If this call is to send body data, we must take some action:
|
||||
We have sent off the full HTTP 1.1 request, and we shall now
|
||||
go into the Expect: 100 state and await such a header */
|
||||
k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
|
||||
k->keepon &= ~KEEP_SEND; /* disable writing */
|
||||
k->start100 = Curl_now(); /* timeout count starts now */
|
||||
*didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
|
||||
/* set a timeout for the multi interface */
|
||||
Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
|
||||
break;
|
||||
}
|
||||
|
||||
k->upload_fromhere += offset;
|
||||
result = Curl_client_read(data, k->upload_fromhere,
|
||||
data->set.upload_buffer_size-offset,
|
||||
&fillcount, &eos);
|
||||
k->upload_fromhere -= offset;
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
nread = offset + fillcount;
|
||||
}
|
||||
else
|
||||
nread = 0; /* we're done uploading/reading */
|
||||
|
||||
if(!nread && (k->keepon & KEEP_SEND_PAUSE)) {
|
||||
/* this is a paused transfer */
|
||||
break;
|
||||
}
|
||||
if(nread <= 0) {
|
||||
result = Curl_done_sending(data, k);
|
||||
if(result)
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
|
||||
/* store number of bytes available for upload */
|
||||
k->upload_present = nread;
|
||||
|
||||
#ifndef CURL_DISABLE_SMTP
|
||||
if(conn->handler->protocol & PROTO_FAMILY_SMTP) {
|
||||
result = Curl_smtp_escape_eob(data, nread, offset);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif /* CURL_DISABLE_SMTP */
|
||||
} /* if 0 == k->upload_present or appended to upload buffer */
|
||||
else {
|
||||
/* We have a partial buffer left from a previous "round". Use
|
||||
that instead of reading more data */
|
||||
}
|
||||
|
||||
/* write to socket (send away data) */
|
||||
result = Curl_xfer_send(data,
|
||||
k->upload_fromhere, /* buffer pointer */
|
||||
k->upload_present, /* buffer size */
|
||||
&bytes_written); /* actually sent */
|
||||
if(!Curl_req_done_sending(data)) {
|
||||
*didwhat |= KEEP_SEND;
|
||||
result = Curl_req_send_more(data);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
#if defined(_WIN32) && defined(USE_WINSOCK)
|
||||
/* FIXME: this looks like it would fit better into cf-socket.c
|
||||
* but then I do not know enough Windows to say... */
|
||||
{
|
||||
struct curltime n = Curl_now();
|
||||
if(Curl_timediff(n, conn->last_sndbuf_update) > 1000) {
|
||||
win_update_buffer_size(conn->writesockfd);
|
||||
conn->last_sndbuf_update = n;
|
||||
if(Curl_timediff(n, data->conn->last_sndbuf_update) > 1000) {
|
||||
win_update_buffer_size(data->conn->writesockfd);
|
||||
data->conn->last_sndbuf_update = n;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nbody = bytes_written;
|
||||
if(nbody) {
|
||||
/* show the data before we change the pointer upload_fromhere */
|
||||
Curl_debug(data, CURLINFO_DATA_OUT,
|
||||
&k->upload_fromhere[bytes_written - nbody],
|
||||
(size_t)nbody);
|
||||
|
||||
k->writebytecount += nbody;
|
||||
Curl_pgrsSetUploadCounter(data, k->writebytecount);
|
||||
}
|
||||
|
||||
if((!k->upload_chunky || k->forbidchunk) &&
|
||||
(k->writebytecount == data->state.infilesize)) {
|
||||
/* we have sent all data we were supposed to */
|
||||
k->upload_done = TRUE;
|
||||
infof(data, "We are completely uploaded and fine");
|
||||
}
|
||||
|
||||
if(k->upload_present != bytes_written) {
|
||||
/* we only wrote a part of the buffer (if anything), deal with it! */
|
||||
|
||||
/* store the amount of bytes left in the buffer to write */
|
||||
k->upload_present -= bytes_written;
|
||||
|
||||
/* advance the pointer where to find the buffer when the next send
|
||||
is to happen */
|
||||
k->upload_fromhere += bytes_written;
|
||||
}
|
||||
else {
|
||||
/* we've uploaded that buffer now */
|
||||
result = Curl_get_upload_buffer(data);
|
||||
if(result)
|
||||
return result;
|
||||
k->upload_fromhere = data->state.ulbuf;
|
||||
k->upload_present = 0; /* no more bytes left */
|
||||
|
||||
if(k->upload_done) {
|
||||
result = Curl_done_sending(data, k);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} while(0); /* just to break out from! */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int select_bits_paused(struct Curl_easy *data, int select_bits)
|
||||
@ -626,7 +468,7 @@ CURLcode Curl_readwrite(struct Curl_easy *data,
|
||||
if((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) {
|
||||
/* write */
|
||||
|
||||
result = readwrite_upload(data, conn, &didwhat);
|
||||
result = readwrite_upload(data, &didwhat);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
@ -1458,3 +1300,9 @@ CURLcode Curl_xfer_recv(struct Curl_easy *data,
|
||||
blen = (size_t)data->set.buffer_size;
|
||||
return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
|
||||
}
|
||||
|
||||
CURLcode Curl_xfer_send_close(struct Curl_easy *data)
|
||||
{
|
||||
Curl_conn_ev_data_done_send(data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
@ -50,10 +50,6 @@ int Curl_single_getsock(struct Curl_easy *data,
|
||||
struct connectdata *conn, curl_socket_t *socks);
|
||||
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
|
||||
bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
|
||||
CURLcode Curl_get_upload_buffer(struct Curl_easy *data);
|
||||
|
||||
CURLcode Curl_done_sending(struct Curl_easy *data,
|
||||
struct SingleRequest *k);
|
||||
|
||||
/**
|
||||
* Write the transfer raw response bytes, as received from the connection.
|
||||
@ -106,4 +102,6 @@ CURLcode Curl_xfer_recv(struct Curl_easy *data,
|
||||
char *buf, size_t blen,
|
||||
ssize_t *pnrcvd);
|
||||
|
||||
CURLcode Curl_xfer_send_close(struct Curl_easy *data);
|
||||
|
||||
#endif /* HEADER_CURL_TRANSFER_H */
|
||||
|
@ -277,7 +277,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
|
||||
|
||||
up_free(data);
|
||||
Curl_dyn_free(&data->state.headerb);
|
||||
Curl_safefree(data->state.ulbuf);
|
||||
Curl_flush_cookies(data, TRUE);
|
||||
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
|
||||
Curl_altsvc_cleanup(&data->asi);
|
||||
|
@ -1215,7 +1215,6 @@ struct UrlState {
|
||||
struct dynbuf headerb; /* buffer to store headers in */
|
||||
struct curl_slist *hstslist; /* list of HSTS files set by
|
||||
curl_easy_setopt(HSTS) calls */
|
||||
char *ulbuf; /* allocated upload buffer or NULL */
|
||||
curl_off_t current_speed; /* the ProgressShow() function sets this,
|
||||
bytes / second */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user