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");
|
infof(data, "Got 417 while waiting for a 100");
|
||||||
data->state.disableexpect = TRUE;
|
data->state.disableexpect = TRUE;
|
||||||
data->req.newurl = strdup(data->state.url);
|
data->req.newurl = strdup(data->state.url);
|
||||||
Curl_done_sending(data, k);
|
Curl_req_abort_sending(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = status_line(data, conn,
|
result = status_line(data, conn,
|
||||||
@ -663,7 +663,10 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
|
|||||||
size_t fillcount;
|
size_t fillcount;
|
||||||
struct Curl_easy *data = (struct Curl_easy *)userdata;
|
struct Curl_easy *data = (struct Curl_easy *)userdata;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
char *xfer_ulbuf;
|
||||||
|
size_t xfer_ulblen;
|
||||||
bool eos;
|
bool eos;
|
||||||
|
int rc = HYPER_POLL_ERROR;
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
|
|
||||||
if(data->req.exp100 > EXP100_SEND_DATA) {
|
if(data->req.exp100 > EXP100_SEND_DATA) {
|
||||||
@ -677,39 +680,44 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
|
|||||||
return HYPER_POLL_PENDING;
|
return HYPER_POLL_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Curl_client_read(data, data->state.ulbuf,
|
result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
|
||||||
data->set.upload_buffer_size,
|
if(result)
|
||||||
&fillcount, &eos);
|
goto out;
|
||||||
if(result) {
|
|
||||||
data->state.hresult = result;
|
result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &fillcount, &eos);
|
||||||
return HYPER_POLL_ERROR;
|
if(result)
|
||||||
}
|
goto out;
|
||||||
|
|
||||||
if(fillcount) {
|
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)
|
if(copy)
|
||||||
*chunk = copy;
|
*chunk = copy;
|
||||||
else {
|
else {
|
||||||
data->state.hresult = CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
return HYPER_POLL_ERROR;
|
goto out;
|
||||||
}
|
}
|
||||||
/* increasing the writebytecount here is a little premature but we
|
/* increasing the writebytecount here is a little premature but we
|
||||||
don't know exactly when the body is sent */
|
don't know exactly when the body is sent */
|
||||||
data->req.writebytecount += fillcount;
|
data->req.writebytecount += fillcount;
|
||||||
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
|
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
|
||||||
return HYPER_POLL_READY;
|
rc = HYPER_POLL_READY;
|
||||||
}
|
}
|
||||||
else if(eos) {
|
else if(eos) {
|
||||||
*chunk = NULL;
|
*chunk = NULL;
|
||||||
return HYPER_POLL_READY;
|
rc = HYPER_POLL_READY;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* paused, save a waker */
|
/* paused, save a waker */
|
||||||
if(data->hyp.send_body_waker)
|
if(data->hyp.send_body_waker)
|
||||||
hyper_waker_free(data->hyp.send_body_waker);
|
hyper_waker_free(data->hyp.send_body_waker);
|
||||||
data->hyp.send_body_waker = hyper_context_waker(ctx);
|
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,
|
hyper_request *hyperreq,
|
||||||
Curl_HttpReq httpreq)
|
Curl_HttpReq httpreq)
|
||||||
{
|
{
|
||||||
struct HTTP *http = data->req.p.http;
|
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
struct dynbuf req;
|
struct dynbuf req;
|
||||||
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
|
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
|
||||||
@ -731,21 +738,21 @@ static CURLcode bodysend(struct Curl_easy *data,
|
|||||||
hyper_body *body;
|
hyper_body *body;
|
||||||
Curl_dyn_init(&req, DYN_HTTP_REQUEST);
|
Curl_dyn_init(&req, DYN_HTTP_REQUEST);
|
||||||
result = Curl_http_req_complete(data, &req, httpreq);
|
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));
|
result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Curl_dyn_free(&req);
|
Curl_dyn_free(&req);
|
||||||
|
|
||||||
body = hyper_body_new();
|
body = hyper_body_new();
|
||||||
hyper_body_set_userdata(body, data);
|
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);
|
hyper_body_set_data_func(body, uploadstreamed);
|
||||||
|
|
||||||
if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
|
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;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
http->sending = HTTPSEND_BODY;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -114,18 +114,12 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
|
|||||||
struct h1_tunnel_state **pts)
|
struct h1_tunnel_state **pts)
|
||||||
{
|
{
|
||||||
struct h1_tunnel_state *ts;
|
struct h1_tunnel_state *ts;
|
||||||
CURLcode result;
|
|
||||||
|
|
||||||
if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
|
if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
|
||||||
failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
|
failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
|
||||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
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));
|
ts = calloc(1, sizeof(*ts));
|
||||||
if(!ts)
|
if(!ts)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
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 fd;
|
||||||
int mode;
|
int mode;
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
char *xfer_buf;
|
char *xfer_ulbuf;
|
||||||
size_t xfer_blen;
|
size_t xfer_ulblen;
|
||||||
curl_off_t bytecount = 0;
|
curl_off_t bytecount = 0;
|
||||||
struct_stat file_stat;
|
struct_stat file_stat;
|
||||||
const char *sendbuf;
|
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;
|
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)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ static CURLcode file_upload(struct Curl_easy *data)
|
|||||||
ssize_t nwrite;
|
ssize_t nwrite;
|
||||||
size_t readcount;
|
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)
|
if(result)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -363,16 +363,16 @@ static CURLcode file_upload(struct Curl_easy *data)
|
|||||||
if((curl_off_t)nread <= data->state.resume_from) {
|
if((curl_off_t)nread <= data->state.resume_from) {
|
||||||
data->state.resume_from -= nread;
|
data->state.resume_from -= nread;
|
||||||
nread = 0;
|
nread = 0;
|
||||||
sendbuf = xfer_buf;
|
sendbuf = xfer_ulbuf;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendbuf = xfer_buf + data->state.resume_from;
|
sendbuf = xfer_ulbuf + data->state.resume_from;
|
||||||
nread -= (size_t)data->state.resume_from;
|
nread -= (size_t)data->state.resume_from;
|
||||||
data->state.resume_from = 0;
|
data->state.resume_from = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sendbuf = xfer_buf;
|
sendbuf = xfer_ulbuf;
|
||||||
|
|
||||||
/* write the data to the target */
|
/* write the data to the target */
|
||||||
nwrite = write(fd, sendbuf, nread);
|
nwrite = write(fd, sendbuf, nread);
|
||||||
@ -395,7 +395,7 @@ static CURLcode file_upload(struct Curl_easy *data)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
close(fd);
|
close(fd);
|
||||||
Curl_multi_xfer_buf_release(data, xfer_buf);
|
Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
58
lib/http.c
58
lib/http.c
@ -1283,7 +1283,6 @@ CURLcode Curl_http_done(struct Curl_easy *data,
|
|||||||
if(!http)
|
if(!http)
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
|
||||||
Curl_dyn_free(&http->send_buffer);
|
|
||||||
Curl_dyn_reset(&data->state.headerb);
|
Curl_dyn_reset(&data->state.headerb);
|
||||||
Curl_hyper_done(data);
|
Curl_hyper_done(data);
|
||||||
Curl_ws_done(data);
|
Curl_ws_done(data);
|
||||||
@ -2151,6 +2150,12 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
|
|||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
struct HTTP *http = data->req.p.http;
|
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);
|
DEBUGASSERT(data->conn);
|
||||||
switch(httpreq) {
|
switch(httpreq) {
|
||||||
case HTTPREQ_PUT: /* Let's PUT the data to the server! */
|
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;
|
data->state.in = (void *) data->state.mimepost;
|
||||||
result = Client_reader_set_fread(data, data->state.infilesize);
|
result = Client_reader_set_fread(data, data->state.infilesize);
|
||||||
}
|
}
|
||||||
http->sending = HTTPSEND_BODY;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case HTTPREQ_POST:
|
case HTTPREQ_POST:
|
||||||
@ -2294,19 +2298,21 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if(!http->postsize) {
|
if(!http->postsize) {
|
||||||
Curl_pgrsSetUploadSize(data, -1);
|
Curl_pgrsSetUploadSize(data, 0);
|
||||||
result = Client_reader_set_null(data);
|
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);
|
Curl_pgrsSetUploadSize(data, http->postsize);
|
||||||
result = Client_reader_set_buf(data, data->set.postfields,
|
if(http->postsize > 0)
|
||||||
(size_t)http->postsize);
|
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 */
|
else { /* we read the bytes from the callback */
|
||||||
Curl_pgrsSetUploadSize(data, http->postsize);
|
Curl_pgrsSetUploadSize(data, http->postsize);
|
||||||
result = Client_reader_set_fread(data, http->postsize);
|
result = Client_reader_set_fread(data, http->postsize);
|
||||||
}
|
}
|
||||||
http->sending = HTTPSEND_BODY;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -2647,7 +2653,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
|||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
struct HTTP *http;
|
|
||||||
Curl_HttpReq httpreq;
|
Curl_HttpReq httpreq;
|
||||||
const char *te = ""; /* transfer-encoding */
|
const char *te = ""; /* transfer-encoding */
|
||||||
const char *request;
|
const char *request;
|
||||||
@ -2699,9 +2704,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
|||||||
if(result)
|
if(result)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
http = data->req.p.http;
|
|
||||||
DEBUGASSERT(http);
|
|
||||||
|
|
||||||
result = Curl_http_host(data, conn);
|
result = Curl_http_host(data, conn);
|
||||||
if(result)
|
if(result)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -2880,7 +2882,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
|||||||
result = Curl_add_custom_headers(data, FALSE, &req);
|
result = Curl_add_custom_headers(data, FALSE, &req);
|
||||||
|
|
||||||
if(!result) {
|
if(!result) {
|
||||||
http->postdata = NULL; /* nothing to post at this point */
|
|
||||||
if((httpreq == HTTPREQ_GET) ||
|
if((httpreq == HTTPREQ_GET) ||
|
||||||
(httpreq == HTTPREQ_HEAD))
|
(httpreq == HTTPREQ_HEAD))
|
||||||
Curl_pgrsSetUploadSize(data, 0); /* nothing */
|
Curl_pgrsSetUploadSize(data, 0); /* nothing */
|
||||||
@ -2896,29 +2897,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
|||||||
if(result)
|
if(result)
|
||||||
goto fail;
|
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)
|
if((conn->httpversion >= 20) && data->req.upload_chunky)
|
||||||
/* upload_chunky was set above to set up the request in a chunky fashion,
|
/* 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
|
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.
|
* connection for closure after we've read the entire response.
|
||||||
*/
|
*/
|
||||||
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
||||||
if(!k->upload_done) {
|
if(!Curl_req_done_sending(data)) {
|
||||||
if((k->httpcode == 417) && data->state.expect100header) {
|
if((k->httpcode == 417) && data->state.expect100header) {
|
||||||
/* 417 Expectation Failed - try again without the Expect
|
/* 417 Expectation Failed - try again without the Expect
|
||||||
header */
|
header */
|
||||||
@ -3801,7 +3779,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
|||||||
data->state.disableexpect = TRUE;
|
data->state.disableexpect = TRUE;
|
||||||
DEBUGASSERT(!data->req.newurl);
|
DEBUGASSERT(!data->req.newurl);
|
||||||
data->req.newurl = strdup(data->state.url);
|
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) {
|
else if(data->set.http_keep_sending_on_error) {
|
||||||
infof(data, "HTTP error before end of send, keep sending");
|
infof(data, "HTTP error before end of send, keep sending");
|
||||||
@ -3813,10 +3791,9 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
|||||||
else {
|
else {
|
||||||
infof(data, "HTTP error before end of send, stop sending");
|
infof(data, "HTTP error before end of send, stop sending");
|
||||||
streamclose(conn, "Stop sending data before everything sent");
|
streamclose(conn, "Stop sending data before everything sent");
|
||||||
result = Curl_done_sending(data, k);
|
result = Curl_req_abort_sending(data);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
k->upload_done = TRUE;
|
|
||||||
if(data->state.expect100header)
|
if(data->state.expect100header)
|
||||||
k->exp100 = EXP100_FAILED;
|
k->exp100 = EXP100_FAILED;
|
||||||
}
|
}
|
||||||
@ -3828,8 +3805,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->state.rewindbeforesend &&
|
if(data->state.rewindbeforesend && !Curl_req_done_sending(data)) {
|
||||||
(conn->writesockfd != CURL_SOCKET_BAD)) {
|
|
||||||
/* We rewind before next send, continue sending now */
|
/* We rewind before next send, continue sending now */
|
||||||
infof(data, "Keep sending data to get tossed away");
|
infof(data, "Keep sending data to get tossed away");
|
||||||
k->keepon |= KEEP_SEND;
|
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 {
|
struct HTTP {
|
||||||
curl_off_t postsize; /* off_t to handle large file sizes */
|
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
|
#ifndef CURL_DISABLE_HTTP
|
||||||
void *h2_ctx; /* HTTP/2 implementation context */
|
void *h2_ctx; /* HTTP/2 implementation context */
|
||||||
void *h3_ctx; /* HTTP/3 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
|
#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,
|
static CURLMcode multi_timeout(struct Curl_multi *multi,
|
||||||
long *timeout_ms);
|
long *timeout_ms);
|
||||||
static void process_pending_handles(struct Curl_multi *multi);
|
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
|
#ifdef DEBUGBUILD
|
||||||
static const char * const multi_statename[]={
|
static const char * const multi_statename[]={
|
||||||
@ -192,7 +192,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
|
|||||||
data->multi->num_alive--;
|
data->multi->num_alive--;
|
||||||
if(!data->multi->num_alive) {
|
if(!data->multi->num_alive) {
|
||||||
/* free the transfer buffer when we have no more active transfers */
|
/* 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)
|
if(!result)
|
||||||
result = Curl_req_done(&data->req, data, premature);
|
result = Curl_req_done(&data->req, data, premature);
|
||||||
|
|
||||||
Curl_safefree(data->state.ulbuf);
|
|
||||||
|
|
||||||
CONNCACHE_LOCK(data);
|
CONNCACHE_LOCK(data);
|
||||||
Curl_detach_connection(data);
|
Curl_detach_connection(data);
|
||||||
if(CONN_INUSE(conn)) {
|
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);
|
Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
multi_xfer_buf_free(multi);
|
multi_xfer_bufs_free(multi);
|
||||||
free(multi);
|
free(multi);
|
||||||
|
|
||||||
return CURLM_OK;
|
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;
|
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);
|
DEBUGASSERT(multi);
|
||||||
Curl_safefree(multi->xfer_buf);
|
Curl_safefree(multi->xfer_buf);
|
||||||
multi->xfer_buf_len = 0;
|
multi->xfer_buf_len = 0;
|
||||||
multi->xfer_buf_borrowed = FALSE;
|
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 */
|
/* buffer used for transfer data, lazy initialized */
|
||||||
char *xfer_buf; /* the actual buffer */
|
char *xfer_buf; /* the actual buffer */
|
||||||
size_t xfer_buf_len; /* the allocated length */
|
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)
|
#if defined(USE_SSL)
|
||||||
struct multi_ssl_backend_data *ssl_backend_data;
|
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
|
BIT(dead); /* a callback returned error, everything needs to crash and
|
||||||
burn */
|
burn */
|
||||||
BIT(xfer_buf_borrowed); /* xfer_buf is currently being borrowed */
|
BIT(xfer_buf_borrowed); /* xfer_buf is currently being borrowed */
|
||||||
|
BIT(xfer_ulbuf_borrowed); /* xfer_buf is currently being borrowed */
|
||||||
#ifdef DEBUGBUILD
|
#ifdef DEBUGBUILD
|
||||||
BIT(warned); /* true after user warned of DEBUGBUILD */
|
BIT(warned); /* true after user warned of DEBUGBUILD */
|
||||||
#endif
|
#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);
|
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 */
|
#endif /* HEADER_CURL_MULTIIF_H */
|
||||||
|
|||||||
130
lib/request.c
130
lib/request.c
@ -25,6 +25,7 @@
|
|||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
|
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
|
#include "cfilters.h"
|
||||||
#include "dynbuf.h"
|
#include "dynbuf.h"
|
||||||
#include "doh.h"
|
#include "doh.h"
|
||||||
#include "multiif.h"
|
#include "multiif.h"
|
||||||
@ -67,12 +68,14 @@ CURLcode Curl_req_start(struct SingleRequest *req,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode req_flush(struct Curl_easy *data);
|
||||||
|
|
||||||
CURLcode Curl_req_done(struct SingleRequest *req,
|
CURLcode Curl_req_done(struct SingleRequest *req,
|
||||||
struct Curl_easy *data, bool aborted)
|
struct Curl_easy *data, bool aborted)
|
||||||
{
|
{
|
||||||
(void)req;
|
(void)req;
|
||||||
if(!aborted)
|
if(!aborted)
|
||||||
(void)Curl_req_flush(data);
|
(void)req_flush(data);
|
||||||
Curl_client_reset(data);
|
Curl_client_reset(data);
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
@ -129,9 +132,9 @@ void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode req_send(struct Curl_easy *data,
|
static CURLcode xfer_send(struct Curl_easy *data,
|
||||||
const char *buf, size_t blen,
|
const char *buf, size_t blen,
|
||||||
size_t hds_len, size_t *pnwritten)
|
size_t hds_len, size_t *pnwritten)
|
||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
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)) {
|
while(Curl_bufq_peek(&data->req.sendbuf, &buf, &blen)) {
|
||||||
size_t nwritten, hds_len = CURLMIN(data->req.sendbuf_hds_len, 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)
|
if(result)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -206,7 +209,33 @@ static CURLcode req_send_buffer_flush(struct Curl_easy *data)
|
|||||||
return result;
|
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;
|
CURLcode result;
|
||||||
|
|
||||||
@ -221,9 +250,30 @@ CURLcode Curl_req_flush(struct Curl_easy *data)
|
|||||||
return CURLE_AGAIN;
|
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;
|
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
|
#ifndef USE_HYPER
|
||||||
|
|
||||||
static CURLcode req_send_buffer_add(struct Curl_easy *data,
|
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;
|
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 Curl_req_send(struct Curl_easy *data, struct dynbuf *buf)
|
||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
@ -275,18 +309,7 @@ CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf)
|
|||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if((data->req.exp100 == EXP100_SEND_DATA) &&
|
return Curl_req_send_more(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;
|
|
||||||
}
|
}
|
||||||
#endif /* !USE_HYPER */
|
#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);
|
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
|
char *newurl; /* Set to the new URL to use when a redirect or a retry is
|
||||||
wanted */
|
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
|
/* Allocated protocol-specific data. Each protocol handler makes sure this
|
||||||
points to data it needs. */
|
points to data it needs. */
|
||||||
union {
|
union {
|
||||||
@ -139,8 +129,9 @@ struct SingleRequest {
|
|||||||
BIT(download_done); /* set to TRUE when download is complete */
|
BIT(download_done); /* set to TRUE when download is complete */
|
||||||
BIT(eos_written); /* iff EOS has been written to client */
|
BIT(eos_written); /* iff EOS has been written to client */
|
||||||
BIT(eos_read); /* iff EOS has been read from the client */
|
BIT(eos_read); /* iff EOS has been read from the client */
|
||||||
BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
|
BIT(upload_done); /* set to TRUE when all request data has been sent */
|
||||||
upload and we're uploading the last chunk */
|
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(ignorebody); /* we read a response-body but we ignore it! */
|
||||||
BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
|
BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
|
||||||
204 or 304 */
|
204 or 304 */
|
||||||
@ -206,15 +197,26 @@ CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf);
|
|||||||
#endif /* !USE_HYPER */
|
#endif /* !USE_HYPER */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush all buffered request bytes.
|
* TRUE iff the request has sent all request headers and data.
|
||||||
* @return CURLE_OK on success, CURLE_AGAIN if sending was blocked,
|
|
||||||
* or the error on the sending.
|
|
||||||
*/
|
*/
|
||||||
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.
|
* TRUE iff the request wants to send, e.g. has buffered bytes.
|
||||||
*/
|
*/
|
||||||
bool Curl_req_want_send(struct Curl_easy *data);
|
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 */
|
#endif /* HEADER_CURL_REQUEST_H */
|
||||||
|
|||||||
@ -577,6 +577,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
|
|||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
|
||||||
|
|
||||||
/* issue the request */
|
/* issue the request */
|
||||||
result = Curl_req_send(data, &req_buffer);
|
result = Curl_req_send(data, &req_buffer);
|
||||||
if(result) {
|
if(result) {
|
||||||
@ -584,8 +586,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
|
|
||||||
|
|
||||||
/* Increment the CSeq on success */
|
/* Increment the CSeq on success */
|
||||||
data->state.rtsp_next_client_CSeq++;
|
data->state.rtsp_next_client_CSeq++;
|
||||||
|
|
||||||
|
|||||||
@ -576,8 +576,10 @@ static CURLcode cr_in_read(struct Curl_easy *data,
|
|||||||
return CURLE_READ_ERROR;
|
return CURLE_READ_ERROR;
|
||||||
}
|
}
|
||||||
ctx->read_len += nread;
|
ctx->read_len += nread;
|
||||||
|
if(ctx->total_len >= 0)
|
||||||
|
ctx->seen_eos = (ctx->read_len >= ctx->total_len);
|
||||||
*pnread = nread;
|
*pnread = nread;
|
||||||
*peos = FALSE;
|
*peos = ctx->seen_eos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DEBUGF(infof(data, "cr_in_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
|
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;
|
CURLcode result;
|
||||||
|
|
||||||
result = Curl_creader_create(&reader, data, &cr_lc,
|
result = Curl_creader_create(&reader, data, &cr_lc,
|
||||||
CURL_CR_TRANSFER_ENCODE);
|
CURL_CR_CONTENT_ENCODE);
|
||||||
if(!result)
|
if(!result)
|
||||||
result = Curl_creader_add(data, reader);
|
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;
|
arg = UPLOADBUFFER_MIN;
|
||||||
|
|
||||||
data->set.upload_buffer_size = (unsigned int)arg;
|
data->set.upload_buffer_size = (unsigned int)arg;
|
||||||
Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLOPT_NOSIGNAL:
|
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);
|
smbc->recv_buf = malloc(MAX_MESSAGE_SIZE);
|
||||||
if(!smbc->recv_buf)
|
if(!smbc->recv_buf)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
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 */
|
/* Multiple requests are allowed with this connection */
|
||||||
connkeep(conn, "SMB default");
|
connkeep(conn, "SMB default");
|
||||||
@ -567,7 +570,7 @@ static CURLcode smb_send(struct Curl_easy *data, size_t len,
|
|||||||
size_t bytes_written;
|
size_t bytes_written;
|
||||||
CURLcode result;
|
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)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -592,7 +595,7 @@ static CURLcode smb_flush(struct Curl_easy *data)
|
|||||||
if(!smbc->send_size)
|
if(!smbc->send_size)
|
||||||
return CURLE_OK;
|
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);
|
&bytes_written);
|
||||||
if(result)
|
if(result)
|
||||||
return 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,
|
static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd,
|
||||||
const void *msg, size_t msg_len)
|
const void *msg, size_t msg_len)
|
||||||
{
|
{
|
||||||
CURLcode result = Curl_get_upload_buffer(data);
|
struct connectdata *conn = data->conn;
|
||||||
if(result)
|
struct smb_conn *smbc = &conn->proto.smbc;
|
||||||
return result;
|
|
||||||
smb_format_message(data, (struct smb_header *)data->state.ulbuf,
|
smb_format_message(data, (struct smb_header *)smbc->send_buf,
|
||||||
cmd, msg_len);
|
cmd, msg_len);
|
||||||
memcpy(data->state.ulbuf + sizeof(struct smb_header),
|
DEBUGASSERT((sizeof(struct smb_header) + msg_len) <= MAX_MESSAGE_SIZE);
|
||||||
msg, msg_len);
|
memcpy(smbc->send_buf + sizeof(struct smb_header), msg, msg_len);
|
||||||
|
|
||||||
return smb_send(data, sizeof(struct smb_header) + msg_len, 0);
|
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)
|
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_write *msg;
|
||||||
struct smb_request *req = data->req.p.smb;
|
struct smb_request *req = data->req.p.smb;
|
||||||
curl_off_t offset = data->req.offset;
|
curl_off_t offset = data->req.offset;
|
||||||
curl_off_t upload_size = data->req.size - data->req.bytecount;
|
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 */
|
if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
|
||||||
upload_size = MAX_PAYLOAD_SIZE - 1;
|
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 */
|
/* Check if there is data in the transfer buffer */
|
||||||
if(!smbc->send_size && smbc->upload_size) {
|
if(!smbc->send_size && smbc->upload_size) {
|
||||||
size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ?
|
size_t nread = smbc->upload_size > (size_t)MAX_MESSAGE_SIZE ?
|
||||||
(size_t)data->set.upload_buffer_size : smbc->upload_size;
|
(size_t)MAX_MESSAGE_SIZE : smbc->upload_size;
|
||||||
bool eos;
|
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)
|
if(result && result != CURLE_AGAIN)
|
||||||
return result;
|
return result;
|
||||||
if(!nread)
|
if(!nread)
|
||||||
@ -1131,6 +1133,7 @@ static CURLcode smb_disconnect(struct Curl_easy *data,
|
|||||||
Curl_safefree(smbc->share);
|
Curl_safefree(smbc->share);
|
||||||
Curl_safefree(smbc->domain);
|
Curl_safefree(smbc->domain);
|
||||||
Curl_safefree(smbc->recv_buf);
|
Curl_safefree(smbc->recv_buf);
|
||||||
|
Curl_safefree(smbc->send_buf);
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,7 @@ struct smb_conn {
|
|||||||
unsigned int session_key;
|
unsigned int session_key;
|
||||||
unsigned short uid;
|
unsigned short uid;
|
||||||
char *recv_buf;
|
char *recv_buf;
|
||||||
|
char *send_buf;
|
||||||
size_t upload_size;
|
size_t upload_size;
|
||||||
size_t send_size;
|
size_t send_size;
|
||||||
size_t sent;
|
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);
|
const struct bufref *resp);
|
||||||
static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
|
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 smtp_get_message(struct Curl_easy *data, struct bufref *out);
|
||||||
|
static CURLcode cr_eob_add(struct Curl_easy *data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SMTP protocol handler.
|
* 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],
|
result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
|
||||||
&address, &host);
|
&address, &host);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
goto out;
|
||||||
|
|
||||||
/* Establish whether we should report SMTPUTF8 to the server for this
|
/* 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 */
|
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 */
|
/* Null reverse-path, RFC-5321, sect. 3.6.3 */
|
||||||
from = strdup("<>");
|
from = strdup("<>");
|
||||||
|
|
||||||
if(!from)
|
if(!from) {
|
||||||
return CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate the optional AUTH parameter */
|
/* Calculate the optional AUTH parameter */
|
||||||
if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
|
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 */
|
converting the host name to an IDN A-label if necessary */
|
||||||
result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
|
result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
|
||||||
&address, &host);
|
&address, &host);
|
||||||
if(result) {
|
if(result)
|
||||||
free(from);
|
goto out;
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Establish whether we should report SMTPUTF8 to the server for this
|
/* 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 */
|
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
|
/* An invalid mailbox was provided but we'll simply let the server
|
||||||
worry about it */
|
worry about it */
|
||||||
auth = aprintf("<%s>", address);
|
auth = aprintf("<%s>", address);
|
||||||
|
|
||||||
free(address);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Empty AUTH, RFC-2554, sect. 5 */
|
/* Empty AUTH, RFC-2554, sect. 5 */
|
||||||
auth = strdup("<>");
|
auth = strdup("<>");
|
||||||
|
|
||||||
if(!auth) {
|
if(!auth) {
|
||||||
free(from);
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
|
goto out;
|
||||||
return CURLE_OUT_OF_MEMORY;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,12 +708,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
|||||||
if(!result)
|
if(!result)
|
||||||
result = Curl_mime_rewind(&data->set.mimepost);
|
result = Curl_mime_rewind(&data->set.mimepost);
|
||||||
|
|
||||||
if(result) {
|
if(result)
|
||||||
free(from);
|
goto out;
|
||||||
free(auth);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->state.infilesize = Curl_mime_size(&data->set.mimepost);
|
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);
|
size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
|
||||||
|
|
||||||
if(!size) {
|
if(!size) {
|
||||||
free(from);
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
free(auth);
|
goto out;
|
||||||
|
|
||||||
return CURLE_OUT_OF_MEMORY;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 */
|
/* Send the MAIL command */
|
||||||
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
|
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
|
||||||
"MAIL FROM:%s%s%s%s%s%s",
|
"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 */
|
utf8 ? " SMTPUTF8" /* Internationalised mailbox */
|
||||||
: ""); /* included in our envelope */
|
: ""); /* included in our envelope */
|
||||||
|
|
||||||
|
out:
|
||||||
free(from);
|
free(from);
|
||||||
free(auth);
|
free(auth);
|
||||||
free(size);
|
free(size);
|
||||||
@ -1393,9 +1395,6 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
|
|||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct SMTP *smtp = data->req.p.smtp;
|
struct SMTP *smtp = data->req.p.smtp;
|
||||||
struct pingpong *pp = &conn->proto.smtpc.pp;
|
|
||||||
char *eob;
|
|
||||||
size_t len, bytes_written;
|
|
||||||
|
|
||||||
(void)premature;
|
(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 &&
|
else if(!data->set.connect_only && data->set.mail_rcpt &&
|
||||||
(data->state.upload || IS_MIME_POST(data))) {
|
(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);
|
smtp_state(data, SMTP_POSTDATA);
|
||||||
|
|
||||||
@ -1818,108 +1777,159 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
|
struct cr_eob_ctx {
|
||||||
const ssize_t nread,
|
struct Curl_creader super;
|
||||||
const ssize_t offset)
|
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
|
struct cr_eob_ctx *ctx = (struct cr_eob_ctx *)reader;
|
||||||
they are sent as CRLF.. instead, as a . on the beginning of a line will
|
(void)data;
|
||||||
be deleted by the server when not part of an EOB terminator and a
|
/* The first char we read is the first on a line, as if we had
|
||||||
genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
|
* read CRLF just before */
|
||||||
data by the server
|
ctx->n_eob = 2;
|
||||||
*/
|
Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
|
||||||
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);
|
|
||||||
|
|
||||||
return CURLE_OK;
|
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 */
|
#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_smtp;
|
||||||
extern const struct Curl_handler Curl_handler_smtps;
|
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 */
|
#endif /* HEADER_CURL_SMTP_H */
|
||||||
|
|||||||
@ -452,8 +452,6 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
|
|||||||
if(data->state.upload) {
|
if(data->state.upload) {
|
||||||
/* If we are uploading, send an WRQ */
|
/* If we are uploading, send an WRQ */
|
||||||
setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
|
setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
|
||||||
state->data->req.upload_fromhere =
|
|
||||||
(char *)state->spacket.data + 4;
|
|
||||||
if(data->state.infilesize != -1)
|
if(data->state.infilesize != -1)
|
||||||
Curl_pgrsSetUploadSize(data, data->state.infilesize);
|
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
|
#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)
|
static int data_pending(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
@ -330,17 +320,6 @@ out:
|
|||||||
return result;
|
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)
|
#if defined(_WIN32) && defined(USE_WINSOCK)
|
||||||
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
|
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
|
||||||
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
|
#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.
|
* Send data to upload to the server, when the socket is writable.
|
||||||
*/
|
*/
|
||||||
static CURLcode readwrite_upload(struct Curl_easy *data,
|
static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
|
||||||
struct connectdata *conn,
|
|
||||||
int *didwhat)
|
|
||||||
{
|
{
|
||||||
size_t bytes_written;
|
CURLcode result = CURLE_OK;
|
||||||
CURLcode result;
|
|
||||||
ssize_t nread; /* number of bytes read */
|
|
||||||
struct SingleRequest *k = &data->req;
|
|
||||||
|
|
||||||
(void)conn;
|
if((data->req.keepon & KEEP_SEND_PAUSE))
|
||||||
*didwhat |= KEEP_SEND;
|
return CURLE_OK;
|
||||||
|
|
||||||
if(!(k->keepon & KEEP_SEND_PAUSE)) {
|
/* We should not get here when the sending is already done. It
|
||||||
result = Curl_req_flush(data);
|
* probably means that someone set `data-req.keepon |= KEEP_SEND`
|
||||||
if(result == CURLE_AGAIN) /* unable to send all we have */
|
* when it should not. */
|
||||||
return CURLE_OK;
|
DEBUGASSERT(!Curl_req_done_sending(data));
|
||||||
else if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
if(!Curl_req_done_sending(data)) {
|
||||||
curl_off_t nbody;
|
*didwhat |= KEEP_SEND;
|
||||||
ssize_t offset = 0;
|
result = Curl_req_send_more(data);
|
||||||
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(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(USE_WINSOCK)
|
#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();
|
struct curltime n = Curl_now();
|
||||||
if(Curl_timediff(n, conn->last_sndbuf_update) > 1000) {
|
if(Curl_timediff(n, data->conn->last_sndbuf_update) > 1000) {
|
||||||
win_update_buffer_size(conn->writesockfd);
|
win_update_buffer_size(data->conn->writesockfd);
|
||||||
conn->last_sndbuf_update = n;
|
data->conn->last_sndbuf_update = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
nbody = bytes_written;
|
return result;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int select_bits_paused(struct Curl_easy *data, int select_bits)
|
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)) {
|
if((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) {
|
||||||
/* write */
|
/* write */
|
||||||
|
|
||||||
result = readwrite_upload(data, conn, &didwhat);
|
result = readwrite_upload(data, &didwhat);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1458,3 +1300,9 @@ CURLcode Curl_xfer_recv(struct Curl_easy *data,
|
|||||||
blen = (size_t)data->set.buffer_size;
|
blen = (size_t)data->set.buffer_size;
|
||||||
return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
|
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);
|
struct connectdata *conn, curl_socket_t *socks);
|
||||||
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
|
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
|
||||||
bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
|
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.
|
* 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,
|
char *buf, size_t blen,
|
||||||
ssize_t *pnrcvd);
|
ssize_t *pnrcvd);
|
||||||
|
|
||||||
|
CURLcode Curl_xfer_send_close(struct Curl_easy *data);
|
||||||
|
|
||||||
#endif /* HEADER_CURL_TRANSFER_H */
|
#endif /* HEADER_CURL_TRANSFER_H */
|
||||||
|
|||||||
@ -277,7 +277,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
|
|||||||
|
|
||||||
up_free(data);
|
up_free(data);
|
||||||
Curl_dyn_free(&data->state.headerb);
|
Curl_dyn_free(&data->state.headerb);
|
||||||
Curl_safefree(data->state.ulbuf);
|
|
||||||
Curl_flush_cookies(data, TRUE);
|
Curl_flush_cookies(data, TRUE);
|
||||||
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
|
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
|
||||||
Curl_altsvc_cleanup(&data->asi);
|
Curl_altsvc_cleanup(&data->asi);
|
||||||
|
|||||||
@ -1215,7 +1215,6 @@ struct UrlState {
|
|||||||
struct dynbuf headerb; /* buffer to store headers in */
|
struct dynbuf headerb; /* buffer to store headers in */
|
||||||
struct curl_slist *hstslist; /* list of HSTS files set by
|
struct curl_slist *hstslist; /* list of HSTS files set by
|
||||||
curl_easy_setopt(HSTS) calls */
|
curl_easy_setopt(HSTS) calls */
|
||||||
char *ulbuf; /* allocated upload buffer or NULL */
|
|
||||||
curl_off_t current_speed; /* the ProgressShow() function sets this,
|
curl_off_t current_speed; /* the ProgressShow() function sets this,
|
||||||
bytes / second */
|
bytes / second */
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user