Skip to content

Commit

Permalink
HTTP/2 Parser implementation (#309):
Browse files Browse the repository at this point in the history
1. Changes in HPACK decoder to copy only Huffman-decoded and dynamically indexed headers;
2. Appropriate changes in HPACK-decoder/parser unit-tests.
  • Loading branch information
aleksostapenko committed Oct 30, 2019
1 parent 71d7b7a commit dc71702
Show file tree
Hide file tree
Showing 10 changed files with 771 additions and 508 deletions.
394 changes: 186 additions & 208 deletions tempesta_fw/hpack.c

Large diffs are not rendered by default.

27 changes: 10 additions & 17 deletions tempesta_fw/hpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,6 @@ typedef struct {
TFW_HPACK_ETBL_COMMON;
} TfwHPackETblIter;

/**
* HPack strings representation.
*
* @ptr - pointer to the actual string data;
* @len - length of the string;
* @count - number of users of the string instance.
*/
typedef struct {
char *ptr;
unsigned long len;
int count;
} TfwHPackStr;

typedef enum {
TFW_H2_TRANS_ADD = 0,
TFW_H2_TRANS_EXPAND,
Expand Down Expand Up @@ -153,23 +140,28 @@ typedef enum {
/**
* Representation of the entry in HPack decoder index.
*
* @hdr - pointer to the header data descriptor;
* @name_len - length of the header's name part;
* @name_num - chunks count of the header's name part;
* @tag - tag of the indexed header;
* @hdr - descriptor of the header data.
* @last - flag bit indicating that corresponding header is the last on the page.
*/
typedef struct {
TfwStr *hdr;
unsigned long name_len;
unsigned int name_num;
unsigned long name_num;
unsigned int tag;
TfwStr hdr[0];
unsigned char last : 1;
} TfwHPackEntry;

/**
* HPack decoder dynamic index table.
*
* @entries - dynamic table of entries;
* @pool - memory pool for dynamic table;
* @pool - memory pool for constantly sized entries (i.e. the entry
* descriptors);
* @h_pool - memory pool for entries of variable size (headers themselves
* - and @TfwStr descriptors for them);
* @n - actual number of entries in the table;
* @curr - circular buffer index of recent entry;
* @length - current length of the dynamic table (in entries);
Expand All @@ -180,6 +172,7 @@ typedef struct {
typedef struct {
TfwHPackEntry *entries;
TfwPool *pool;
TfwPool *h_pool;
unsigned int n;
unsigned int curr;
unsigned int length;
Expand Down
3 changes: 0 additions & 3 deletions tempesta_fw/http_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +922,6 @@ tfw_h2_apply_settings_entry(TfwH2Ctx *ctx, unsigned short id,
return T_OK;
}

/*
* TODO #309: apply settings entry.
*/
return T_OK;
}

Expand Down
40 changes: 39 additions & 1 deletion tempesta_fw/http_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,35 @@ __http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val, bool client)
}
EXPORT_SYMBOL(__http_msg_hdr_val);

void
__h2_msg_hdr_name(TfwStr *hdr, TfwStr *out_name)
{
TfwStr *c, *end;

if (unlikely(TFW_STR_EMPTY(hdr))) {
TFW_STR_INIT(out_val);
return;
}

BUG_ON(TFW_STR_DUP(hdr));
BUG_ON(TFW_STR_EMPTY(hdr));

*out_name = *hdr;

if (unlikely(TFW_STR_PLAIN(hdr))) {
WARN_ON_ONCE(hdr->flags & TFW_STR_HDR_VALUE)
return;
}

TFW_STR_FOR_EACH_CHUNK(c, hdr, end) {
if (c->flags & TFW_STR_HDR_VALUE) {
out_name->len -= c->len;
out_name->nchunks--;
}
}
}
EXPORT_SYMBOL(__h2_msg_hdr_name);

void
__h2_msg_hdr_val(TfwStr *hdr, TfwStr *out_val)
{
Expand All @@ -277,6 +306,7 @@ __h2_msg_hdr_val(TfwStr *hdr, TfwStr *out_val)
/* Empty header value part. */
TFW_STR_INIT(out_val);
}
EXPORT_SYMBOL(__h2_msg_hdr_val);

/**
* Slow check of generic (raw) header for singularity.
Expand Down Expand Up @@ -504,7 +534,15 @@ tfw_http_msg_hdr_close(TfwHttpMsg *hm)
* Both the headers, the new one and existing one, can already be
* compound.
*/
id = __hdr_lookup(hm, &parser->hdr);
if (TFW_MSG_H2(hm)) {
TfwStr h_name;

__h2_msg_hdr_name(&parser->hdr, &h_name);
id = __h2_hdr_lookup(hm, &h_name);
}
else {
id = __hdr_lookup(hm, &parser->hdr);
}

/* Allocate some more room if not enough to store the header. */
if (unlikely(id == ht->size)) {
Expand Down
1 change: 1 addition & 0 deletions tempesta_fw/http_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ __tfw_http_msg_set_str_data(TfwStr *str, void *data, struct sk_buff *skb)
__tfw_http_msg_set_str_data(str, data, \
ss_skb_peek_tail(&hm->msg.skb_head))

void __h2_msg_hdr_name(TfwStr *hdr, TfwStr *out_name);
void __h2_msg_hdr_val(TfwStr *hdr, TfwStr *out_val);
void __http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val, bool client);

Expand Down
4 changes: 0 additions & 4 deletions tempesta_fw/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ typedef struct {
* @hb_len - length of the message HTTP/2 headers block;
* @hdrs_len - accumulated length of message's decoded and parsed headers;
* @hdrs_cnt - count of all headers from message headers block;
* @start_pos - pointer to the beginning of decoded headers' buffer; used
* as start point during exporting buffer pages to message's
* target skb;
* @__off - offset for iterator reinitializing before next processing
* stage;
* @hdr - descriptor of currently decoded header in target buffer;
Expand All @@ -90,7 +87,6 @@ typedef struct {
unsigned long hb_len;
unsigned long hdrs_len;
unsigned int hdrs_cnt;
char *start_pos;
char __off[0];
TfwStr hdr;
char *pos;
Expand Down
23 changes: 17 additions & 6 deletions tempesta_fw/pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,25 +212,36 @@ tfw_pool_free(TfwPool *p, void *ptr, size_t n)
EXPORT_SYMBOL(tfw_pool_free);

/**
* Delete all chunks between the last (i.e. current in use) and the first one
* Delete all chunks between the first (i.e. current in use) and the last one
* (which is the holder of @TfwPool itself). This is a garbage collection
* procedure, which is applicable only for cases when pool is used for one
* dynamically resizable (via @__tfw_pool_realloc()) instance.
* dynamically resizable (via @__tfw_pool_realloc()) instance. Also, this
* function can be used when caller definitely know, that all data behind the
* @ptr can be evicted (including the page which contains the @ptr).
*/
void
tfw_pool_clean(TfwPool *p)
tfw_pool_clean(TfwPool *pool, void *ptr)
{
TfwPoolChunk *c, *next;

if (!p)
if (!pool)
return;

for (c = p->curr->next; c; c = next) {
for (c = pool->curr->next; c; c = next) {
if (!(next = c->next))
break;
if (ptr) {
if ((char *)ptr < (char *)TFW_POOL_CHUNK_BASE(c)
|| (char *)ptr >= (char *)TFW_POOL_CHUNK_BASE(c)
+ c->off)
{
continue;
}
ptr = NULL;
}
tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(c), c->order);
}
p->curr->next = c;
pool->curr->next = c;
}
EXPORT_SYMBOL(tfw_pool_clean);

Expand Down
Loading

0 comments on commit dc71702

Please sign in to comment.