http2 hpack basic decode ok including huff
authorAndy Green <andy.green@linaro.org>
Sun, 12 Oct 2014 00:38:16 +0000 (08:38 +0800)
committerAndy Green <andy.green@linaro.org>
Sun, 12 Oct 2014 00:38:16 +0000 (08:38 +0800)
Signed-off-by: Andy Green <andy.green@linaro.org>
CMakeLists.txt
lib/hpack.c
lib/http2.c
lib/huftable.h
lib/libwebsockets.h
lib/minihuf.c
lib/output.c
lib/private-libwebsockets.h
lib/server.c
test-server/test-server.c

index 59d6c3a..f7fc82b 100644 (file)
@@ -296,6 +296,7 @@ endif()
 if (LWS_WITH_HTTP2)
        list(APPEND SOURCES
                lib/http2.c
+               lib/hpack.c
                lib/ssl-http2.c
                )
 endif()
index 0d19815..1bda810 100644 (file)
@@ -1,4 +1,27 @@
 /*
+ * lib/hpack.c
+ *
+ * Copyright (C) 2014 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+/*
  * Official static header table for HPACK
  *        +-------+-----------------------------+---------------+
           | 1     | :authority                  |               |
@@ -104,7 +127,7 @@ static const unsigned char static_token[] = {
        WSI_TOKEN_HTTP_EXPECT,
        WSI_TOKEN_HTTP_EXPIRES,
        WSI_TOKEN_HTTP_FROM,
-       WSI_TOKEN_HTTP_HOST,
+       WSI_TOKEN_HOST,
        WSI_TOKEN_HTTP_IF_MATCH,
        WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
        WSI_TOKEN_HTTP_IF_NONE_MATCH,
@@ -130,6 +153,8 @@ static const unsigned char static_token[] = {
        WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
 };
 
+/* some of the entries imply values as well as header names */
+
 static const char * const http2_canned[] = {
        "",
        "",
@@ -142,7 +167,6 @@ static const char * const http2_canned[] = {
        "200",
        "204",
        "206",
-       "300",
        "304",
        "400",
        "404",
@@ -151,9 +175,11 @@ static const char * const http2_canned[] = {
        "gzip, deflate"
 };
 
+/* see minihuf.c */
+
 #include "huftable.h"
 
-int lextable_decode(int pos, char c)
+static int huftable_decode(int pos, char c)
 {
        int q = pos + !!c;
 
@@ -163,77 +189,282 @@ int lextable_decode(int pos, char c)
        return pos + (lextable[q] << 1);
 }
 
-static int lws_add_header(int header, const char *payload, int len)
+static int lws_hpack_update_table_size(struct libwebsocket *wsi, int idx)
 {
-       wsi->u.ah.frag_index[header]
+       lwsl_info("hpack set table size %d\n", idx);
+       return 0;
 }
 
-int lws_hpack_interpret(struct libwebsocket *wsi, unsigned char c)
+static int lws_frag_start(struct libwebsocket *wsi, int hdr_token_idx)
 {
+       struct allocated_headers * ah = wsi->u.http2.http.ah;
+
+       if (!hdr_token_idx)
+               return 1;
+       
+       if (ah->next_frag_index >= ARRAY_SIZE(ah->frag_index))
+               return 1;
+       
+       ah->frags[ah->next_frag_index].offset = ah->pos;
+       ah->frags[ah->next_frag_index].len = 0;
+       ah->frags[ah->next_frag_index].next_frag_index = 0;
+
+       ah->frag_index[hdr_token_idx] = ah->next_frag_index;
+       
+       return 0;
+}
+
+static int lws_frag_append(struct libwebsocket *wsi, unsigned char c)
+{
+       struct allocated_headers * ah = wsi->u.http2.http.ah;
+
+       ah->data[ah->pos++] = c;
+       ah->frags[ah->next_frag_index].len++;
+       
+       return ah->pos >= sizeof(ah->data);
+}
+
+static int lws_frag_end(struct libwebsocket *wsi)
+{
+       if (lws_frag_append(wsi, 0))
+               return 1;
+
+       wsi->u.http2.http.ah->next_frag_index++;
+       return 0;
+}
+
+static void lws_dump_header(struct libwebsocket *wsi, int hdr)
+{
+       char s[200];
+       int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
+       s[len] = '\0';
+       lwsl_info("  hdr tok %d '%s'\n", hdr, s);
+}
+
+static int lws_token_from_index(struct libwebsocket *wsi, int index)
+{
+       if (index < ARRAY_SIZE(static_token))
+               return static_token[index];
+       
+       // dynamic indexes
+       
+       return 0;
+}
+
+static int lws_add_indexed_hdr(struct libwebsocket *wsi, int idx)
+{
+       const char *p;
+       int tok = lws_token_from_index(wsi, idx);
+
+       lwsl_info("adding indexed hdr %d (tok %d)\n", idx, tok);
+
+       if (lws_frag_start(wsi, tok))
+               return 1;
+
+       if (idx < ARRAY_SIZE(http2_canned)) {
+               p = http2_canned[idx];
+               while (*p)
+                       if (lws_frag_append(wsi, *p++))
+                               return 1;
+       }
+       if (lws_frag_end(wsi))
+               return 1;
+       
+       lws_dump_header(wsi, tok);
+
+       return 0;
+}
+
+int lws_hpack_interpret(struct libwebsocket_context *context,
+                       struct libwebsocket *wsi, unsigned char c)
+{
+       unsigned int prev;
+       unsigned char c1;
+       int n;
+
        switch (wsi->u.http2.hpack) {
        case HPKS_TYPE:
                if (c & 0x80) { /* indexed header field only */
+                       /* just a possibly-extended integer */
+                       wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7;
                        wsi->u.http2.header_index = c & 0x7f;
+                       if ((c & 0x7f) == 0x7f) {
+                               wsi->u.http2.hpack_len = c & 0x7f;
+                               wsi->u.http2.hpack_m = 0;
+                               wsi->u.http2.hpack = HPKS_IDX_EXT;
+                               break;
+                       }
+                       if (lws_add_indexed_hdr(wsi, c & 0x7f))
+                               return 1;
                        /* stay at same state */
                        break;
                }
                if (c & 0x40) { /* literal header incr idx */
+                       /*
+                        * [possibly-extended hdr idx (6) | new literal hdr name]
+                        * H + possibly-extended value length
+                        * literal value
+                        */
+                       wsi->u.http2.header_index = 0;
                        if (c == 0x40) { /* literal name */
-                               wsi->u.http2.header_index = 0;
-                               wsi->u.http2.hpack
+                               wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
+                               wsi->u.http2.value = 0;
                                wsi->u.http2.hpack = HPKS_HLEN;
                                break;
                        }
                        /* indexed name */
+                       wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
+                       if ((c & 0x3f) == 0x3f) {
+                               wsi->u.http2.hpack_len = c & 0x3f;
+                               wsi->u.http2.hpack_m = 0;
+                               wsi->u.http2.hpack = HPKS_IDX_EXT;
+                               break;
+                       }
                        wsi->u.http2.header_index = c & 0x3f;
+                       wsi->u.http2.value = 1;
                        wsi->u.http2.hpack = HPKS_HLEN;
                        break;
                }
                switch(c & 0xf0) {
+               case 0x10: /* literal header never index */
                case 0: /* literal header without indexing */
+                       /* 
+                        * follows 0x40 except 4-bit hdr idx
+                        * and don't add to index
+                        */
                        if (c == 0) { /* literal name */
-                               wsi->u.http2.hpack = HPKS_NAME_HLEN;
+                               wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE;
+                               wsi->u.http2.hpack = HPKS_HLEN;
+                               wsi->u.http2.value = 0;
                                break;
                        }
                        /* indexed name */
-                       wsi->u.http2.header_index = c & 0xf;
-                       wsi->u.http2.hpack = HPKS_VALUE_HLEN;
-                       break;
-               case 0x10: /* literal header never indexed */
-                       if (c == 0x10) { /* literal name */
-                               wsi->u.http2.header_index = 0;
-                               wsi->u.http2.hpack = HPKS_NAME_HLEN;
+                       wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE;
+                       wsi->u.http2.header_index = 0;
+                       if ((c & 0xf) == 0xf) {
+                               wsi->u.http2.hpack_len = c & 0xf;
+                               wsi->u.http2.hpack_m = 0;
+                               wsi->u.http2.hpack = HPKS_IDX_EXT;
                                break;
                        }
-                       /* indexed name */
                        wsi->u.http2.header_index = c & 0xf;
-                       wsi->u.http2.hpack = HPKS_NAME_HLEN;
+                       wsi->u.http2.value = 1;
+                       wsi->u.http2.hpack = HPKS_HLEN;
                        break;
+
                case 0x20:
                case 0x30: /* header table size update */
-                       /* = c & 0x1f */
-                       /* stay at same state */
+                       /* possibly-extended size value (5) */
+                       wsi->u.http2.hpack_type = HPKT_SIZE_5;
+                       if ((c & 0x1f) == 0x1f) {
+                               wsi->u.http2.hpack_len = c & 0x1f;
+                               wsi->u.http2.hpack_m = 0;
+                               wsi->u.http2.hpack = HPKS_IDX_EXT;
+                               break;
+                       }
+                       lws_hpack_update_table_size(wsi, c & 0x1f);
+                       /* stay at HPKS_TYPE state */
                        break;
                }
-               break;  
-       case HPKS_HLEN:
+               break;
+               
+       case HPKS_IDX_EXT:
+               wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
+               wsi->u.http2.hpack_m += 7;
+               if (!(c & 0x80)) {
+                       switch (wsi->u.http2.hpack_type) {
+                       case HPKT_INDEXED_HDR_7:
+                               if (lws_add_indexed_hdr(wsi, wsi->u.http2.hpack_len))
+                                       return 1;
+                               wsi->u.http2.hpack = HPKS_TYPE;
+                               break;
+                       default:
+                               wsi->u.http2.header_index = wsi->u.http2.hpack_len;
+                               wsi->u.http2.value = 1;
+                               wsi->u.http2.hpack = HPKS_HLEN;
+                               break;
+                       }
+               }
+               break;
+
+       case HPKS_HLEN: /* [ H | 7+ ] */
                wsi->u.http2.huff = !!(c & 0x80);
+               wsi->u.http2.hpack_pos = 0;
                wsi->u.http2.hpack_len = c & 0x7f;
-               if (wsi->u.http2.hpack_len < 127) {
-                       wsi->u.http2.hpack = HPKS_NAME_DATA;
+               if (wsi->u.http2.hpack_len < 0x7f) {
+pre_data:
+                       if (wsi->u.http2.value) {
+                               if (lws_frag_start(wsi,
+                                       lws_token_from_index(wsi,
+                                               wsi->u.http2.header_index)))
+                                       return 1;
+                       } else
+                               wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
+                       wsi->u.http2.hpack = HPKS_DATA;
                        break;
                }
                wsi->u.http2.hpack_m = 0;
-               wsi->u.http2.hpack = HPKS_NAME_HLEN_EXT;
+               wsi->u.http2.hpack = HPKS_HLEN_EXT;
                break;
+               
        case HPKS_HLEN_EXT:
-               wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
+               wsi->u.http2.hpack_len += (c & 0x7f) <<
+                                       wsi->u.http2.hpack_m;
                wsi->u.http2.hpack_m += 7;
                if (!(c & 0x80))
-                       wsi->u.http2.hpack = HPKS_NAME_DATA;
+                       goto pre_data;
+
                break;
 
        case HPKS_DATA:
+               for (n = 0; n < 8; n++) {
+                       if (wsi->u.http2.huff) {
+                               prev = wsi->u.http2.hpack_pos;
+                               wsi->u.http2.hpack_pos = 
+                                       huftable_decode(
+                                               wsi->u.http2.hpack_pos,
+                                                       (c >> 7) & 1);
+                               c <<= 1;
+                               if (wsi->u.http2.hpack_pos == 0xffff)
+                                       return 1;
+                               if (!(wsi->u.http2.hpack_pos & 0x8000))
+                                       continue;
+                               c1 = wsi->u.http2.hpack_pos & 0x7fff;
+                               wsi->u.http2.hpack_pos = 0;
+       
+                               if (!c1 && prev == HUFTABLE_0x100_PREV)
+                                       ; /* EOT */
+                       } else {
+                               n = 8;
+                               c1 = c;
+                       }
+                       if (wsi->u.http2.value) { /* value */
+                               if (lws_frag_append(wsi, c1))
+                                       return 1;
+                       } else { /* name */
+                               if (libwebsocket_parse(context, wsi, c1))
+                                       return 1;
+                               
+                       }
+               }
+               if (--wsi->u.http2.hpack_len == 0) {
+                       n = 8;
+                       if (wsi->u.http2.value) {
+                               if (lws_frag_end(wsi))
+                                       return 1;
+
+                               lws_dump_header(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index));
 
+                               wsi->u.http2.hpack = HPKS_TYPE;
+                       } else { /* name */
+                               if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
+                                       
+                               wsi->u.http2.value = 1;
+                               wsi->u.http2.hpack = HPKS_HLEN;
+                       }
+               }
+               break;
        }
+       
+       return 0;
 }
index b9bed87..61d9d07 100644 (file)
@@ -66,6 +66,7 @@ lws_create_server_child_wsi(struct libwebsocket_context *context, struct libwebs
        lws_http2_init(&wsi->u.http2.peer_settings);
        lws_http2_init(&wsi->u.http2.my_settings);
        wsi->u.http2.stream_id = sid;
+       wsi->u.http2.my_stream_id = sid;
 
        wsi->u.http2.parent_wsi = parent_wsi;
        wsi->u.http2.next_child_wsi = parent_wsi->u.http2.next_child_wsi;
@@ -129,8 +130,12 @@ lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned c
 
 int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf)
 {
+       struct libwebsocket *wsi_eff = wsi;
        unsigned char *p = &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH];
        int n;
+       
+       while (wsi_eff->u.http2.parent_wsi)
+               wsi_eff = wsi_eff->u.http2.parent_wsi;
 
        *p++ = len >> 16;
        *p++ = len >> 8;
@@ -142,10 +147,10 @@ int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigne
        *p++ = sid >> 8;
        *p++ = sid;
        
-       lwsl_info("%s: %p. type %d, flags 0x%x, sid=%d, len=%d\n",
-                 __func__, wsi, type, flags, sid, len);
+       lwsl_info("%s: %p (eff %p). type %d, flags 0x%x, sid=%d, len=%d\n",
+                 __func__, wsi, wsi_eff, type, flags, sid, len);
 
-       n = lws_issue_raw(wsi, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH], len + LWS_HTTP2_FRAME_HEADER_LENGTH);
+       n = lws_issue_raw(wsi_eff, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH], len + LWS_HTTP2_FRAME_HEADER_LENGTH);
        if (n >= LWS_HTTP2_FRAME_HEADER_LENGTH)
                return n - LWS_HTTP2_FRAME_HEADER_LENGTH;
        
@@ -169,7 +174,8 @@ int
 lws_http2_parser(struct libwebsocket_context *context,
                     struct libwebsocket *wsi, unsigned char c)
 {
-       struct libwebsocket *wsi_new;
+       int n;
+       //dstruct libwebsocket *wsi_new;
 
        switch (wsi->state) {
        case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE:
@@ -206,19 +212,31 @@ lws_http2_parser(struct libwebsocket_context *context,
                                                return 1;
                                break;
                        case LWS_HTTP2_FRAME_TYPE_HEADERS:
-                               
+                               if (lws_hpack_interpret(context, wsi->u.http2.stream_wsi, c))
+                                       return 1;
                                break;
                        }
                        wsi->u.http2.count++;
-                       if (wsi->u.http2.count == wsi->u.http2.length) {
-                               wsi->u.http2.frame_state = 0;
-                               wsi->u.http2.count = 0;
-                               /* set our initial window size */
-                               if (!wsi->u.http2.initialized) {
-                                       wsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE];
-                                       lwsl_info("initial tx credit on master conn %p: %d\n", wsi, wsi->u.http2.tx_credit);
-                                       wsi->u.http2.initialized = 1;
-                               }
+                       if (wsi->u.http2.count != wsi->u.http2.length)
+                               break;
+                       
+                       /* end of frame */
+
+                       wsi->u.http2.frame_state = 0;
+                       wsi->u.http2.count = 0;
+                       /* set our initial window size */
+                       if (!wsi->u.http2.initialized) {
+                               wsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE];
+                               lwsl_info("initial tx credit on master conn %p: %d\n", wsi, wsi->u.http2.tx_credit);
+                               wsi->u.http2.initialized = 1;
+                       }
+                       switch (wsi->u.http2.type) {
+                       case LWS_HTTP2_FRAME_TYPE_HEADERS:
+                               /* service the http request itself */
+                               lwsl_info("servicing initial http request\n");
+                               n = lws_http_action(context, wsi->u.http2.stream_wsi);
+                               lwsl_info("  action result %d\n", n);
+                               break;
                        }
                        break;
                }
@@ -264,6 +282,7 @@ lws_http2_parser(struct libwebsocket_context *context,
                                }
                                break;
                        case LWS_HTTP2_FRAME_TYPE_HEADERS:
+                               lwsl_info("LWS_HTTP2_FRAME_TYPE_HEADERS: stream_id = %d\n", wsi->u.http2.stream_id);
                                if (!wsi->u.http2.stream_id)
                                        return 1;
                                wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
@@ -318,10 +337,6 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
                        wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
                        
                        wsi->u.http.fd = LWS_INVALID_FILE;
-                       
-                       /* service the http request itself */
-                       //lwsl_info("servicing initial http request\n");
-                       //n = lws_http_action(context, wsi);
 
                        return 0;
                }
index b7eb426..385a83b 100644 (file)
@@ -525,3 +525,6 @@ static unsigned char lextable[] = {
        0xcc, 0x30, 0xfc, 0xcf, 0x3c, 0xf0, 0x0c, 0xcf, 
        0xd0, 0x03, 0x3f, 0x33, 0xff, 0xff, 0xc3, 0xf3, 
 };
+
+/* state that points to 0x100 for disambiguation with 0x0 */
+#define HUFTABLE_0x100_PREV 118
index 84c1e95..50b8ff4 100644 (file)
@@ -326,7 +326,18 @@ enum lws_token_indexes {
        WSI_TOKEN_KEY,
        WSI_TOKEN_VERSION,
        WSI_TOKEN_SWORIGIN,
+       
+       WSI_TOKEN_HTTP_URI_ARGS,
+
+       /* use token storage to stash these */
 
+       _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
+       _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+       _WSI_TOKEN_CLIENT_URI,
+       _WSI_TOKEN_CLIENT_HOST,
+       _WSI_TOKEN_CLIENT_ORIGIN,
+
+#ifdef LWS_USE_HTTP2
        WSI_TOKEN_HTTP_COLON_AUTHORITY,
        WSI_TOKEN_HTTP_COLON_METHOD,
        WSI_TOKEN_HTTP_COLON_PATH,
@@ -366,17 +377,8 @@ enum lws_token_indexes {
        WSI_TOKEN_HTTP_VARY,
        WSI_TOKEN_HTTP_VIA,
        WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
+#endif
        
-       WSI_TOKEN_HTTP_URI_ARGS,
-
-       /* use token storage to stash these */
-
-       _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
-       _WSI_TOKEN_CLIENT_PEER_ADDRESS,
-       _WSI_TOKEN_CLIENT_URI,
-       _WSI_TOKEN_CLIENT_HOST,
-       _WSI_TOKEN_CLIENT_ORIGIN,
-
        /* always last real token index*/
        WSI_TOKEN_COUNT,
        /* parser state additions */
index 9f7b970..06d7b70 100644 (file)
@@ -482,6 +482,7 @@ again:
                fprintf(stderr, "  trying %d\n", n);
 
                while (m < huf_literal[n].len) {
+                       prev = walk;
                        walk = lextable_decode(walk, code_bit(n, m));
 
                        if (walk == 0xffff) {
@@ -491,8 +492,15 @@ again:
 
                        if (walk & 0x8000) {
                                y = walk & 0x7fff;
-                               if (y == 0 && m == 29)
+                               if (y == 0 && m == 29) {
                                        y |= 0x100;
+                                       fprintf(stdout, 
+                                               "\n/* state that points to "
+                                               "0x100 for disambiguation with "
+                                               "0x0 */\n"
+                                               "#define HUFTABLE_0x100_PREV "
+                                               "%d\n", prev);
+                               }
                                break;
                        }
                        m++;
index 40bb143..be1e544 100644 (file)
@@ -434,10 +434,14 @@ send_raw:
        case LWS_WRITE_PING:
 #ifdef LWS_USE_HTTP2
                if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) {
+                       unsigned char flags = 0;
+
                        n = LWS_HTTP2_FRAME_TYPE_DATA;
-                       if (protocol == LWS_WRITE_HTTP_HEADERS)
+                       if (protocol == LWS_WRITE_HTTP_HEADERS) {
                                n = LWS_HTTP2_FRAME_TYPE_HEADERS;
-                       return lws_http2_frame_write(wsi, n, 0, wsi->u.http2.my_stream_id, len, buf);
+                               flags = LWS_HTTP2_FLAGS__HEADER__END_HEADER;
+                       }
+                       return lws_http2_frame_write(wsi, n, flags, wsi->u.http2.my_stream_id, len, buf);
                }
 #endif
                return lws_issue_raw(wsi, (unsigned char *)buf - pre,
index cac681b..9d5f1b4 100755 (executable)
@@ -578,6 +578,7 @@ struct _lws_http_mode_related {
        int content_remain;
 };
 
+
 #ifdef LWS_USE_HTTP2
 
 enum lws_http2_settings {
@@ -610,6 +611,8 @@ enum lws_http2_wellknown_frame_types {
 #define LWS_HTTP2_FRAME_HEADER_LENGTH 9
 #define LWS_HTTP2_SETTINGS_LENGTH 6
 
+#define LWS_HTTP2_FLAGS__HEADER__END_HEADER 4
+
 struct http2_settings {
        unsigned int setting[LWS_HTTP2_SETTINGS__COUNT];
 };
@@ -617,12 +620,23 @@ struct http2_settings {
 enum http2_hpack_state {
        HPKS_TYPE,
        
+       HPKS_IDX_EXT,
+       
        HPKS_HLEN,
        HPKS_HLEN_EXT,
 
        HPKS_DATA,
 };
 
+enum http2_hpack_type {
+       HPKT_INDEXED_HDR_7,
+       HPKT_INDEXED_HDR_6_VALUE_INCR,
+       HPKT_LITERAL_HDR_VALUE_INCR,
+       HPKT_INDEXED_HDR_4_VALUE,
+       HPKT_LITERAL_HDR_VALUE,
+       HPKT_SIZE_5
+};
+
 struct _lws_http2_related {
        /* 
         * having this first lets us also re-use all HTTP union code
@@ -649,8 +663,10 @@ struct _lws_http2_related {
 
        /* hpack */
        enum http2_hpack_state hpack;
+       enum http2_hpack_type hpack_type;
        unsigned int header_index;
        unsigned int hpack_len;
+       unsigned short hpack_pos;
        unsigned char hpack_m;
        unsigned int huff:1;
        unsigned int value:1;
@@ -904,6 +920,9 @@ LWS_EXTERN int lws_http2_do_pps_send(struct libwebsocket_context *context, struc
 LWS_EXTERN int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf);
 LWS_EXTERN struct libwebsocket *
 lws_http2_wsi_from_id(struct libwebsocket *wsi, unsigned int sid);
+LWS_EXTERN int lws_hpack_interpret(struct libwebsocket_context *context,
+                                  struct libwebsocket *wsi,
+                                  unsigned char c);
 #endif
 
 LWS_EXTERN int
index 4d036a9..8563a43 100644 (file)
@@ -183,6 +183,9 @@ int lws_http_action(struct libwebsocket_context *context,
 
        if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
                !lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) &&
+#ifdef LWS_USE_HTTP2
+               !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH) &&
+#endif
                !lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
                lwsl_warn("Missing URI in HTTP request\n");
                goto bail_nuke_ah;
@@ -197,25 +200,33 @@ int lws_http_action(struct libwebsocket_context *context,
        if (libwebsocket_ensure_user_space(wsi))
                goto bail_nuke_ah;
 
-       if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
-               uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
-               uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
-               lwsl_info("HTTP GET request for '%s'\n",
-                               lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
+#ifdef LWS_USE_HTTP2
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)) {
+               uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH);
+               uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
+               lwsl_info("HTTP2 request for '%s'\n", uri_ptr);
+               goto got_uri;
+       }
+#endif
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
+               uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI);
+               uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI);
+               lwsl_info("HTTP OPTIONS request for '%s'\n", uri_ptr);
+               goto got_uri;
        }
        if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
-               lwsl_info("HTTP POST request for '%s'\n",
-                               lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI));
                uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI);
                uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
+               lwsl_info("HTTP POST request for '%s'\n", uri_ptr);
+               goto got_uri;
        }
-       if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
-               lwsl_info("HTTP OPTIONS request for '%s'\n",
-                               lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI));
-               uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI);
-               uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI);
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
+               uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
+               uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
+               lwsl_info("HTTP GET request for '%s'\n", uri_ptr);
        }
 
+got_uri:
        /* HTTP header had a content length? */
 
        wsi->u.http.content_length = 0;
index b89d014..24438d1 100644 (file)
@@ -112,21 +112,16 @@ dump_handshake_info(struct libwebsocket *wsi)
                /*[WSI_TOKEN_OPTIONS_URI]       =*/ "options uri",
                /*[WSI_TOKEN_HOST]              =*/ "Host",
                /*[WSI_TOKEN_CONNECTION]        =*/ "Connection",
-               /*[WSI_TOKEN_KEY1]              =*/ "key 1",
-               /*[WSI_TOKEN_KEY2]              =*/ "key 2",
-               /*[WSI_TOKEN_PROTOCOL]          =*/ "Protocol",
                /*[WSI_TOKEN_UPGRADE]           =*/ "Upgrade",
                /*[WSI_TOKEN_ORIGIN]            =*/ "Origin",
                /*[WSI_TOKEN_DRAFT]             =*/ "Draft",
                /*[WSI_TOKEN_CHALLENGE]         =*/ "Challenge",
-
-               /* new for 04 */
-               /*[WSI_TOKEN_KEY]               =*/ "Key",
-               /*[WSI_TOKEN_VERSION]           =*/ "Version",
-               /*[WSI_TOKEN_SWORIGIN]          =*/ "Sworigin",
-
                /* new for 05 */
                /*[WSI_TOKEN_EXTENSIONS]        =*/ "Extensions",
+               /*[WSI_TOKEN_KEY1]              =*/ "key 1",
+               /*[WSI_TOKEN_KEY2]              =*/ "key 2",
+
+               /*[WSI_TOKEN_PROTOCOL]          =*/ "Protocol",
 
                /* client receives these */
                /*[WSI_TOKEN_ACCEPT]            =*/ "Accept",
@@ -148,9 +143,12 @@ dump_handshake_info(struct libwebsocket *wsi)
                "Date:",
                "Range:",
                "Referer:",
+               /* new for 04 */
+               /*[WSI_TOKEN_KEY]               =*/ "Key",
+               /*[WSI_TOKEN_VERSION]           =*/ "Version",
+               /*[WSI_TOKEN_SWORIGIN]          =*/ "Sworigin",
                "Uri-Args:",
 
-               /*[WSI_TOKEN_MUXURL]    =*/ "MuxURL",
        };
        char buf[256];