http2 track content length add END_STREAM

Signed-off-by: Andy Green <andy.green@linaro.org>
diff --git a/lib/hpack.c b/lib/hpack.c
index bd4f462..4b2a1a8 100644
--- a/lib/hpack.c
+++ b/lib/hpack.c
@@ -238,25 +238,96 @@
 	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);
+	lwsl_info("  hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s);
 }
 
-static int lws_token_from_index(struct libwebsocket *wsi, int index)
+static int lws_token_from_index(struct libwebsocket *wsi, int index, char **arg, int *len)
 {
+	struct hpack_dynamic_table *dyn;
+	
+	/* dynamic table only belongs to network wsi */
+	
+	wsi = lws_http2_get_network_wsi(wsi);
+	
+	dyn = wsi->u.http2.hpack_dyn_table;
+
 	if (index < ARRAY_SIZE(static_token))
 		return static_token[index];
+
+	if (!dyn)
+		return 0;
 	
-	// dynamic indexes
+	index -= ARRAY_SIZE(static_token);
+	if (index >= dyn->num_entries)
+		return 0;
 	
-	return 0;
+	if (arg && len) {
+		*arg = dyn->args + dyn->entries[index].arg_offset;
+		*len = dyn->entries[index].arg_len;
+	}
+	
+	return dyn->entries[index].token;
 }
 
-static int lws_add_indexed_hdr(struct libwebsocket *wsi, int idx)
+static int lws_hpack_add_dynamic_header(struct libwebsocket *wsi, int token, char *arg, int len)
+{
+	struct hpack_dynamic_table *dyn;
+	int ret = 1;
+	
+	wsi = lws_http2_get_network_wsi(wsi);
+	dyn = wsi->u.http2.hpack_dyn_table;
+
+	if (!dyn) {
+		dyn = malloc(sizeof(*dyn));
+		if (!dyn)
+			return 1;
+		memset(dyn, 0, sizeof(*dyn));
+		wsi->u.http2.hpack_dyn_table = dyn;
+		
+		dyn->args = malloc(1024);
+		if (!dyn->args)
+			goto bail1;
+		dyn->args_length = 1024;
+		dyn->entries = malloc(sizeof(dyn->entries[0]) * 20);
+		if (!dyn->entries)
+			goto bail2;
+		dyn->num_entries = 20;
+	}
+	
+	if (dyn->next == dyn->num_entries)
+		return 1;
+	
+	if (dyn->args_length - dyn->pos < len)
+		return 1;
+	
+	dyn->entries[dyn->next].token = token;
+	dyn->entries[dyn->next].arg_offset = dyn->pos;
+	if (len)
+		memcpy(dyn->args + dyn->pos, arg, len);
+	dyn->entries[dyn->next].arg_len = len;
+	
+	lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n", __func__, dyn->next, token, lws_token_to_string(token), len);
+	
+	dyn->pos += len;
+	dyn->next++;
+	
+	return 0;
+	
+bail2:
+	free(dyn->args);
+bail1:
+	free(dyn);
+	wsi->u.http2.hpack_dyn_table = NULL;
+		
+	return ret;
+}
+
+static int lws_write_indexed_hdr(struct libwebsocket *wsi, int idx)
 {
 	const char *p;
-	int tok = lws_token_from_index(wsi, idx);
+	int tok = lws_token_from_index(wsi, idx, NULL, 0);
 
-	lwsl_info("adding indexed hdr %d (tok %d)\n", idx, tok);
+	lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok, lws_token_to_string(tok));
 
 	if (lws_frag_start(wsi, tok))
 		return 1;
@@ -283,6 +354,28 @@
 	int n;
 
 	switch (wsi->u.http2.hpack) {
+	case HPKS_OPT_PADDING:
+		wsi->u.http2.padding = c;
+		lwsl_info("padding %d\n", c);
+		if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) {
+			wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY;
+			wsi->u.http2.hpack_m = 4;
+		} else
+			wsi->u.http2.hpack = HPKS_TYPE;
+		break;
+	case HKPS_OPT_E_DEPENDENCY:
+		wsi->u.http2.hpack_e_dep <<= 8;
+		wsi->u.http2.hpack_e_dep |= c;
+		if (! --wsi->u.http2.hpack_m) {
+			lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep);
+			wsi->u.http2.hpack = HKPS_OPT_WEIGHT;
+		}
+		break;
+	case HKPS_OPT_WEIGHT:
+		/* weight */
+		wsi->u.http2.hpack = HPKS_TYPE;
+		break;
+			
 	case HPKS_TYPE:
 		if (c & 0x80) { /* indexed header field only */
 			/* just a possibly-extended integer */
@@ -294,7 +387,7 @@
 				wsi->u.http2.hpack = HPKS_IDX_EXT;
 				break;
 			}
-			if (lws_add_indexed_hdr(wsi, c & 0x7f))
+			if (lws_write_indexed_hdr(wsi, c & 0x7f))
 				return 1;
 			/* stay at same state */
 			break;
@@ -374,7 +467,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))
+				if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len))
 					return 1;
 				wsi->u.http2.hpack = HPKS_TYPE;
 				break;
@@ -396,7 +489,7 @@
 			if (wsi->u.http2.value) {
 				if (lws_frag_start(wsi,
 					lws_token_from_index(wsi,
-				  		wsi->u.http2.header_index)))
+				  		wsi->u.http2.header_index, NULL, NULL)))
 					return 1;
 			} else
 				wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
@@ -448,14 +541,27 @@
 			}
 		}
 		if (--wsi->u.http2.hpack_len == 0) {
+			
+			switch (wsi->u.http2.hpack_type) {
+			case HPKT_LITERAL_HDR_VALUE_INCR:
+			case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!!
+				if (lws_hpack_add_dynamic_header(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index, NULL, NULL), NULL, 0))
+					return 1;
+				break;
+			default:
+				break;
+			}
+			
 			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;
+				lws_dump_header(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index, NULL, NULL));
+				if (wsi->u.http2.count + wsi->u.http2.padding == wsi->u.http2.length)
+					wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING;
+				else
+					wsi->u.http2.hpack = HPKS_TYPE;
 			} else { /* name */
 				if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
 					
@@ -464,6 +570,11 @@
 			}
 		}
 		break;
+	case HKPS_OPT_DISCARD_PADDING:
+		lwsl_info("eating padding %x\n", c);
+		if (! --wsi->u.http2.padding)
+			wsi->u.http2.hpack = HPKS_TYPE;
+		break;
 	}
 	
 	return 0;