aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2020-05-04 11:37:12 +0200
committerDaniel Stenberg <daniel@haxx.se>2020-05-04 14:57:57 +0200
commit18815aa670eeace30e8d61dc581859cfe3df02b5 (patch)
tree3c8fd83c63a6c429d0e1fe50f14bded03a31f0fe
parent7a86a25f5b73b86455cd977572250de0a6124524 (diff)
ngtcp2: convert to dynbuf
Closes #5335
-rw-r--r--docs/DYNBUF.md2
-rw-r--r--lib/dynbuf.c3
-rw-r--r--lib/http.h4
-rw-r--r--lib/vquic/ngtcp2.c104
4 files changed, 23 insertions, 90 deletions
diff --git a/docs/DYNBUF.md b/docs/DYNBUF.md
index ff9009de3..3ab059bae 100644
--- a/docs/DYNBUF.md
+++ b/docs/DYNBUF.md
@@ -54,7 +54,7 @@ Reset the buffer length, but leave the allocation.
Keep `length` bytes of the buffer tail (the last `length` bytes of the
buffer). The rest of the buffer is dropped. The specified `length` must not be
-larger than the buffer length. (**This function is currently not provided**.)
+larger than the buffer length.
## ptr
diff --git a/lib/dynbuf.c b/lib/dynbuf.c
index 81e30ce94..64004952f 100644
--- a/lib/dynbuf.c
+++ b/lib/dynbuf.c
@@ -123,7 +123,7 @@ void Curl_dyn_reset(struct dynbuf *s)
s->leng = 0;
}
-#if 0
+#ifdef USE_NGTCP2
/*
* Specify the size of the tail to keep (number of bytes from the end of the
* buffer). The rest will be dropped.
@@ -147,7 +147,6 @@ CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
return CURLE_OK;
}
-
#endif
/*
diff --git a/lib/http.h b/lib/http.h
index cc262f7d3..9ea3eb283 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -182,9 +182,7 @@ struct HTTP {
#ifdef USE_NGHTTP3
size_t unacked_window;
struct h3out *h3out; /* per-stream buffers for upload */
- char *overflow_buf; /* excess data received during a single Curl_read */
- size_t overflow_buflen; /* amount of data currently in overflow_buf */
- size_t overflow_bufsize; /* size of the overflow_buf allocation */
+ struct dynbuf overflow; /* excess data received during a single Curl_read */
#endif
};
diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c
index 5f7b6e2e0..8cec432a4 100644
--- a/lib/vquic/ngtcp2.c
+++ b/lib/vquic/ngtcp2.c
@@ -38,6 +38,7 @@
#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"
@@ -1018,57 +1019,12 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
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;
@@ -1076,10 +1032,6 @@ static CURLcode write_data(struct Curl_easy *data,
/* 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;
@@ -1088,26 +1040,8 @@ static CURLcode write_data(struct Curl_easy *data,
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;
}
@@ -1120,7 +1054,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
CURLcode result = CURLE_OK;
(void)conn;
- result = write_data(data, stream, buf, buflen);
+ result = write_data(stream, buf, buflen);
if(result) {
return -1;
}
@@ -1183,7 +1117,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
/* 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;
}
@@ -1214,26 +1148,26 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
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;
}
@@ -1341,15 +1275,16 @@ static Curl_send ngh3_stream_send;
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;
}
@@ -1528,6 +1463,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
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. */
@@ -2032,7 +1968,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature)
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);
}
}
@@ -2047,7 +1983,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data)
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