]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ngtcp2: convert to dynbuf
authorDaniel Stenberg <daniel@haxx.se>
Mon, 4 May 2020 09:37:12 +0000 (11:37 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 4 May 2020 12:57:57 +0000 (14:57 +0200)
Closes #5335

docs/DYNBUF.md
lib/dynbuf.c
lib/http.h
lib/vquic/ngtcp2.c

index ff9009de378dc8d206e63eb1ef5c9790fcb94660..3ab059bae1baafa969c7f8df86ea05ad08f9c3ae 100644 (file)
@@ -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
 
index 81e30ce94054ab60677b1605685e10574c6b0a8f..64004952fe1bb9407ddec8a2757c1d01aef09d5f 100644 (file)
@@ -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
 
 /*
index cc262f7d357401f344d4d0f257da0848b1e594c3..9ea3eb28306a747031b65b5cdc8dff5d39edf2e9 100644 (file)
@@ -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
 };
 
index 5f7b6e2e0ab24f9f4a2a1a6315e2f7b3df96436a..8cec432a47a9097f152f92c1107dc5f9ab0bd639 100644 (file)
@@ -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