mirror of
https://github.com/curl/curl.git
synced 2024-11-21 01:16:58 +08:00
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().
This commit is contained in:
parent
96c0164b88
commit
02dfc930b5
40
lib/http2.c
40
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);
|
||||
|
||||
if(rv != (int)nread) {
|
||||
failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
|
||||
nghttp2_strerror(rv), rv);
|
||||
/* 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);
|
||||
|
||||
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((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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user