From 2876092d5293a6e4a880889b37dd4389289bd2e9 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Sat, 21 May 2016 18:35:42 +0200
Subject: [PATCH] http2: window size experiments

---
 lib/http2.c | 43 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/lib/http2.c b/lib/http2.c
index 3fe02a5..e938770 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -57,10 +57,13 @@
 #define NGHTTP2_HAS_ERROR_CALLBACK 1
 #else
 #define nghttp2_session_callbacks_set_error_callback(x,y)
 #endif
 
+#define H2_BUFSIZE 32768
+#define H2_INITIAL_WINDOW_INC (512*1048576) /* 512MB */
+
 /*
  * Curl_http2_init_state() is called when the easy handle is created and
  * allows for HTTP/2 specific init of state.
  */
 void Curl_http2_init_state(struct UrlState *state)
@@ -377,10 +380,11 @@ static int push_promise(struct SessionHandle *data,
     CURLMcode rc;
     struct http_conn *httpc;
     size_t i;
     /* clone the parent */
     struct SessionHandle *newhandle = duphandle(data);
+
     if(!newhandle) {
       infof(data, "failed to duplicate handle\n");
       rv = 1; /* FAIL HARD */
       goto fail;
     }
@@ -489,11 +493,11 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
 
   stream = data_s->req.protop;
   if(!stream)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
+  DEBUGF(infof(data_s, "on_frame_recv() header %x stream %u\n",
                frame->hd.type, stream_id));
 
   switch(frame->hd.type) {
   case NGHTTP2_DATA:
     /* If body started on this stream, then receiving DATA is illegal. */
@@ -959,15 +963,13 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
 /*
  * The HTTP2 settings we send in the Upgrade request
  */
 static nghttp2_settings_entry settings[] = {
   { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 },
-  { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE },
+  { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, H2_INITIAL_WINDOW_INC },
 };
 
-#define H2_BUFSIZE 32768
-
 #ifdef NGHTTP2_HAS_ERROR_CALLBACK
 static int error_callback(nghttp2_session *session,
                           const char *msg,
                           size_t len,
                           void *userp)
@@ -985,19 +987,28 @@ static int error_callback(nghttp2_session *session,
 CURLcode Curl_http2_init(struct connectdata *conn)
 {
   if(!conn->proto.httpc.h2) {
     int rc;
     nghttp2_session_callbacks *callbacks;
+    nghttp2_option *h2opt;
 
     conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
     if(conn->proto.httpc.inbuf == NULL)
       return CURLE_OUT_OF_MEMORY;
 
+    rc = nghttp2_option_new(&h2opt);
+    if(rc)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* switch off automatic window updates */
+    nghttp2_option_set_no_auto_window_update(h2opt, 1);
+
     rc = nghttp2_session_callbacks_new(&callbacks);
 
     if(rc) {
       failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
+      nghttp2_option_del(h2opt);
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
 
     /* nghttp2_send_callback */
     nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
@@ -1028,14 +1039,16 @@ CURLcode Curl_http2_init(struct connectdata *conn)
     /* nghttp2_on_header_callback */
     nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
 
     nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
 
-    /* The nghttp2 session is not yet setup, do it */
-    rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
+    /* Create the nghttp2 session */
+    rc = nghttp2_session_client_new2(&conn->proto.httpc.h2, callbacks, conn,
+                                     h2opt);
 
     nghttp2_session_callbacks_del(callbacks);
+    nghttp2_option_del(h2opt);
 
     if(rc) {
       failf(conn->data, "Couldn't initialize nghttp2!");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
@@ -1771,11 +1784,23 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
   infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
         stream_id, conn->data);
   stream->stream_id = stream_id;
 
-  /* this does not call h2_session_send() since there can not have been any
+#if 1
+  infof(conn->data, "Bump HTTP/2 window size another %d bytes\n",
+        H2_INITIAL_WINDOW_INC);
+  rv = nghttp2_submit_window_update(h2, NGHTTP2_FLAG_NONE, 0,
+                                    H2_INITIAL_WINDOW_INC);
+  if(rv) {
+    failf(conn->data, "Couldn't update the initial window size");
+    *err = CURLE_HTTP2;
+    return -1;
+  }
+#endif
+
+    /* this does not call h2_session_send() since there can not have been any
    * priority upodate since the nghttp2_submit_request() call above */
   rv = nghttp2_session_send(h2);
 
   if(rv != 0) {
     *err = CURLE_SEND_ERROR;
@@ -1893,11 +1918,13 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
                                          conn->data);
   }
   else {
     /* stream ID is unknown at this point */
     stream->stream_id = -1;
-    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
+    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
+                                 /* set default window size */
+                                 &settings[1], 1);
     if(rv != 0) {
       failf(data, "nghttp2_submit_settings() failed: %s(%d)",
             nghttp2_strerror(rv), rv);
       return CURLE_HTTP2;
     }
-- 
2.8.1

