From 18815aa670eeace30e8d61dc581859cfe3df02b5 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 4 May 2020 11:37:12 +0200 Subject: ngtcp2: convert to dynbuf Closes #5335 --- docs/DYNBUF.md | 2 +- lib/dynbuf.c | 3 +- lib/http.h | 4 +-- lib/vquic/ngtcp2.c | 104 +++++++++++------------------------------------------ 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 -- cgit v1.2.3