mirror of
https://github.com/curl/curl.git
synced 2024-11-27 05:50:21 +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;
|
CURLcode result;
|
||||||
struct http_conn *httpc = &conn->proto.httpc;
|
struct http_conn *httpc = &conn->proto.httpc;
|
||||||
int rv;
|
int rv;
|
||||||
|
ssize_t nproc;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
struct HTTP *stream = conn->data->req.protop;
|
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
|
||||||
if(rv != (int)nread) {
|
called by nghttp2_session_mem_recv() will write stream specific
|
||||||
failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
|
data into stream->mem, overwriting data already there. */
|
||||||
nghttp2_strerror(rv), rv);
|
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;
|
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. */
|
/* Try to send some frames since we may read SETTINGS already. */
|
||||||
rv = nghttp2_session_send(httpc->h2);
|
rv = nghttp2_session_send(httpc->h2);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user