aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/http.h2
-rw-r--r--lib/http2.c64
2 files changed, 46 insertions, 20 deletions
diff --git a/lib/http.h b/lib/http.h
index 53d2bfeba..13fa1d99b 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -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
diff --git a/lib/http2.c b/lib/http2.c
index 521a78106..78a09af8e 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -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;