From 2a3c1f5b416e015ed6a83f97ab1571f72f8cc885 Mon Sep 17 00:00:00 2001
From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
Date: Thu, 30 Jan 2014 23:26:20 +0900
Subject: [PATCH] Use nghttp2_session_mem_recv and nghttp2_session_upgrade

---
 lib/http2.c | 84 +++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/lib/http2.c b/lib/http2.c
index 126a812..b0ee39f 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -103,37 +103,6 @@ static ssize_t send_callback(nghttp2_session *h2,
   return written;
 }
 
-/*
- * The implementation of nghttp2_recv_callback type. Here we read data from
- * the network and write them in |buf|. The capacity of |buf| is |length|
- * bytes. Returns the number of bytes stored in |buf|. See the documentation
- * of nghttp2_recv_callback for the details.
- */
-static ssize_t recv_callback(nghttp2_session *h2,
-                             uint8_t *buf, size_t length, int flags,
-                             void *userp)
-{
-  struct connectdata *conn = (struct connectdata *)userp;
-  ssize_t nread;
-  CURLcode rc;
-
-  infof(conn->data, "recv_callback() was called with length %d\n", length);
-
-  rc = Curl_read_plain(conn->sock[FIRSTSOCKET], (char *)buf, length,
-                       &nread);
-  (void)h2;
-  (void)flags;
-
-  if(rc) {
-    failf(conn->data, "Failed receiving HTTP2 data");
-    return NGHTTP2_ERR_CALLBACK_FAILURE;
-  }
-  if(!nread)
-    return NGHTTP2_ERR_WOULDBLOCK;
-
-  return nread;
-}
-
 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
                          void *userp)
 {
@@ -268,7 +237,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
  */
 static const nghttp2_session_callbacks callbacks = {
   send_callback,         /* nghttp2_send_callback */
-  recv_callback,         /* nghttp2_recv_callback */
+  NULL,                  /* nghttp2_recv_callback */
   on_frame_recv,         /* nghttp2_on_frame_recv_callback */
   on_invalid_frame_recv, /* nghttp2_on_invalid_frame_recv_callback */
   on_data_chunk_recv,    /* nghttp2_on_data_chunk_recv_callback */
@@ -368,18 +337,41 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
 static ssize_t http2_recv(struct connectdata *conn, int sockindex,
                           char *mem, size_t len, CURLcode *err)
 {
-  int rc;
+  CURLcode rc;
+  int rv;
+  ssize_t nread;
   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
 
   conn->proto.httpc.mem = mem;
   conn->proto.httpc.size = len;
 
-  rc = nghttp2_session_recv(conn->proto.httpc.h2);
+  infof(conn->data, "http2_recv\n");
+
+  for(;;) {
+    rc = Curl_read_plain(conn->sock[FIRSTSOCKET], mem, len, &nread);
+
+    if(rc == CURLE_AGAIN) {
+      *err = rc;
+      return -1;
+    }
+    if(rc) {
+      failf(conn->data, "Failed receiving HTTP2 data");
+      *err = CURLE_RECV_ERROR;
+      return 0;
+    }
+    infof(conn->data, "nread=%zd\n", nread);
+    if(!nread) {
+      *err = CURLE_RECV_ERROR;
+      return 0; /* TODO EOF? */
+    }
+    rv = nghttp2_session_mem_recv(conn->proto.httpc.h2, mem, nread);
 
-  if(rc < 0) {
-    failf(conn->data, "nghttp2_session_recv() returned %d\n",
-          rc);
-    *err = CURLE_RECV_ERROR;
+    if(nghttp2_is_fatal(rv)) {
+      failf(conn->data, "nghttp2_session_mem_recv() returned %d:%s\n",
+            rv, nghttp2_strerror(rv));
+      *err = CURLE_RECV_ERROR;
+      return 0;
+    }
   }
   return 0;
 }
@@ -399,11 +391,27 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
 void Curl_http2_switched(struct connectdata *conn)
 {
+  /* TODO Fix me */
+  uint8_t binsettings[80];
+  ssize_t binlen;
+  int rc;
+
   /* we are switched! */
   conn->handler = &Curl_handler_http2;
   conn->recv[FIRSTSOCKET] = http2_recv;
   conn->send[FIRSTSOCKET] = http2_send;
   infof(conn->data, "We have switched to HTTP2\n");
+
+  binlen = nghttp2_pack_settings_payload(binsettings,
+                                         sizeof(binsettings),
+                                         settings,
+                                         sizeof(settings)/sizeof(settings[0]));
+  rc =  nghttp2_session_upgrade(conn->proto.httpc.h2, binsettings, binlen,
+                                NULL);
+  if(!rc) {
+    failf(conn->data,
+          "nghttp2 unexpectedly failed on nghttp2_session_upgrade");
+  }
 }
 
 #endif
-- 
1.8.4.2

