serf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhuij...@apache.org
Subject svn commit: r1710687 - /serf/trunk/protocols/http2_protocol.c
Date Mon, 26 Oct 2015 20:19:07 GMT
Author: rhuijben
Date: Mon Oct 26 20:19:07 2015
New Revision: 1710687

URL: http://svn.apache.org/viewvc?rev=1710687&view=rev
Log:
Checkpoint the current http2 protocol implementation. This now dumps the
completely decoded hpack headers when logging is set.

This adds some helper functions to quickly create frames with a few
integer values.

* protocols/http2_protocol.c
  (includes): Add http2_buckets.h.
  (serf_bucket_create_numberv): New static function.
  (serf__http2_protocol_init): Construct hpack table.
  (http2_read): Read just the inner payload. Decode headers.

Modified:
    serf/trunk/protocols/http2_protocol.c

Modified: serf/trunk/protocols/http2_protocol.c
URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1710687&r1=1710686&r2=1710687&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.c (original)
+++ serf/trunk/protocols/http2_protocol.c Mon Oct 26 20:19:07 2015
@@ -28,6 +28,7 @@
 #include "serf_bucket_util.h"
 
 #include "serf_private.h"
+#include "protocols/http2_buckets.h"
 #include "protocols/http2_protocol.h"
 
 static apr_status_t
@@ -42,6 +43,88 @@ http2_protocol_hangup(serf_connection_t
 static void
 http2_protocol_teardown(serf_connection_t *conn);
 
+static serf_bucket_t *
+serf_bucket_create_numberv(serf_bucket_alloc_t *allocator, const char *format, ...)
+{
+  va_list va;
+  const char *c;
+  char *buffer;
+  apr_size_t sz = 0;
+  unsigned char *r;
+
+  va_start(va, format);
+
+  for (c = format; *c; c++)
+    {
+      switch (*c)
+      {
+        case '1': /* char */
+          sz += 1;
+          break;
+        case '2': /* apr_int16_t / apr_uint16_t */
+          sz += 2;
+          break;
+        case '3': /* apr_int32_t / apr_uint32_t */
+          sz += 3;
+          break;
+        case '4': /* apr_int32_t / apr_uint32_t */
+          sz += 4;
+          break;
+        case '8': /* apr_int64_t / apr_uint64_t */
+          sz += 8;
+          break;
+        default:
+          abort(); /* Invalid format */
+      }
+    }
+
+  buffer = serf_bucket_mem_alloc(allocator, sz);
+  r = (void*)buffer;
+  for (c = format; *c; c++)
+    {
+        apr_uint32_t tmp;
+        apr_uint64_t tmp_64;
+
+       switch (*c)
+        {
+          case '1':
+            *r++ = va_arg(va, char);
+            break;
+          case '2':
+            tmp = va_arg(va, apr_uint16_t);
+            *r++ = (tmp >> 8) & 0xFF;
+            *r++ = tmp & 0xFF;
+            break;
+          case '3':
+            tmp = va_arg(va, apr_uint32_t);
+            *r++ = (tmp >> 16) & 0xFF;
+            *r++ = (tmp >> 8) & 0xFF;
+            *r++ = tmp & 0xFF;
+            break;
+          case '4':
+            tmp = va_arg(va, apr_uint32_t);
+            *r++ = (tmp >> 24) & 0xFF;
+            *r++ = (tmp >> 16) & 0xFF;
+            *r++ = (tmp >> 8) & 0xFF;
+            *r++ = tmp & 0xFF;
+            break;
+          case '8':
+            tmp_64 = va_arg(va, apr_uint64_t);
+            *r++ = (tmp_64 >> 56) & 0xFF;
+            *r++ = (tmp_64 >> 48) & 0xFF;
+            *r++ = (tmp_64 >> 40) & 0xFF;
+            *r++ = (tmp_64 >> 32) & 0xFF;
+            *r++ = (tmp_64 >> 24) & 0xFF;
+            *r++ = (tmp_64 >> 16) & 0xFF;
+            *r++ = (tmp_64 >> 8) & 0xFF;
+            *r++ = tmp_64 & 0xFF;
+            break;
+       }
+    }
+  return serf_bucket_simple_own_create(buffer, sz, allocator);
+}
+
+
 typedef struct serf_http2_stream_t
 {
   struct serf_http2_procotol_state_t *ctx;
@@ -77,6 +160,8 @@ typedef struct serf_http2_procotol_state
   apr_pool_t *pool;
   serf_bucket_t *ostream;
 
+  serf_hpack_table_t *hpack_tbl;
+
   apr_int64_t lr_window; /* local->remote */
   apr_int64_t rl_window; /* remote->local */
   apr_int32_t next_local_streamid;
@@ -121,6 +206,8 @@ void serf__http2_protocol_init(serf_conn
 
   ctx->first = ctx->last = NULL;
 
+  ctx->hpack_tbl = serf__hpack_table_create(TRUE, 16384, protocol_pool);
+
   apr_pool_cleanup_register(protocol_pool, conn, http2_protocol_cleanup,
                             apr_pool_cleanup_null);
 
@@ -141,27 +228,27 @@ void serf__http2_protocol_init(serf_conn
 
   /* And now a settings frame and a huge window */
   {
-    serf_bucket_t *no_settings;
+    serf_bucket_t *settings;
     serf_bucket_t *window_size;
-    apr_int32_t frame_id = 0;
 
-    no_settings = serf_bucket_simple_create("", 0, NULL, NULL, conn->allocator);
-    tmp = serf_bucket_http2_frame_create(no_settings, HTTP2_FRAME_TYPE_SETTINGS, 0,
-                                         &frame_id, NULL, NULL, /* Static id: 0*/
-                                         HTTP2_DEFAULT_MAX_FRAMESIZE,
-                                         NULL, NULL, conn->allocator);
+    settings = serf_bucket_create_numberv(conn->allocator, "24",
+                              (apr_int16_t)HTTP2_SETTING_HEADER_TABLE_SIZE,
+                              (apr_int32_t)0);
+    tmp = serf__bucket_http2_frame_create(settings, HTTP2_FRAME_TYPE_SETTINGS, 0,
+                                          NULL, NULL, NULL, /* Static id: 0*/
+                                          HTTP2_DEFAULT_MAX_FRAMESIZE,
+                                          NULL, NULL, conn->allocator);
 
     serf_bucket_aggregate_append(ctx->ostream, tmp);
 
     /* Add 2GB - 65535 to the current window.
        (Adding 2GB -1 appears to overflow at at least one server) */
-    window_size = serf_bucket_simple_create("\x7F\xFF\x00\x00", 4, NULL, NULL,
-                                            conn->allocator);
-    tmp = serf_bucket_http2_frame_create(window_size,
-                                         HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0,
-                                         &frame_id, NULL, NULL,
-                                         HTTP2_DEFAULT_MAX_FRAMESIZE,
-                                         NULL, NULL, conn->allocator);
+    window_size = serf_bucket_create_numberv(conn->allocator, "4", 0x7FFF0000);
+    tmp = serf__bucket_http2_frame_create(window_size,
+                                          HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0,
+                                          NULL, NULL, NULL,
+                                          HTTP2_DEFAULT_MAX_FRAMESIZE,
+                                          NULL, NULL, conn->allocator);
     serf_bucket_aggregate_append(ctx->ostream, tmp);
   }
 }
@@ -201,12 +288,12 @@ setup_for_http2(serf_http2_procotol_stat
       request->req_bkt = NULL;
     }
   
-  hpack = serf_bucket_http2_frame_create(hpack, HTTP2_FRAME_TYPE_HEADERS,
-                                         HTTP2_FLAG_END_STREAM
-                                         | HTTP2_FLAG_END_HEADERS,
-                                         &streamid, NULL, NULL,
-                                         HTTP2_DEFAULT_MAX_FRAMESIZE,
-                                         NULL, NULL, request->allocator);
+  hpack = serf__bucket_http2_frame_create(hpack, HTTP2_FRAME_TYPE_HEADERS,
+                                          HTTP2_FLAG_END_STREAM
+                                          | HTTP2_FLAG_END_HEADERS,
+                                          &streamid, NULL, NULL,
+                                          HTTP2_DEFAULT_MAX_FRAMESIZE,
+                                          NULL, NULL, request->allocator);
 
   serf_bucket_aggregate_append(ctx->ostream, hpack);
 
@@ -252,40 +339,49 @@ http2_read(serf_connection_t *conn)
           if (! ctx->in_payload)
             {
               unsigned char flags;
+              unsigned char frametype;
 
-              status = serf_bucket_http2_unframe_read_info(ctx->cur_frame,
-                                                           NULL, NULL, &flags);
+              status = serf__bucket_http2_unframe_read_info(ctx->cur_frame,
+                                                            NULL, &frametype,
+                                                            &flags);
 
-              if (!SERF_BUCKET_READ_ERROR(status))
-                {
-                  ctx->in_payload = TRUE;
+              if (status)
+                break;
+
+              ctx->in_payload = TRUE;
 
-                  if (flags & HTTP2_FLAG_PADDED)
-                    {
-                      ctx->cur_payload =
-                        serf_bucket_http2_unpad_create(
+              if (flags & HTTP2_FLAG_PADDED)
+                {
+                  ctx->cur_payload =
+                        serf__bucket_http2_unpad_create(
                               ctx->cur_frame, TRUE,
                               ctx->cur_frame->allocator);
-                    }
-                  else
-                    ctx->cur_payload = ctx->cur_frame;
                 }
+              else
+                ctx->cur_payload = ctx->cur_frame;
 
-              if (status)
-                break;
+              if (frametype == HTTP2_FRAME_TYPE_HEADERS)
+                {
+                  ctx->cur_payload = serf__bucket_hpack_decode_create(
+                                            ctx->cur_payload,
+                                            NULL, NULL,
+                                            16384, ctx->hpack_tbl,
+                                            ctx->cur_frame->allocator);
+                }
             }
 
-          status = serf_bucket_read(ctx->cur_frame,
+          status = serf_bucket_read(ctx->cur_payload,
                                     sizeof(ctx->buffer) - ctx->buffer_used,
                                     &data, &len);
 
-          if (!SERF_BUCKET_READ_ERROR(status))
+          if (SERF_BUCKET_READ_ERROR(status))
+            break;
+
+          if (len)
             {
               memcpy(&ctx->buffer[ctx->buffer_used], data, len);
               ctx->buffer_used += len;
             }
-          else
-            break;
 
           if (APR_STATUS_IS_EOF(status))
             {
@@ -293,12 +389,20 @@ http2_read(serf_connection_t *conn)
               unsigned char frametype;
               unsigned char flags;
 
-              serf_bucket_http2_unframe_read_info(ctx->cur_frame,
-                                                  &streamid, &frametype,
-                                                  &flags);
+              serf__bucket_http2_unframe_read_info(ctx->cur_frame,
+                                                   &streamid, &frametype,
+                                                   &flags);
               serf__log(LOGLVL_INFO, LOGCOMP_CONN, __FILE__, conn->config,
-                        "Read 0x%02x http2 frame on stream 0x%x, flags=0x%x\n",
-                        (int)frametype, (int)streamid, (int)flags);
+                        "Read 0x%02x http2 frame on stream 0x%x, flags=0x%x, size=0x%x\n",
+                        (int)frametype, (int)streamid, (int)flags, (int)ctx->buffer_used);
+
+              if (frametype == HTTP2_FRAME_TYPE_DATA
+                  || frametype == HTTP2_FRAME_TYPE_HEADERS)
+                {
+                  /* Ugly hack to dump body. Memory LEAK! */
+                  serf__log(LOGLVL_INFO, LOGCOMP_CONN, __FILE__, conn->config,
+                            "%s\n", apr_pstrmemdup(conn->pool, ctx->buffer, ctx->buffer_used));
+                }
 
               if (frametype == HTTP2_FRAME_TYPE_GOAWAY && conn)
                 serf__log(LOGLVL_WARNING, LOGCOMP_CONN, __FILE__, conn->config,
@@ -308,6 +412,37 @@ http2_read(serf_connection_t *conn)
                                                                (ctx->buffer_used >=
8)
                                                                ? ctx->buffer_used-8 :
0));
 
+              if (frametype == HTTP2_FRAME_TYPE_SETTINGS)
+                {
+                  /* Always ack settings */
+                  serf_bucket_aggregate_append(
+                    ctx->ostream,
+                    serf__bucket_http2_frame_create(
+                                    NULL,
+                                    HTTP2_FRAME_TYPE_SETTINGS,
+                                    HTTP2_FLAG_ACK,
+                                    NULL, NULL, NULL,
+                                    HTTP2_DEFAULT_MAX_FRAMESIZE,
+                                    NULL, NULL, conn->allocator));
+                }
+              else if (frametype == HTTP2_FRAME_TYPE_DATA)
+                {
+                  /* Provide a bit of window space to the server after 
+                     receiving data */
+                  serf_bucket_aggregate_append(
+                    ctx->ostream,
+                    serf__bucket_http2_frame_create(
+                      serf_bucket_create_numberv(conn->allocator, "4", (apr_int32_t)16384),
+                              HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0,
+                              &streamid, NULL, NULL,
+                              HTTP2_DEFAULT_MAX_FRAMESIZE,
+                              NULL, NULL, conn->allocator));
+                }
+              else if (frametype == HTTP2_FRAME_TYPE_PING)
+                {
+                  /* TODO: PONG (=Ping Ack) */
+                }
+
               serf_bucket_destroy(ctx->cur_payload);
               ctx->cur_frame = ctx->cur_payload = NULL;
               ctx->in_payload = FALSE;
@@ -332,9 +467,9 @@ http2_read(serf_connection_t *conn)
         }
 
       ctx->cur_frame = ctx->cur_payload =
-            serf_bucket_http2_unframe_create(conn->stream, FALSE,
-                                             HTTP2_DEFAULT_MAX_FRAMESIZE,
-                                             conn->stream->allocator);
+            serf__bucket_http2_unframe_create(conn->stream, FALSE,
+                                              HTTP2_DEFAULT_MAX_FRAMESIZE,
+                                              conn->stream->allocator);
     }
 
   return status;



Mime
View raw message