diff options
author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2015-05-26 00:10:05 +0900 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2015-05-25 23:07:49 +0200 |
commit | 02dfc930b5d5aaeab0ea7bf0019d2e753daa7491 (patch) | |
tree | c48c7d25b16f24c51440f86ef53a50c0d15a75d1 | |
parent | 96c0164b8871d36eeaafdfc99b1a9bea2b83657e (diff) |
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.c | 36 |
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); |