DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
result = Curl_conn_send(data, io_ctx->sockindex,
- (void *)buf, buflen, FALSE, &nwrote);
+ (void *)buf, buflen, &nwrote);
if(result == CURLE_AGAIN) {
DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
/* would block, register interest */
blen -= ts->nsent;
buf += ts->nsent;
- nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &result);
+ nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, &result);
if(nwritten < 0) {
if(result == CURLE_AGAIN) {
result = CURLE_OK;
if(cf) {
struct Curl_easy *data = CF_DATA_CURRENT(cf);
nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
- FALSE, err);
+ err);
CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
buflen, nwritten, *err);
}
static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
struct cf_call_data save;
CURLcode result;
int blocked = 0;
- (void)eos; /* TODO, maybe useful for blocks? */
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
*err = CURLE_SEND_ERROR;
return -1;
size_t written;
result = Curl_conn_send(data, cf->sockindex,
Curl_dyn_ptr(&ctx->data_out),
- len, FALSE, &written);
+ len, &written);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
written = 0;
#endif /* USE_WINSOCK */
static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_socket_ctx *ctx = cf->ctx;
curl_socket_t fdsave;
ssize_t nwritten;
size_t orig_len = len;
- (void)eos; /* unused */
*err = CURLE_OK;
fdsave = cf->conn->sock[cf->sockindex];
cf->conn->sock[cf->sockindex] = ctx->sock;
}
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
return cf->next?
- cf->next->cft->do_send(cf->next, data, buf, len, eos, err) :
+ cf->next->cft->do_send(cf->next, data, buf, len, err) :
CURLE_RECV_ERROR;
}
}
ssize_t Curl_cf_send(struct Curl_easy *data, int num,
- const void *mem, size_t len, bool eos,
- CURLcode *code)
+ const void *mem, size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
cf = cf->next;
}
if(cf) {
- ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, eos, code);
+ ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
DEBUGASSERT(nwritten >= 0 || *code);
DEBUGASSERT(nwritten < 0 || !*code || !len);
return nwritten;
}
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
if(cf)
- return cf->cft->do_send(cf, data, buf, len, eos, err);
+ return cf->cft->do_send(cf, data, buf, len, err);
*err = CURLE_SEND_ERROR;
return -1;
}
}
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t blen, bool eos,
+ const void *buf, size_t blen,
size_t *pnwritten)
{
- size_t write_len = blen;
ssize_t nwritten;
CURLcode result = CURLE_OK;
struct connectdata *conn;
if(p) {
size_t altsize = (size_t)strtoul(p, NULL, 10);
if(altsize)
- write_len = CURLMIN(write_len, altsize);
+ blen = CURLMIN(blen, altsize);
}
}
#endif
- if(write_len != blen)
- eos = FALSE;
- nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
- &result);
+ nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
DEBUGASSERT((nwritten >= 0) || result);
*pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
return result;
struct Curl_easy *data, /* transfer */
const void *buf, /* data to write */
size_t len, /* amount to write */
- bool eos, /* last chunk */
CURLcode *err); /* error to return */
typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf,
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err);
+ const void *buf, size_t len, CURLcode *err);
ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
bool blocking, bool *done);
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err);
+ const void *buf, size_t len, CURLcode *err);
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
* The error code is placed into `*code`.
*/
ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t len, bool eos, CURLcode *code);
+ const void *buf, size_t len, CURLcode *code);
/**
* The easy handle `data` is being attached to `conn`. This does
* Will return CURLE_AGAIN iff blocked on sending.
*/
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t blen, bool eos,
+ const void *buf, size_t blen,
size_t *pnwritten);
}
static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t len, bool eos, CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
RTMP *r = conn->proto.rtmp;
ssize_t num;
(void)sockindex; /* unused */
- (void)eos; /* unused */
num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
if(num < 0)
for(;;) {
/* Write the buffer to the socket */
- result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
+ result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
if(result)
break;
Curl_attach_connection(data, c);
sigpipe_ignore(data, &pipe_st);
- result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
+ result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, n);
sigpipe_restore(&pipe_st);
if(result && result != CURLE_AGAIN)
if(strlen(sel) < 1)
break;
- result = Curl_xfer_send(data, sel, k, FALSE, &amount);
+ result = Curl_xfer_send(data, sel, k, &amount);
if(!result) { /* Which may not have written it all! */
result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
if(result)
free(sel_org);
if(!result)
- result = Curl_xfer_send(data, "\r\n", 2, FALSE, &amount);
+ result = Curl_xfer_send(data, "\r\n", 2, &amount);
if(result) {
failf(data, "Failed sending Gopher request");
return result;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
if(data) {
- ssize_t nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf,
- buflen, FALSE, err);
+ ssize_t nwritten = Curl_conn_cf_send(cf->next, data,
+ (const char *)buf, buflen, err);
if(nwritten > 0)
CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
return nwritten;
}
static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
CF_DATA_SAVE(save, cf, data);
- (void)eos; /* TODO: use for stream EOF */
if(stream && stream->id != -1) {
if(stream->upload_blocked_len) {
/* the data in `buf` has already been submitted or added to the
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
- result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
+ result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
#ifdef HAVE_GSSAPI
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = data_sec;
size_t written;
while(len > 0) {
- result = Curl_conn_send(data, sockindex, to_p, len, FALSE, &written);
+ result = Curl_conn_send(data, sockindex, to_p, len, &written);
if(!result && written > 0) {
len -= written;
to_p += written;
/* Matches Curl_send signature */
static ssize_t sec_send(struct Curl_easy *data, int sockindex,
- const void *buffer, size_t len, bool eos,
- CURLcode *err)
+ const void *buffer, size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
curl_socket_t fd = conn->sock[sockindex];
- (void)eos; /* unused */
*err = CURLE_OK;
return sec_write(data, conn, fd, buffer, len);
}
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
size_t n;
- result = Curl_xfer_send(data, buf, len, FALSE, &n);
+ result = Curl_xfer_send(data, buf, len, &n);
if(result)
return result;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
if(conn) {
struct ldapconninfo *li = conn->proto.ldapc;
CURLcode err = CURLE_SEND_ERROR;
- ret = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &err);
+ ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
if(ret < 0 && err == CURLE_AGAIN) {
SET_SOCKERRNO(EWOULDBLOCK);
}
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
- result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, FALSE,
- &bytes_written);
+ result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, &bytes_written);
if(result == CURLE_AGAIN) {
bytes_written = 0;
}
result = Curl_conn_send(data, FIRSTSOCKET,
pp->sendthis + pp->sendsize - pp->sendleft,
- pp->sendleft, FALSE, &written);
+ pp->sendleft, &written);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
written = 0;
size_t hds_len, size_t *pnwritten)
{
CURLcode result = CURLE_OK;
- bool eos = FALSE;
*pnwritten = 0;
#ifdef DEBUGBUILD
blen = hds_len + (size_t)data->set.max_send_speed;
}
- if(data->req.eos_read &&
- (Curl_bufq_is_empty(&data->req.sendbuf) ||
- Curl_bufq_len(&data->req.sendbuf) == blen)) {
- DEBUGF(infof(data, "sending last upload chunk of %zu bytes", blen));
- eos = TRUE;
- }
- result = Curl_xfer_send(data, buf, blen, eos, pnwritten);
+ result = Curl_xfer_send(data, buf, blen, pnwritten);
if(!result && *pnwritten) {
if(hds_len)
Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
size_t bytes_written;
CURLcode result;
- result = Curl_xfer_send(data, smbc->send_buf, len, FALSE, &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, smbc->send_buf + smbc->sent, len, FALSE,
+ result = Curl_xfer_send(data, smbc->send_buf + smbc->sent, len,
&bytes_written);
if(result)
return result;
CURLcode result;
nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp,
- sx->outstanding, FALSE, &result);
+ sx->outstanding, &result);
if(nwritten <= 0) {
if(CURLE_AGAIN == result) {
return CURLPX_OK;
us_length = htons((unsigned short)gss_send_token.length);
memcpy(socksreq + 2, &us_length, sizeof(short));
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4,
- FALSE, &code);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != nwritten)) {
failf(data, "Failed to send GSS-API authentication request.");
gss_release_name(&gss_status, &server);
nwritten = Curl_conn_cf_send(cf->next, data,
(char *)gss_send_token.value,
- gss_send_token.length, FALSE, &code);
+ gss_send_token.length, &code);
if(code || ((ssize_t)gss_send_token.length != nwritten)) {
failf(data, "Failed to send GSS-API authentication token.");
gss_release_name(&gss_status, &server);
memcpy(socksreq + 2, &us_length, sizeof(short));
}
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
- &code);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != nwritten)) {
failf(data, "Failed to send GSS-API encryption request.");
gss_release_buffer(&gss_status, &gss_w_token);
if(data->set.socks5_gssapi_nec) {
memcpy(socksreq, &gss_enc, 1);
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
- &code);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
if(code || ( 1 != nwritten)) {
failf(data, "Failed to send GSS-API encryption type.");
gss_delete_sec_context(&gss_status, &gss_context, NULL);
else {
nwritten = Curl_conn_cf_send(cf->next, data,
(char *)gss_w_token.value,
- gss_w_token.length, FALSE, &code);
+ gss_w_token.length, &code);
if(code || ((ssize_t)gss_w_token.length != nwritten)) {
failf(data, "Failed to send GSS-API encryption type.");
gss_release_buffer(&gss_status, &gss_w_token);
us_length = htons((unsigned short)sspi_send_token.cbBuffer);
memcpy(socksreq + 2, &us_length, sizeof(short));
- written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
- &code);
+ written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != written)) {
failf(data, "Failed to send SSPI authentication request.");
free(service_name);
written = Curl_conn_cf_send(cf->next, data,
(char *)sspi_send_token.pvBuffer,
- sspi_send_token.cbBuffer, FALSE, &code);
+ sspi_send_token.cbBuffer, &code);
if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
failf(data, "Failed to send SSPI authentication token.");
free(service_name);
memcpy(socksreq + 2, &us_length, sizeof(short));
}
- written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
- &code);
+ written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != written)) {
failf(data, "Failed to send SSPI encryption request.");
if(sspi_send_token.pvBuffer)
if(data->set.socks5_gssapi_nec) {
memcpy(socksreq, &gss_enc, 1);
- written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
- &code);
+ written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
if(code || (1 != written)) {
failf(data, "Failed to send SSPI encryption type.");
s_pSecFn->DeleteSecurityContext(&sspi_context);
else {
written = Curl_conn_cf_send(cf->next, data,
(char *)sspi_send_token.pvBuffer,
- sspi_send_token.cbBuffer, FALSE, &code);
+ sspi_send_token.cbBuffer, &code);
if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
failf(data, "Failed to send SSPI encryption type.");
if(sspi_send_token.pvBuffer)
default: /* write! */
bytes_written = 0;
result = Curl_xfer_send(data, outbuf + total_written,
- outlen - total_written, FALSE, &bytes_written);
+ outlen - total_written, &bytes_written);
total_written += bytes_written;
break;
}
}
CURLcode Curl_xfer_send(struct Curl_easy *data,
- const void *buf, size_t blen, bool eos,
+ const void *buf, size_t blen,
size_t *pnwritten)
{
CURLcode result;
} */
sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
(data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- result = Curl_conn_send(data, sockindex, buf, blen, eos, pnwritten);
+ result = Curl_conn_send(data, sockindex, buf, blen, pnwritten);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
*pnwritten = 0;
* Will return CURLE_OK on blocking with (*pnwritten == 0).
*/
CURLcode Curl_xfer_send(struct Curl_easy *data,
- const void *buf, size_t blen, bool eos,
+ const void *buf, size_t blen,
size_t *pnwritten);
/**
int sockindex, /* socketindex */
const void *buf, /* data to write */
size_t len, /* max amount to write */
- bool eos, /* last chunk */
CURLcode *err); /* error to return */
/* return the count of bytes read, or -1 on error */
}
static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
size_t nheader, i;
ssize_t nwritten = -1;
struct cf_call_data save;
+ bool eos;
CF_DATA_SAVE(save, cf, data);
nva[i].ValueLength = e->valuelen;
}
+ switch(data->state.httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ case HTTPREQ_PUT:
+ /* known request body size or -1 */
+ eos = FALSE;
+ break;
+ default:
+ /* there is not request body */
+ eos = TRUE;
+ stream->upload_done = TRUE;
+ break;
+ }
+
CURL_TRC_CF(data, cf, "req: send %zu headers", nheader);
stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
nva, nheader,
}
static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
pktx_init(&pktx, cf, data);
*err = CURLE_OK;
- (void)eos; /* TODO: use for stream EOF and block handling */
result = cf_progress_ingress(cf, data, &pktx);
if(result) {
*err = result;
}
static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_osslq_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nwritten;
CURLcode result;
- (void)eos; /* TODO: use to end stream */
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
DEBUGASSERT(ctx->tls.ossl.ssl);
struct bufq recvbuf; /* h3 response */
struct h1_req_parser h1; /* h1 request parsing */
curl_uint64_t error3; /* HTTP/3 stream error code */
+ curl_off_t upload_left; /* number of request bytes left to upload */
BIT(opened); /* TRUE after stream has been opened */
BIT(closed); /* TRUE on stream close */
BIT(reset); /* TRUE on stream reset */
(void)cf;
bits = CURL_CSELECT_IN;
- if(stream && !stream->send_closed)
+ if(stream && !stream->send_closed && stream->upload_left)
bits |= CURL_CSELECT_OUT;
if(data->state.select_bits != bits) {
data->state.select_bits = bits;
return nread;
}
-static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct stream_ctx *stream,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
-{
- struct cf_quiche_ctx *ctx = cf->ctx;
- ssize_t nwritten;
-
- nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
- (uint8_t *)buf, len, eos);
- if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
- /* TODO: we seem to be blocked on flow control and should HOLD
- * sending. But when do we open again? */
- if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> window exhausted", stream->id, len);
- stream->quic_flow_blocked = TRUE;
- }
- *err = CURLE_AGAIN;
- return -1;
- }
- else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> invalid stream state", stream->id, len);
- *err = CURLE_HTTP3;
- return -1;
- }
- else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> exceeds size", stream->id, len);
- *err = CURLE_SEND_ERROR;
- return -1;
- }
- else if(nwritten < 0) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> quiche err %zd", stream->id, len, nwritten);
- *err = CURLE_SEND_ERROR;
- return -1;
- }
- else {
- if(eos && (len == (size_t)nwritten))
- stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send body(len=%zu, "
- "eos=%d) -> %zd",
- stream->id, len, stream->send_closed, nwritten);
- *err = CURLE_OK;
- return nwritten;
- }
-}
-
/* Index where :authority header field will appear in request header
field list. */
#define AUTHORITY_DST_IDX 3
static ssize_t h3_open_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const char *buf, size_t len, bool eos,
+ const void *buf, size_t len,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
nva[i].value_len = e->valuelen;
}
- if(eos && ((size_t)nwritten == len))
+ switch(data->state.httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ case HTTPREQ_PUT:
+ if(data->state.infilesize != -1)
+ stream->upload_left = data->state.infilesize;
+ else
+ /* data sending without specifying the data amount up front */
+ stream->upload_left = -1; /* unknown */
+ break;
+ default:
+ stream->upload_left = 0; /* no request body */
+ break;
+ }
+
+ if(stream->upload_left == 0)
stream->send_closed = TRUE;
stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader,
}
}
- if(nwritten > 0 && ((size_t)nwritten < len)) {
- /* after the headers, there was request BODY data */
- size_t hds_len = (size_t)nwritten;
- ssize_t bwritten;
-
- bwritten = cf_quiche_send_body(cf, data, stream,
- buf + hds_len, len - hds_len, eos, err);
- if((bwritten < 0) && (CURLE_AGAIN != *err)) {
- /* real error, fail */
- nwritten = -1;
- }
- else if(bwritten > 0) {
- nwritten += bwritten;
- }
- }
-
out:
free(nva);
Curl_dynhds_free(&h2_headers);
}
static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
}
if(!stream || !stream->opened) {
- nwritten = h3_open_stream(cf, data, buf, len, eos, err);
+ nwritten = h3_open_stream(cf, data, buf, len, err);
if(nwritten < 0)
goto out;
stream = H3_STREAM_CTX(ctx, data);
goto out;
}
else {
- nwritten = cf_quiche_send_body(cf, data, stream, buf, len, eos, err);
+ bool eof = (stream->upload_left >= 0 &&
+ (curl_off_t)len >= stream->upload_left);
+ nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
+ (uint8_t *)buf, len, eof);
+ if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
+ /* TODO: we seem to be blocked on flow control and should HOLD
+ * sending. But when do we open again? */
+ if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
+ "-> window exhausted", stream->id, len);
+ stream->quic_flow_blocked = TRUE;
+ }
+ *err = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
+ "-> invalid stream state", stream->id, len);
+ *err = CURLE_HTTP3;
+ nwritten = -1;
+ goto out;
+ }
+ else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
+ "-> exceeds size", stream->id, len);
+ *err = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
+ }
+ else if(nwritten < 0) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
+ "-> quiche err %zd", stream->id, len, nwritten);
+ *err = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
+ }
+ else {
+ /* quiche accepted all or at least a part of the buf */
+ if(stream->upload_left > 0) {
+ stream->upload_left = (nwritten < stream->upload_left)?
+ (stream->upload_left - nwritten) : 0;
+ }
+ if(stream->upload_left == 0)
+ stream->send_closed = TRUE;
+
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send body(len=%zu, "
+ "left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd",
+ stream->id, len, stream->upload_left, nwritten);
+ *err = CURLE_OK;
+ }
}
out:
nwritten = -1;
}
CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
+ stream? stream->id : (uint64_t)~0, len, nwritten, *err);
return nwritten;
}
ssize_t sent;
stream->send_closed = TRUE;
+ stream->upload_left = 0;
body[0] = 'X';
- sent = cf_quiche_send(cf, data, body, 0, TRUE, &result);
+ sent = cf_quiche_send(cf, data, body, 0, &result);
CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] DONE_SEND -> %zd, %d",
stream->id, sent, result);
}
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
int rc;
struct connectdata *conn = data->conn;
(void) sockindex; /* we only support SCP on the fixed known primary socket */
(void) err;
- (void)eos;
rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
/* return number of sent bytes */
static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos,
- CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
(void)sockindex;
- (void)eos;
/* limit the writes to the maximum specified in Section 3 of
* https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
/* swap in the TLS writer function for this call only, and then swap back
the SSH one again */
conn->send[0] = ssh->tls_send;
- result = Curl_conn_send(data, socknum, buffer, length, FALSE, &nwrite);
+ result = Curl_conn_send(data, socknum, buffer, length, &nwrite);
conn->send[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex; /* we only support SCP on the fixed known primary socket */
- (void)eos;
/* libssh2_channel_write() returns int! */
nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
/* return number of sent bytes */
static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex;
- (void)eos;
nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
return CURLE_OK;
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
- ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, FALSE,
- &result);
+ ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
if(ret <= 0) {
if(result == CURLE_AGAIN)
CURLcode result;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
blen, nwritten, result);
backend->gtls.io_result = result;
if(!data)
return 0;
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, FALSE,
- &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d",
blen, nwritten, result);
if(nwritten < 0 && CURLE_AGAIN == result) {
if(blen < 0)
return 0;
- nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, FALSE,
- &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, &result);
CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
blen, (int)nwritten, result);
BIO_clear_retry_flags(bio);
CURLcode result;
int ret = 0;
ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
- (const char *)buf, len, FALSE,
- &result);
+ (const char *)buf, len, &result);
if(nwritten < 0) {
nwritten = 0;
if(CURLE_AGAIN == result)
/* send initial handshake data which is now stored in output buffer */
written = Curl_conn_cf_send(cf->next, data,
- outbuf.pvBuffer, outbuf.cbBuffer, FALSE,
+ outbuf.pvBuffer, outbuf.cbBuffer,
&result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
/* send handshake token to server */
written = Curl_conn_cf_send(cf->next, data,
outbuf[i].pvBuffer, outbuf[i].cbBuffer,
- FALSE, &result);
+ &result);
if((result != CURLE_OK) ||
(outbuf[i].cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send next handshake data: "
this_write = Curl_conn_cf_send(cf->next, data,
ptr + written, len - written,
- FALSE, &result);
+ &result);
if(result == CURLE_AGAIN)
continue;
else if(result != CURLE_OK) {
/* send close message which is in output buffer */
ssize_t written = Curl_conn_cf_send(cf->next, data,
outbuf.pvBuffer, outbuf.cbBuffer,
- FALSE, &result);
+ &result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if(!result) {
if(written < (ssize_t)outbuf.cbBuffer) {
OSStatus rtn = noErr;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, FALSE,
- &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
*dataLength, nwritten, result);
if(nwritten <= 0) {
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
struct Curl_easy *data, const void *buf, size_t len,
- bool eos, CURLcode *err)
+ CURLcode *err)
{
struct cf_call_data save;
ssize_t nwritten;
- (void)eos; /* unused */
CF_DATA_SAVE(save, cf, data);
*err = CURLE_OK;
nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
backend->io_result = result;
CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
blen, nwritten, result);
if(data->set.connect_only)
result = Curl_senddata(data, out, outlen, &n);
else {
- result = Curl_xfer_send(data, out, outlen, FALSE, &n);
+ result = Curl_xfer_send(data, out, outlen, &n);
if(!result && !n && outlen)
result = CURLE_AGAIN;
}
/* raw mode sends exactly what was requested, and this is from within
the write callback */
if(Curl_is_in_callback(data)) {
- result = Curl_xfer_send(data, buffer, buflen, FALSE, &nwritten);
+ result = Curl_xfer_send(data, buffer, buflen, &nwritten);
}
else
result = Curl_senddata(data, buffer, buflen, &nwritten);