summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2015-05-07 14:51:32 +0900
committerDaniel Stenberg <daniel@haxx.se>2015-05-18 08:57:18 +0200
commitd261652d422b0724406d03df8ff753ac7a20b7b6 (patch)
tree850daeb8c6c61d38e16b8b493d38c8019064c7ab /lib
parent74a4bd5ecd83ce1fde0dba8a642d3daaa99d916e (diff)
downloadcurl-d261652d422b0724406d03df8ff753ac7a20b7b6.tar.gz
http2: Fix streams get stuck
This commit fixes the bug that streams get stuck if stream gets some DATA, and stream->closed becomes true at the same time. Previously, in this condition, after we processed DATA, we are going to try to read data from underlying transport, but there is no data, and gets EAGAIN. There was no code path to evaludate stream->closed.
Diffstat (limited to 'lib')
-rw-r--r--lib/http2.c42
1 files changed, 22 insertions, 20 deletions
diff --git a/lib/http2.c b/lib/http2.c
index 6014f3d19..521a78106 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -762,6 +762,21 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
return result;
}
+static ssize_t http2_handle_stream_close(struct SessionHandle *data,
+ struct HTTP *stream, CURLcode *err) {
+ /* Reset to FALSE to prevent infinite loop in readwrite_data
+ function. */
+ stream->closed = FALSE;
+ if(stream->error_code != NGHTTP2_NO_ERROR) {
+ failf(data, "HTTP/2 stream = %x was not closed cleanly: error_code = %d",
+ stream->stream_id, stream->error_code);
+ *err = CURLE_HTTP2;
+ return -1;
+ }
+ DEBUGF(infof(data, "http2_recv returns 0\n"));
+ return 0;
+}
+
/*
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
* a regular CURLcode value.
@@ -778,15 +793,13 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
(void)sockindex; /* we always do HTTP2 on sockindex 0 */
-#if 0
- if(stream->closed) {
- /* Reset to FALSE to prevent infinite loop in readwrite_data
- function. */
- stream->closed = FALSE;
- DEBUGF(infof(data, "http2_recv2 stream found closed?\n"));
- return 0;
+ /* If stream is closed, return 0 to signal the http routine to close
+ the connection. We need to handle stream closure here,
+ otherwise, we may be going to read from underlying connection,
+ and gets EAGAIN, and we will get stuck there. */
+ if(stream->memlen == 0 && stream->closed) {
+ return http2_handle_stream_close(data, stream, err);
}
-#endif
/* Nullify here because we call nghttp2_session_send() and they
might refer to the old buffer. */
@@ -905,18 +918,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
/* If stream is closed, return 0 to signal the http routine to close
the connection */
if(stream->closed) {
- /* Reset to FALSE to prevent infinite loop in readwrite_data
- function. */
- stream->closed = FALSE;
- if(stream->error_code != NGHTTP2_NO_ERROR) {
- failf(data,
- "HTTP/2 stream = %x was not closed cleanly: error_code = %d",
- stream->stream_id, stream->error_code);
- *err = CURLE_HTTP2;
- return -1;
- }
- DEBUGF(infof(data, "http2_recv returns 0\n"));
- return 0;
+ return http2_handle_stream_close(data, stream, err);
}
*err = CURLE_AGAIN;
DEBUGF(infof(data, "http2_recv returns -1, AGAIN\n"));