]> granicus.if.org Git - curl/commitdiff
http2: Read data left in connection buffer after pause
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
Thu, 7 May 2015 08:22:57 +0000 (17:22 +0900)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 18 May 2015 06:57:18 +0000 (08:57 +0200)
Previously when we do pause because of out of buffer, we just throw
away unread data in connection buffer.  This just broke protocol
framing, and I saw occasional FRAME_SIZE_ERROR.  This commit fix this
issue by remembering how much data read, and in the next iteration, we
process remaining data.

lib/http.h
lib/http2.c

index 53d2bfeba93a3047f168e0015d82521ddec3cdeb..13fa1d99b7ae0e134dfce3cfbbc67ff95020a503 100644 (file)
@@ -191,6 +191,8 @@ struct http_conn {
   sending send_underlying; /* underlying send Curl_send callback */
   recving recv_underlying; /* underlying recv Curl_recv callback */
   char *inbuf; /* buffer to receive data from underlying socket */
+  size_t inbuflen; /* number of bytes filled in inbuf */
+  size_t nread_inbuf; /* number of bytes read from in inbuf */
   /* We need separate buffer for transmission and reception because we
      may call nghttp2_session_send() after the
      nghttp2_session_mem_recv() but mem buffer is still not full. In
index 521a78106d3c8953263d329e5083c9d0ec3174f7..78a09af8eeca01c858e0adebbb0721df6ddccddd 100644 (file)
@@ -859,36 +859,47 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
     }
   }
   else {
+    char *inbuf;
     /* remember where to store incoming data for this stream and how big the
        buffer is */
     stream->mem = mem;
     stream->len = len;
     stream->memlen = 0;
 
-    nread = ((Curl_recv*)httpc->recv_underlying)(conn, FIRSTSOCKET,
-                                                 httpc->inbuf, H2_BUFSIZE,
-                                                 &result);
-    if(result == CURLE_AGAIN) {
-      *err = result;
-      return -1;
-    }
+    if(httpc->inbuflen == 0) {
+      nread = ((Curl_recv *)httpc->recv_underlying)(
+          conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
 
-    if(nread == -1) {
-      failf(data, "Failed receiving HTTP2 data");
-      *err = result;
-      return 0;
-    }
+      if(result == CURLE_AGAIN) {
+        *err = result;
+        return -1;
+      }
 
-    if(nread == 0) {
-      failf(data, "Unexpected EOF");
-      *err = CURLE_RECV_ERROR;
-      return -1;
-    }
+      if(nread == -1) {
+        failf(data, "Failed receiving HTTP2 data");
+        *err = result;
+        return 0;
+      }
 
-    DEBUGF(infof(data, "nread=%zd\n", nread));
+      if(nread == 0) {
+        failf(data, "Unexpected EOF");
+        *err = CURLE_RECV_ERROR;
+        return -1;
+      }
 
-    rv = nghttp2_session_mem_recv(httpc->h2,
-                                  (const uint8_t *)httpc->inbuf, nread);
+      DEBUGF(infof(data, "nread=%zd\n", nread));
+
+      httpc->inbuflen = nread;
+      inbuf = httpc->inbuf;
+    }
+    else {
+      nread = httpc->inbuflen - httpc->nread_inbuf;
+      inbuf = httpc->inbuf + httpc->nread_inbuf;
+
+      DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
+                   nread));
+    }
+    rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
 
     if(nghttp2_is_fatal((int)rv)) {
       failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
@@ -897,6 +908,16 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       return 0;
     }
     DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
+    if(nread == rv) {
+      DEBUGF(infof(data, "All data in connection buffer processed\n"));
+      httpc->inbuflen = 0;
+      httpc->nread_inbuf = 0;
+    }
+    else {
+      httpc->nread_inbuf += rv;
+      DEBUGF(infof(data, "%zu bytes left in connection buffer\n",
+                   httpc->inbuflen - httpc->nread_inbuf));
+    }
     /* Always send pending frames in nghttp2 session, because
        nghttp2_session_mem_recv() may queue new frame */
     rv = nghttp2_session_send(httpc->h2);
@@ -1145,6 +1166,9 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   httpc->upload_mem = NULL;
   httpc->upload_len = 0;
 
+  httpc->inbuflen = 0;
+  httpc->nread_inbuf = 0;
+
   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
   conn->httpversion = 20;
   conn->bundle->server_supports_pipelining = TRUE;