#include "strcase.h"
#include "connect.h"
#include "strerror.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
return 0;
}
-/* Minimum size of the overflow buffer */
-#define OVERFLOWSIZE 1024
-
-/*
- * allocate_overflow() ensures that there is room for incoming data in the
- * overflow buffer, growing it to accommodate the new data if necessary. We
- * may need to use the overflow buffer because we can't precisely limit the
- * amount of HTTP/3 header data we receive using QUIC flow control mechanisms.
- */
-static CURLcode allocate_overflow(struct Curl_easy *data,
- struct HTTP *stream,
- size_t length)
-{
- size_t maxleft;
- size_t newsize;
- /* length can be arbitrarily large, so take care not to overflow newsize */
- maxleft = CURL_MAX_READ_SIZE - stream->overflow_buflen;
- if(length > maxleft) {
- /* The reason to have a max limit for this is to avoid the risk of a bad
- server feeding libcurl with a highly compressed list of headers that
- will cause our overflow buffer to grow too large */
- failf(data, "Rejected %zu bytes of overflow data (max is %d)!",
- stream->overflow_buflen + length, CURL_MAX_READ_SIZE);
- return CURLE_OUT_OF_MEMORY;
- }
- newsize = stream->overflow_buflen + length;
- if(newsize > stream->overflow_bufsize) {
- /* We enlarge the overflow buffer as it is too small */
- char *newbuff;
- newsize = CURLMAX(newsize * 3 / 2, stream->overflow_bufsize*2);
- newsize = CURLMIN(CURLMAX(OVERFLOWSIZE, newsize), CURL_MAX_READ_SIZE);
- newbuff = realloc(stream->overflow_buf, newsize);
- if(!newbuff) {
- failf(data, "Failed to alloc memory for overflow buffer!");
- return CURLE_OUT_OF_MEMORY;
- }
- stream->overflow_buf = newbuff;
- stream->overflow_bufsize = newsize;
- infof(data, "Grew HTTP/3 overflow buffer to %zu bytes\n", newsize);
- }
- return CURLE_OK;
-}
-
/*
* write_data() copies data to the stream's receive buffer. If not enough
* space is available in the receive buffer, it copies the rest to the
* stream's overflow buffer.
*/
-static CURLcode write_data(struct Curl_easy *data,
- struct HTTP *stream,
- const void *mem, size_t memlen)
+static CURLcode write_data(struct HTTP *stream, const void *mem, size_t memlen)
{
CURLcode result = CURLE_OK;
const char *buf = mem;
/* copy as much as possible to the receive buffer */
if(stream->len) {
size_t len = CURLMIN(ncopy, stream->len);
-#if 0 /* extra debugging of incoming h3 data */
- fprintf(stderr, "!! Copies %zd bytes to %p (total %zd)\n",
- len, stream->mem, stream->memlen);
-#endif
memcpy(stream->mem, buf, len);
stream->len -= len;
stream->memlen += len;
ncopy -= len;
}
/* copy the rest to the overflow buffer */
- if(ncopy) {
- result = allocate_overflow(data, stream, ncopy);
- if(result) {
- return result;
- }
-#if 0 /* extra debugging of incoming h3 data */
- fprintf(stderr, "!! Copies %zd overflow bytes to %p (total %zd)\n",
- ncopy, stream->overflow_buf, stream->overflow_buflen);
-#endif
- memcpy(stream->overflow_buf + stream->overflow_buflen, buf, ncopy);
- stream->overflow_buflen += ncopy;
- }
-#if 0 /* extra debugging of incoming h3 data */
- {
- size_t i;
- for(i = 0; i < memlen; i++) {
- fprintf(stderr, "!! data[%d]: %02x '%c'\n", i, buf[i], buf[i]);
- }
- }
-#endif
+ if(ncopy)
+ result = Curl_dyn_addn(&stream->overflow, buf, ncopy);
return result;
}
CURLcode result = CURLE_OK;
(void)conn;
- result = write_data(data, stream, buf, buflen);
+ result = write_data(stream, buf, buflen);
if(result) {
return -1;
}
/* add a CRLF only if we've received some headers */
if(stream->firstheader) {
- result = write_data(data, stream, "\r\n", 2);
+ result = write_data(stream, "\r\n", 2);
if(result) {
return -1;
}
int status = decode_status_code(h3val.base, h3val.len);
DEBUGASSERT(status != -1);
ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status);
- result = write_data(data, stream, line, ncopy);
+ result = write_data(stream, line, ncopy);
if(result) {
return -1;
}
}
else {
/* store as a HTTP1-style header */
- result = write_data(data, stream, h3name.base, h3name.len);
+ result = write_data(stream, h3name.base, h3name.len);
if(result) {
return -1;
}
- result = write_data(data, stream, ": ", 2);
+ result = write_data(stream, ": ", 2);
if(result) {
return -1;
}
- result = write_data(data, stream, h3val.base, h3val.len);
+ result = write_data(stream, h3val.base, h3val.len);
if(result) {
return -1;
}
- result = write_data(data, stream, "\r\n", 2);
+ result = write_data(stream, "\r\n", 2);
if(result) {
return -1;
}
static size_t drain_overflow_buffer(struct HTTP *stream)
{
- size_t ncopy = CURLMIN(stream->overflow_buflen, stream->len);
+ size_t overlen = Curl_dyn_len(&stream->overflow);
+ size_t ncopy = CURLMIN(overlen, stream->len);
if(ncopy > 0) {
- memcpy(stream->mem, stream->overflow_buf, ncopy);
+ memcpy(stream->mem, Curl_dyn_ptr(&stream->overflow), ncopy);
stream->len -= ncopy;
stream->mem += ncopy;
stream->memlen += ncopy;
- stream->overflow_buflen -= ncopy;
- memmove(stream->overflow_buf, stream->overflow_buf + ncopy,
- stream->overflow_buflen);
+ if(ncopy != overlen)
+ /* make the buffer only keep the tail */
+ (void)Curl_dyn_tail(&stream->overflow, overlen - ncopy);
}
return ncopy;
}
stream->stream3_id = stream3_id;
stream->h3req = TRUE; /* senf off! */
+ Curl_dyn_init(&stream->overflow, CURL_MAX_READ_SIZE);
/* Calculate number of headers contained in [mem, mem + len). Assumes a
correctly generated HTTP header field block. */
if(data->conn->handler == &Curl_handler_http3) {
/* only for HTTP/3 transfers */
struct HTTP *stream = data->req.protop;
- Curl_safefree(stream->overflow_buf);
+ Curl_dyn_free(&stream->overflow);
}
}
there's no more data coming on the socket, we need to keep reading
until the overflow buffer is empty. */
const struct HTTP *stream = data->req.protop;
- return stream->overflow_buflen > 0;
+ return Curl_dyn_len(&stream->overflow) > 0;
}
#endif