The attached patch which fixes the bug that HTTP/2 hangs if whole response
body is read with  headers. This bug was not revealed with nghttp2 test
servers, but I discovered it while developing nghttp2 Python bindings which
includes HTTP/2 server in Python.

Best regards,
Tatsuhiro Tsujikawa
From ba22f0728a276846df44563958b81e7bcad18746 Mon Sep 17 00:00:00 2001
From: Tatsuhiro Tsujikawa <[email protected]>
Date: Thu, 27 Feb 2014 01:21:17 +0900
Subject: [PATCH] Fix bug that HTTP/2 hangs if whole response body is read with
 headers

For HTTP/2, we may read up everything including responde body with
header fields in Curl_http_readwrite_headers. If no content-length is
provided, curl waits for the connection close, which we emulate it
using conn->proto.httpc.closed = TRUE. The thing is if we read
everything, then http2_recv won't be called and we cannot signal the
HTTP/2 stream has closed. As a workaround, we return nonzero from
data_pending to call http2_recv.
---
 lib/http2.c    |  4 ++++
 lib/transfer.c | 11 ++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/lib/http2.c b/lib/http2.c
index e8d31d5..1498d60 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -511,6 +511,10 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
 
   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
 
+  if(httpc->closed) {
+    return 0;
+  }
+
   /* Nullify here because we call nghttp2_session_send() and they
      might refer to the old buffer. */
   httpc->upload_mem = NULL;
diff --git a/lib/transfer.c b/lib/transfer.c
index 83727db..8748c6a 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -310,7 +310,16 @@ static int data_pending(const struct connectdata *conn)
   /* in the case of libssh2, we can never be really sure that we have emptied
      its internal buffers so we MUST always try until we get EAGAIN back */
   return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
-    Curl_ssl_data_pending(conn, FIRSTSOCKET);
+    Curl_ssl_data_pending(conn, FIRSTSOCKET) ||
+    /* For HTTP/2, we may read up everything including responde body
+       with header fields in Curl_http_readwrite_headers. If no
+       content-length is provided, curl waits for the connection
+       close, which we emulate it using conn->proto.httpc.closed =
+       TRUE. The thing is if we read everything, then http2_recv won't
+       be called and we cannot signal the HTTP/2 stream has closed. As
+       a workaround, we return nonzero here to call http2_recv. */
+    ((conn->handler->protocol&CURLPROTO_HTTP) && conn->httpversion == 20 &&
+     conn->proto.httpc.closed);
 }
 
 static void read_rewind(struct connectdata *conn,
-- 
1.9.0

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to