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,
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) {
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;
}
/*
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))
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)) {
result = CURLE_OUT_OF_MEMORY;
}
}
- http->sending = HTTPSEND_BODY;
return result;
}
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;
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;
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;
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;
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);
out:
close(fd);
- Curl_multi_xfer_buf_release(data, xfer_buf);
+ Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
return result;
}
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);
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! */
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:
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:
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
- struct HTTP *http;
Curl_HttpReq httpreq;
const char *te = ""; /* transfer-encoding */
const char *request;
if(result)
goto fail;
- http = data->req.p.http;
- DEBUGASSERT(http);
-
result = Curl_http_host(data, conn);
if(result)
goto fail;
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 */
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
* 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 */
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");
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;
}
}
}
- 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;
***************************************************************************/
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
};
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[]={
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);
}
}
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)) {
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;
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;
}
/* 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;
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
*/
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 */
#include "curl_setup.h"
#include "urldata.h"
+#include "cfilters.h"
#include "dynbuf.h"
#include "doh.h"
#include "multiif.h"
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;
}
#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;
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;
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;
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,
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;
if(result)
return result;
- if((data->req.exp100 == EXP100_SEND_DATA) &&
- !Curl_bufq_is_full(&data->req.sendbuf)) {
+ return Curl_req_send_more(data);
+}
+#endif /* !USE_HYPER */
+
+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_send_buffer_flush(data);
+ result = req_flush(data);
if(result == CURLE_AGAIN)
result = CURLE_OK;
return result;
}
-#endif /* !USE_HYPER */
-bool Curl_req_want_send(struct Curl_easy *data)
+CURLcode Curl_req_abort_sending(struct Curl_easy *data)
{
- return data->req.sendbuf_init && !Curl_bufq_is_empty(&data->req.sendbuf);
+ 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;
}
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 {
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 */
#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.
+ */
+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_flush(struct Curl_easy *data);
+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 */
if(result)
goto out;
+ Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+
/* issue the request */
result = Curl_req_send(data, &req_buffer);
if(result) {
goto out;
}
- Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
-
/* Increment the CSeq on success */
data->state.rtsp_next_client_CSeq++;
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
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);
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:
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");
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;
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;
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);
}
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;
/* 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)
Curl_safefree(smbc->share);
Curl_safefree(smbc->domain);
Curl_safefree(smbc->recv_buf);
+ Curl_safefree(smbc->send_buf);
return CURLE_OK;
}
unsigned int session_key;
unsigned short uid;
char *recv_buf;
+ char *send_buf;
size_t upload_size;
size_t send_size;
size_t sent;
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.
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 */
/* 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) {
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 */
/* 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;
}
}
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);
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;
}
}
}
}
+ /* 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",
utf8 ? " SMTPUTF8" /* Internationalised mailbox */
: ""); /* included in our envelope */
+out:
free(from);
free(auth);
free(size);
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;
}
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);
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;
+ 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;
+}
- /* Do we need to allocate a scratch buffer? */
- if(!scratch || data->set.crlf) {
- oldscratch = scratch;
+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);
+}
- scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
- if(!newscratch) {
- failf(data, "Failed to alloc scratch buffer");
+/* this is the 5-bytes End-Of-Body marker for SMTP */
+#define SMTP_EOB "\r\n.\r\n"
+#define SMTP_EOB_FIND_LEN 3
- 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;
+/* 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;
- eob_sent = 0;
+ if(buf[i] == SMTP_EOB[ctx->n_eob]) {
+ /* matching another char of the EOB */
+ ++ctx->n_eob;
+ }
+ }
- /* Reset the trailing CRLF flag as there was more data */
- smtp->trailing_crlf = FALSE;
+ /* add any remainder to buf */
+ if(start < nread) {
+ result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
+ if(result)
+ return result;
+ }
}
- /* 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;
+ 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;
}
- 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;
+ *peos = FALSE;
+ if(!Curl_bufq_is_empty(&ctx->buf)) {
+ result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
}
+ else
+ *pnread = 0;
- /* Only use the new buffer if we replaced something */
- if(si != nread) {
- /* Upload from the new (replaced) buffer instead */
- data->req.upload_fromhere = scratch;
+ 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;
+}
- /* Save the buffer so it can be freed later */
- data->state.scratch = scratch;
+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)
+};
- /* Free the old scratch buffer */
- free(oldscratch);
+static CURLcode cr_eob_add(struct Curl_easy *data)
+{
+ struct Curl_creader *reader = NULL;
+ CURLcode result;
- /* Set the new amount too */
- data->req.upload_present = si;
- }
- else
- free(newscratch);
+ result = Curl_creader_create(&reader, data, &cr_eob,
+ CURL_CR_CONTENT_ENCODE);
+ if(!result)
+ result = Curl_creader_add(data, reader);
- return CURLE_OK;
+ if(result && reader)
+ Curl_creader_free(data, reader);
+ return result;
}
#endif /* CURL_DISABLE_SMTP */
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 */
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);
}
}
#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;
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
/*
* 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;
-
- (void)conn;
- *didwhat |= KEEP_SEND;
-
- 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;
- }
-
- 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;
- }
+ CURLcode result = CURLE_OK;
- /* store number of bytes available for upload */
- k->upload_present = nread;
+ if((data->req.keepon & KEEP_SEND_PAUSE))
+ return CURLE_OK;
-#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 */
- }
+ /* 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));
- /* 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)
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;
}
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;
+}
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.
char *buf, size_t blen,
ssize_t *pnrcvd);
+CURLcode Curl_xfer_send_close(struct Curl_easy *data);
+
#endif /* HEADER_CURL_TRANSFER_H */
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);
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 */