summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2015-05-26 00:10:05 +0900
committerDaniel Stenberg <daniel@haxx.se>2015-05-25 23:07:49 +0200
commit02dfc930b5d5aaeab0ea7bf0019d2e753daa7491 (patch)
treec48c7d25b16f24c51440f86ef53a50c0d15a75d1
parent96c0164b8871d36eeaafdfc99b1a9bea2b83657e (diff)
downloadgnurl-02dfc930b5d5aaeab0ea7bf0019d2e753daa7491.tar.gz
gnurl-02dfc930b5d5aaeab0ea7bf0019d2e753daa7491.tar.bz2
gnurl-02dfc930b5d5aaeab0ea7bf0019d2e753daa7491.zip
http2: Copy data passed in Curl_http2_switched into HTTP/2 connection buffer
Previously, after seeing upgrade to HTTP/2, we feed data followed by upgrade response headers directly to nghttp2_session_mem_recv() in Curl_http2_switched(). But it turns out that passed buffer, mem, is part of stream->mem, and callbacks called by nghttp2_session_mem_recv() will write stream specific data into stream->mem, overwriting input data. This will corrupt input, and most likely frame length error is detected by nghttp2 library. The fix is first copy the passed data to HTTP/2 connection buffer, httpc->inbuf, and call nghttp2_session_mem_recv().
-rw-r--r--lib/http2.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/lib/http2.c b/lib/http2.c
index a56535471..fa47d0ece 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -1248,6 +1248,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
CURLcode result;
struct http_conn *httpc = &conn->proto.httpc;
int rv;
+ ssize_t nproc;
struct SessionHandle *data = conn->data;
struct HTTP *stream = conn->data->req.protop;
@@ -1290,14 +1291,43 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
}
}
- rv = (int)nghttp2_session_mem_recv(httpc->h2, (const uint8_t*)mem, nread);
+ /* we are going to copy mem to httpc->inbuf. This is required since
+ mem is part of buffer pointed by stream->mem, and callbacks
+ called by nghttp2_session_mem_recv() will write stream specific
+ data into stream->mem, overwriting data already there. */
+ if(H2_BUFSIZE < nread) {
+ failf(data, "connection buffer size is too small to store data following "
+ "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
+ H2_BUFSIZE, nread);
+ return CURLE_HTTP2;
+ }
+
+ infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
+ " after upgrade: len=%zu\n",
+ nread);
- if(rv != (int)nread) {
+ memcpy(httpc->inbuf, mem, nread);
+ httpc->inbuflen = nread;
+
+ nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
+ httpc->inbuflen);
+
+ if(nghttp2_is_fatal((int)nproc)) {
failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
- nghttp2_strerror(rv), rv);
+ nghttp2_strerror((int)nproc), (int)nproc);
return CURLE_HTTP2;
}
+ DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
+
+ if((ssize_t)nread == nproc) {
+ httpc->inbuflen = 0;
+ httpc->nread_inbuf = 0;
+ }
+ else {
+ httpc->nread_inbuf += nproc;
+ }
+
/* Try to send some frames since we may read SETTINGS already. */
rv = nghttp2_session_send(httpc->h2);