DEBUGASSERT(blen >= nwritten);
ts->nsent += nwritten;
- Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten);
+ Curl_debug(data, CURLINFO_HEADER_OUT, buf, nwritten);
out:
if(result)
#endif
}
/* tunnel.recbuf has soft limit, any success MUST add all data */
- DEBUGASSERT((size_t)nwritten == len);
+ DEBUGASSERT(nwritten == len);
return 0;
}
# pragma warning(pop)
#endif
}
+
+size_t curlx_uitouz(unsigned int uinum)
+{
+ return (size_t)uinum;
+}
+
+size_t curlx_sotouz_range(curl_off_t sonum, size_t uzmin, size_t uzmax)
+{
+ if(sonum < 0)
+ return uzmin;
+#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
+ if(sonum > SIZE_MAX)
+ return uzmax;
+#endif
+ return CURLMIN(CURLMAX((size_t)sonum, uzmin), uzmax);
+}
+
+bool curlx_sztouz(ssize_t sznum, size_t *puznum)
+{
+ if(sznum < 0) {
+ *puznum = 0;
+ return FALSE;
+ }
+ *puznum = (size_t)sznum;
+ return TRUE;
+}
+
+curl_off_t curlx_uztoso(size_t uznum)
+{
+#if SIZEOF_SIZE_T >= SIZEOF_CURL_OFF_T
+ if(uznum > (size_t)CURL_OFF_T_MAX)
+ return CURL_OFF_T_MAX;
+#endif
+ return (curl_off_t)uznum;
+}
size_t curlx_sitouz(int sinum);
+size_t curlx_uitouz(unsigned int uinum);
+
+/* Convert a curl_off_t to fit into size_t interval [uzmin, uzmax].
+ * values outside this interval give the lower/upper bound. */
+size_t curlx_sotouz_range(curl_off_t sonum, size_t uzmin, size_t uzmax);
+
+/* Convert a size_t to curl_off_t, return CURL_OFF_T_MAX if too large. */
+curl_off_t curlx_uztoso(size_t uznum);
+
+/* Convert a ssize_t to size_t, return FALSE if negative and set 0 */
+bool curlx_sztouz(ssize_t sznum, size_t *puznum);
+
#ifdef _WIN32
#undef read
#define read(fd, buf, count) (ssize_t)_read(fd, buf, curlx_uztoui(count))
if(result)
break;
- Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
+ Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written);
- if((size_t)bytes_written != write_len) {
+ if(bytes_written != write_len) {
/* if not all was written at once, we must advance the pointer, decrease
the size left and try again! */
write_len -= bytes_written;
result = Curl_creader_set_null(data);
}
else if(data->set.postfields) {
- if(postsize > 0)
- result = Curl_creader_set_buf(data, data->set.postfields,
- (size_t)postsize);
+ size_t plen = curlx_sotouz_range(postsize, 0, SIZE_MAX);
+ if(plen == SIZE_MAX)
+ return CURLE_OUT_OF_MEMORY;
+ else if(plen)
+ result = Curl_creader_set_buf(data, data->set.postfields, plen);
else
result = Curl_creader_set_null(data);
}
#include "curlx/strparse.h"
#include "transfer.h"
#include "curlx/dynbuf.h"
+#include "curlx/warnless.h"
#include "headers.h"
/* The last 3 #include files should be in this order */
* in the H1 request and we upgrade from there. This stream
* is opened implicitly as #1. */
uint8_t binsettings[H2_BINSETTINGS_LEN];
- ssize_t binlen; /* length of the binsettings data */
+ ssize_t rclen;
+ size_t binlen; /* length of the binsettings data */
- binlen = populate_binsettings(binsettings, data);
- if(binlen <= 0) {
+ rclen = populate_binsettings(binsettings, data);
+
+ if(!curlx_sztouz(rclen, &binlen) || !binlen) {
failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
result = CURLE_FAILED_INIT;
goto out;
DEBUGASSERT(stream);
stream->id = 1;
/* queue SETTINGS frame (again) */
- rc = nghttp2_session_upgrade2(ctx->h2, binsettings, (size_t)binlen,
+ rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
data->state.httpreq == HTTPREQ_HEAD,
NULL);
if(rc) {
{
struct cf_h2_ctx *ctx = cf->ctx;
const unsigned char *buf;
- size_t blen;
+ size_t blen, nread;
ssize_t rv;
while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) {
rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
- if(rv < 0) {
+ if(!curlx_sztouz(rv, &nread)) {
failf(data, "nghttp2 recv error %zd: %s", rv, nghttp2_strerror((int)rv));
return CURLE_HTTP2;
}
- Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
+ Curl_bufq_skip(&ctx->inbufq, nread);
if(Curl_bufq_is_empty(&ctx->inbufq)) {
break;
}
size_t blen;
struct SingleRequest *k = &data->req;
uint8_t binsettings[H2_BINSETTINGS_LEN];
- ssize_t binlen; /* length of the binsettings data */
+ ssize_t rc;
+ size_t binlen; /* length of the binsettings data */
- binlen = populate_binsettings(binsettings, data);
- if(binlen <= 0) {
+ rc = populate_binsettings(binsettings, data);
+ if(!curlx_sztouz(rc, &binlen) || !binlen) {
failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
curlx_dyn_free(req);
return CURLE_FAILED_INIT;
}
- result = curlx_base64url_encode((const char *)binsettings, (size_t)binlen,
+ result = curlx_base64url_encode((const char *)binsettings, binlen,
&base64, &blen);
if(result) {
curlx_dyn_free(req);
return result;
}
-static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- const void *buf, size_t blen, bool eos,
- CURLcode *err)
+static CURLcode cf_h2_body_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct h2_stream_ctx *stream,
+ const void *buf, size_t blen, bool eos,
+ size_t *pnwritten)
{
struct cf_h2_ctx *ctx = cf->ctx;
- size_t nwritten;
+ CURLcode result;
+ *pnwritten = 0;
if(stream->closed) {
if(stream->resp_hds_complete) {
/* Server decided to close the stream after having sent us a final
"on closed stream with response", stream->id);
if(eos)
stream->body_eos = TRUE;
- *err = CURLE_OK;
- return (ssize_t)blen;
+ *pnwritten = blen;
+ return CURLE_OK;
}
/* Server closed before we got a response, this is an error */
infof(data, "stream %u closed", stream->id);
- *err = CURLE_SEND_ERROR;
- return -1;
+ return CURLE_SEND_ERROR;
}
- *err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten);
- if(*err)
- return -1;
+ result = Curl_bufq_write(&stream->sendbuf, buf, blen, pnwritten);
+ if(result)
+ return result;
- if(eos && (blen == nwritten))
+ if(eos && (blen == *pnwritten))
stream->body_eos = TRUE;
if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
/* resume the potentially suspended stream */
int rv = nghttp2_session_resume_data(ctx->h2, stream->id);
- if(nghttp2_is_fatal(rv)) {
- *err = CURLE_SEND_ERROR;
- return -1;
- }
+ if(nghttp2_is_fatal(rv))
+ return CURLE_SEND_ERROR;
}
- return (ssize_t)nwritten;
+
+ return CURLE_OK;
}
static CURLcode h2_submit(struct h2_stream_ctx **pstream,
nghttp2_data_provider data_prd;
int32_t stream_id;
nghttp2_priority_spec pri_spec;
- ssize_t nwritten;
+ ssize_t rc;
+ size_t nwritten;
CURLcode result = CURLE_OK;
*pnwritten = 0;
if(result)
goto out;
- nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
- if(nwritten < 0)
+ rc = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
+ if(!curlx_sztouz(rc, &nwritten))
goto out;
- *pnwritten = (size_t)nwritten;
+ *pnwritten = nwritten;
if(!stream->h1.done) {
/* need more data */
goto out;
bodylen = len - *pnwritten;
if(bodylen || eos) {
- ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &result);
- if(n >= 0)
+ size_t n;
+ result = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &n);
+ if(!result)
*pnwritten += n;
else if(result == CURLE_AGAIN)
result = CURLE_OK;
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save;
- ssize_t nwritten;
CURLcode result = CURLE_OK, r2;
CF_DATA_SAVE(save, cf, data);
* being able to flush stream->sendbuf. Make a 0-length write
* to trigger flushing again.
* If this works, we report to have written `len` bytes. */
+ size_t n;
DEBUGASSERT(eos);
- nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, &result);
- CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d",
- stream->id, nwritten, result, eos);
- if(nwritten < 0) {
+ result = cf_h2_body_send(cf, data, stream, buf, 0, eos, &n);
+ CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %d, %zu, eos=%d",
+ stream->id, result, n, eos);
+ if(result)
goto out;
- }
*pnwritten = len;
}
else {
- nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, &result);
- CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d",
- stream->id, len, nwritten, result, eos);
- if(nwritten >= 0)
- *pnwritten = (size_t)nwritten;
+ result = cf_h2_body_send(cf, data, stream, buf, len, eos, pnwritten);
+ CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %d, %zu, eos=%d",
+ stream->id, len, result, *pnwritten, eos);
}
/* Call the nghttp2 send loop and flush to write ALL buffered data,
}
if(!data->multi->xfer_buf) {
- data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
+ data->multi->xfer_buf = malloc(curlx_uitouz(data->set.buffer_size));
if(!data->multi->xfer_buf) {
- failf(data, "could not allocate xfer_buf of %zu bytes",
- (size_t)data->set.buffer_size);
+ failf(data, "could not allocate xfer_buf of %u bytes",
+ data->set.buffer_size);
return CURLE_OUT_OF_MEMORY;
}
data->multi->xfer_buf_len = data->set.buffer_size;
}
if(!data->multi->xfer_ulbuf) {
- data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
+ data->multi->xfer_ulbuf =
+ malloc(curlx_uitouz(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);
+ failf(data, "could not allocate xfer_ulbuf of %u bytes",
+ data->set.upload_buffer_size);
return CURLE_OUT_OF_MEMORY;
}
data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
{
if(limit != -1) {
/* How much more are we allowed to write? */
- curl_off_t remain_diff;
- remain_diff = limit - data->req.bytecount;
- if(remain_diff < 0) {
- /* already written too much! */
- return 0;
- }
-#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
- else if(remain_diff > SSIZE_MAX) {
- return SIZE_MAX;
- }
-#endif
- else {
- return (size_t)remain_diff;
- }
+ return curlx_sotouz_range(limit - data->req.bytecount, 0, SIZE_MAX);
}
return SIZE_MAX;
}
}
/* respect length limitations */
if(ctx->total_len >= 0) {
- curl_off_t remain = ctx->total_len - ctx->read_len;
- if(remain <= 0)
- blen = 0;
- else if(remain < (curl_off_t)blen)
- blen = (size_t)remain;
+ blen = curlx_sotouz_range(ctx->total_len - ctx->read_len, 0, blen);
}
nread = 0;
if(ctx->read_cb && blen) {
/* already started reading? */
if(ctx->index)
return CURLE_READ_ERROR;
- if(offset <= 0)
+ boffset = curlx_sotouz_range(offset, 0, SIZE_MAX);
+ if(!boffset)
return CURLE_OK;
- boffset = (size_t)offset;
if(boffset > ctx->blen)
return CURLE_READ_ERROR;
if(!ptr || s->postfieldsize == -1)
result = Curl_setstropt(&s->str[STRING_COPYPOSTFIELDS], ptr);
else {
+ size_t pflen;
+
if(s->postfieldsize < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
-#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
- /*
- * Check that requested length does not overflow the size_t type.
- */
- else if(s->postfieldsize > SIZE_MAX)
+ pflen = curlx_sotouz_range(s->postfieldsize, 0, SIZE_MAX);
+ if(pflen == SIZE_MAX)
return CURLE_OUT_OF_MEMORY;
-#endif
else {
/* Allocate even when size == 0. This satisfies the need of possible
later address compare to detect the COPYPOSTFIELDS mode, and to
mark that postfields is used rather than read function or form
data.
*/
- char *p = Curl_memdup0(ptr, (size_t)s->postfieldsize);
+ char *p = Curl_memdup0(ptr, pflen);
if(!p)
return CURLE_OUT_OF_MEMORY;
else {
#include "hsts.h"
#include "setopt.h"
#include "headers.h"
+#include "curlx/warnless.h"
/* The last 2 #include files should be in this order */
#include "curl_memory.h"
* @param err error code in case of -1 return
* @return number of bytes read or -1 for error
*/
-static ssize_t xfer_recv_resp(struct Curl_easy *data,
- char *buf, size_t blen,
- bool eos_reliable,
- CURLcode *err)
+static CURLcode xfer_recv_resp(struct Curl_easy *data,
+ char *buf, size_t blen,
+ bool eos_reliable,
+ size_t *pnread)
{
- size_t nread;
+ CURLcode result;
DEBUGASSERT(blen > 0);
+ *pnread = 0;
/* If we are reading BODY data and the connection does NOT handle EOF
* and we know the size of the BODY data, limit the read amount */
if(!eos_reliable && !data->req.header && data->req.size != -1) {
- curl_off_t totalleft = data->req.size - data->req.bytecount;
- if(totalleft <= 0)
- blen = 0;
- else if(totalleft < (curl_off_t)blen)
- blen = (size_t)totalleft;
+ blen = curlx_sotouz_range(data->req.size - data->req.bytecount, 0, blen);
}
else if(xfer_recv_shutdown_started(data)) {
/* we already received everything. Do not try more. */
blen = 0;
}
- if(!blen) {
- /* want nothing more */
- *err = CURLE_OK;
- nread = 0;
- }
- else {
- *err = Curl_xfer_recv(data, buf, blen, &nread);
+ if(blen) {
+ result = Curl_xfer_recv(data, buf, blen, pnread);
+ if(result)
+ return result;
}
- if(*err)
- return -1;
- if(nread == 0) {
+ if(*pnread == 0) {
if(data->req.shutdown) {
bool done;
- *err = xfer_recv_shutdown(data, &done);
- if(*err)
- return -1;
+ result = xfer_recv_shutdown(data, &done);
+ if(result)
+ return result;
if(!done) {
- *err = CURLE_AGAIN;
- return -1;
+ return CURLE_AGAIN;
}
}
DEBUGF(infof(data, "sendrecv_dl: we are done"));
}
- return (ssize_t)nread;
+ return CURLE_OK;
}
/*
read or we get a CURLE_AGAIN */
do {
size_t bytestoread;
- ssize_t nread;
if(!is_multiplex) {
/* Multiplexed connection have inherent handling of EOF and we do not
}
rcvd_eagain = FALSE;
- nread = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result);
- if(nread < 0) {
- if(CURLE_AGAIN != result)
+ result = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &blen);
+ if(result) {
+ if(result != CURLE_AGAIN)
goto out; /* real error */
rcvd_eagain = TRUE;
result = CURLE_OK;
!data->req.resp_trailer) {
DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, "
"not waiting for EOS"));
- nread = 0;
+ blen = 0;
/* continue as if we received the EOS */
}
else
}
/* We only get a 0-length receive at the end of the response */
- blen = (size_t)nread;
is_eos = (blen == 0);
if(!blen && (conn->recv[FIRSTSOCKET] == Curl_cf_recv)) {
DEBUGASSERT(data->conn);
DEBUGASSERT(data->set.buffer_size > 0);
- if((size_t)data->set.buffer_size < blen)
- blen = (size_t)data->set.buffer_size;
+ if(curlx_uitouz(data->set.buffer_size) < blen)
+ blen = curlx_uitouz(data->set.buffer_size);
return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd);
}
return CURLE_OK;
}
-static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
+static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h3_stream_ctx *stream,
- CURLcode *err)
+ size_t *pnread)
{
- ssize_t nread = -1;
-
(void)cf;
+ *pnread = 0;
if(stream->reset) {
failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
- *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
- goto out;
+ return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
}
else if(!stream->resp_hds_complete) {
failf(data,
"HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
"getting all response header fields, treated as error",
stream->id);
- *err = CURLE_HTTP3;
- goto out;
+ return CURLE_HTTP3;
}
- *err = CURLE_OK;
- nread = 0;
-
-out:
- return nread;
+ return CURLE_OK;
}
/* incoming data frames on the h3 stream */
goto out;
}
else if(stream->closed) {
- ssize_t nread = recv_closed_stream(cf, data, stream, &result);
- if(nread > 0)
- *pnread = (size_t)nread;
+ result = recv_closed_stream(cf, data, stream, pnread);
goto out;
}
result = CURLE_AGAIN;
#include "select.h"
#include "curlx/nonblock.h"
#include "curlx/strparse.h"
+#include "curlx/warnless.h"
/* The last 2 #include files should be in this order */
#include "curl_memory.h"
size_t inlen;
size_t nwritten;
CURLcode result;
- curl_off_t remain = dec->payload_len - dec->payload_offset;
+ size_t remain = curlx_sotouz_range(dec->payload_len - dec->payload_offset,
+ 0, SIZE_MAX);
(void)data;
while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) {
- if((curl_off_t)inlen > remain)
- inlen = (size_t)remain;
+ if(inlen > remain)
+ inlen = remain;
result = write_cb(inbuf, inlen, dec->frame_age, dec->frame_flags,
dec->payload_offset, dec->payload_len,
write_ctx, &nwritten);
return result;
Curl_bufq_skip(inraw, nwritten);
dec->payload_offset += nwritten;
- remain = dec->payload_len - dec->payload_offset;
- CURL_TRC_WS(data, "passed %zu bytes payload, %"
- FMT_OFF_T " remain", nwritten, remain);
+ remain = curlx_sotouz_range(dec->payload_len - dec->payload_offset,
+ 0, SIZE_MAX);
+ CURL_TRC_WS(data, "passed %zu bytes payload, %zu remain",
+ nwritten, remain);
}
return remain ? CURLE_AGAIN : CURLE_OK;
curl_off_t payload_offset,
size_t payload_buffered)
{
- curl_off_t remain = payload_total - payload_offset;
+ curl_off_t buffered, remain = payload_total - payload_offset;
if((payload_total < 0) || (payload_offset < 0) || (remain < 0))
return -1;
-#if SIZEOF_SIZE_T >= SIZEOF_CURL_OFF_T
- if(payload_buffered > (size_t)CURL_OFF_T_MAX)
+ buffered = curlx_uztoso(payload_buffered);
+ if(remain < buffered)
return -1;
-#endif
- if(remain < (curl_off_t)payload_buffered)
- return -1;
- return remain - (curl_off_t)payload_buffered;
+ return remain - buffered;
}
static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen,
struct bufq *out, size_t *pnwritten)
{
CURLcode result;
- size_t i, len, n;
+ size_t i, len, n, remain;
*pnwritten = 0;
if(Curl_bufq_is_full(out))
/* not the most performant way to do this */
len = buflen;
- if((curl_off_t)len > enc->payload_remain)
- len = (size_t)enc->payload_remain;
+ remain = curlx_sotouz_range(enc->payload_remain, 0, SIZE_MAX);
+ if(remain < len)
+ len = remain;
for(i = 0; i < len; ++i) {
unsigned char c = buf[i] ^ enc->mask[enc->xori];
if(ws->enc.payload_remain) {
CURL_TRC_WS(data, "current frame, %" FMT_OFF_T " remaining",
ws->enc.payload_remain);
- if(ws->enc.payload_remain < (curl_off_t)blen)
- blen = (size_t)ws->enc.payload_remain;
+ blen = curlx_sotouz_range(ws->enc.payload_remain, 0, blen);
}
result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);