summaryrefslogtreecommitdiff
path: root/src/http_decoder_table.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/http_decoder_table.cpp')
-rw-r--r--src/http_decoder_table.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/src/http_decoder_table.cpp b/src/http_decoder_table.cpp
new file mode 100644
index 0000000..d0f42f0
--- /dev/null
+++ b/src/http_decoder_table.cpp
@@ -0,0 +1,537 @@
+/*
+**********************************************************************************************
+* File: http_decoder_table.c
+* Description:
+* Authors: LuWenPeng <[email protected]>
+* Date: 2022-10-31
+* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
+***********************************************************************************************
+*/
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "http_decoder_inc.h"
+
+#define INIT_HEADER_CNT 16
+#define MAX_URI_CACHE_SIZE 2048
+#define MAX_STATUS_CACHE_SIZE 32
+#define MAX_METHOD_CACHE_SIZE 8
+#define MAX_VERSION_CACHE_SIZE 4
+#define MAX_HEADER_KEY_CACHE_SIZE 4096
+#define MAX_HEADER_VALUE_CACHE_SIZE 4096
+
+struct http_decoder_header {
+ struct http_decoder_string key;
+ struct http_decoder_string val;
+};
+
+struct http_decoder_table {
+ struct http_decoder_string uri;
+ struct http_decoder_string status;
+ struct http_decoder_string method;
+ struct http_decoder_string version;
+ struct http_decoder_string body;
+
+ nmx_pool_t *ref_mempool;
+ int header_complete; // flag for all headers parsed completely
+ size_t header_cnt;
+ size_t header_index;
+ size_t header_iter;
+ struct http_decoder_header *headers;
+};
+
+static void http_decoder_table_init(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ struct http_decoder_header *header = NULL;
+ assert(table);
+
+ http_decoder_string_init(&table->uri, MAX_URI_CACHE_SIZE);
+ http_decoder_string_init(&table->status, MAX_STATUS_CACHE_SIZE);
+ http_decoder_string_init(&table->method, MAX_METHOD_CACHE_SIZE);
+ http_decoder_string_init(&table->version, MAX_METHOD_CACHE_SIZE);
+
+ for (size_t i = 0; i < table->header_cnt; i++) {
+ header = &table->headers[i];
+ http_decoder_string_init(&header->key, MAX_HEADER_KEY_CACHE_SIZE);
+ http_decoder_string_init(&header->val, MAX_HEADER_VALUE_CACHE_SIZE);
+ }
+
+ http_decoder_string_init(&table->body, 0);
+}
+
+struct http_decoder_table *http_decoder_table_new(nmx_pool_t *mempool)
+{
+ struct http_decoder_table *table =
+ MEMPOOL_CALLOC(mempool, struct http_decoder_table, 1);
+ assert(table);
+
+ table->ref_mempool = mempool;
+ table->header_cnt = INIT_HEADER_CNT;
+ table->headers = MEMPOOL_CALLOC(mempool, struct http_decoder_header,
+ table->header_cnt);
+
+ http_decoder_table_init(table);
+
+ return table;
+}
+
+void http_decoder_table_free(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return;
+ }
+ if (table->uri.cache.str != NULL) {
+ FREE(table->uri.cache.str);
+ }
+ if (table->status.cache.str != NULL) {
+ FREE(table->status.cache.str);
+ }
+ if (table->method.cache.str != NULL) {
+ FREE(table->method.cache.str);
+ }
+ if (table->version.cache.str != NULL) {
+ FREE(table->version.cache.str);
+ }
+ if (table->body.cache.str != NULL) {
+ FREE(table->body.cache.str);
+ }
+
+ if (table->headers != NULL) {
+ for (size_t i = 0; i < table->header_cnt; i++) {
+ if (table->headers[i].key.cache.str != NULL) {
+ FREE(table->headers[i].key.cache.str);
+ }
+
+ if (table->headers[i].val.cache.str != NULL) {
+ FREE(table->headers[i].val.cache.str);
+ }
+ }
+
+ MEMPOOL_FREE(table->ref_mempool, table->headers);
+ table->headers = NULL;
+ }
+ MEMPOOL_FREE(table->ref_mempool, table);
+}
+
+enum string_state
+http_decoder_table_state(struct http_decoder_table *table, enum http_item type)
+{
+ if (NULL == table) {
+ return STRING_STATE_INIT;
+ }
+ struct http_decoder_header *header = NULL;
+ enum string_state state = STRING_STATE_INIT;
+ assert(table);
+
+ switch (type) {
+ case HTTP_ITEM_URI:
+ state = http_decoder_string_state(&table->uri);
+ break;
+ case HTTP_ITEM_STATUS:
+ state = http_decoder_string_state(&table->status);
+ break;
+ case HTTP_ITEM_METHOD:
+ state = http_decoder_string_state(&table->method);
+ break;
+ case HTTP_ITEM_VERSION:
+ state = http_decoder_string_state(&table->version);
+ break;
+ case HTTP_ITEM_HDRKEY:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ state = http_decoder_string_state(&header->key);
+ break;
+ case HTTP_ITEM_HDRVAL:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ state = http_decoder_string_state(&header->val);
+ break;
+ case HTTP_ITEM_BODY:
+ state = http_decoder_string_state(&table->body);
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ return state;
+}
+
+void http_decoder_table_refer(struct http_decoder_table *table, enum http_item type,
+ const char *at, size_t len)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ struct http_decoder_header *header = NULL;
+ assert(table);
+
+ switch (type) {
+ case HTTP_ITEM_URI:
+ http_decoder_string_refer(&table->uri, at, len);
+ break;
+ case HTTP_ITEM_STATUS:
+ http_decoder_string_refer(&table->status, at, len);
+ break;
+ case HTTP_ITEM_METHOD:
+ http_decoder_string_refer(&table->method, at, len);
+ break;
+ case HTTP_ITEM_VERSION:
+ http_decoder_string_refer(&table->version, at, len);
+ break;
+ case HTTP_ITEM_HDRKEY:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ http_decoder_string_refer(&header->key, at, len);
+ break;
+ case HTTP_ITEM_HDRVAL:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ http_decoder_string_refer(&header->val, at, len);
+ break;
+ case HTTP_ITEM_BODY:
+ http_decoder_string_refer(&table->body, at, len);
+ break;
+ default:
+ abort();
+ break;
+ }
+}
+
+void http_decoder_table_cache(struct http_decoder_table *table, enum http_item type)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ struct http_decoder_header *header = NULL;
+ assert(table);
+
+ switch (type) {
+ case HTTP_ITEM_URI:
+ http_decoder_string_cache(&table->uri);
+ break;
+ case HTTP_ITEM_STATUS:
+ http_decoder_string_cache(&table->status);
+ break;
+ case HTTP_ITEM_METHOD:
+ http_decoder_string_cache(&table->method);
+ break;
+ case HTTP_ITEM_VERSION:
+ http_decoder_string_cache(&table->version);
+ break;
+ case HTTP_ITEM_HDRKEY:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ http_decoder_string_cache(&header->key);
+ break;
+ case HTTP_ITEM_HDRVAL:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ http_decoder_string_cache(&header->val);
+ break;
+ case HTTP_ITEM_BODY:
+ http_decoder_string_cache(&table->body);
+ break;
+ default:
+ abort();
+ break;
+ }
+}
+
+void http_decoder_table_commit(struct http_decoder_table *table, enum http_item type)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ size_t i = 0;
+ struct http_decoder_header *header = NULL;
+ assert(table);
+
+ switch (type) {
+ case HTTP_ITEM_URI:
+ http_decoder_string_commit(&table->uri);
+ break;
+ case HTTP_ITEM_STATUS:
+ http_decoder_string_commit(&table->status);
+ break;
+ case HTTP_ITEM_METHOD:
+ http_decoder_string_commit(&table->method);
+ break;
+ case HTTP_ITEM_VERSION:
+ http_decoder_string_commit(&table->version);
+ break;
+ case HTTP_ITEM_HDRKEY:
+ assert(table->header_index < table->header_cnt);
+ header = &table->headers[table->header_index];
+ http_decoder_string_commit(&header->key);
+ break;
+ case HTTP_ITEM_HDRVAL:
+ header = &table->headers[table->header_index];
+ http_decoder_string_commit(&header->val);
+ // inc index
+ if ((table->header_index + 1) >= table->header_cnt) {
+ struct http_decoder_header *old_headers = table->headers;
+ table->headers =
+ MEMPOOL_CALLOC(table->ref_mempool, struct http_decoder_header,
+ table->header_cnt * 2);
+ table->header_cnt *= 2;
+
+ for (i = 0; i <= table->header_index; i++) {
+ table->headers[i] = old_headers[i];
+ }
+
+ MEMPOOL_FREE(table->ref_mempool, old_headers);
+
+ for (i = table->header_index + 1; i < table->header_cnt; i++) {
+ header = &table->headers[i];
+ memset(header, 0, sizeof(struct http_decoder_header));
+ http_decoder_string_init(&header->key, MAX_HEADER_KEY_CACHE_SIZE);
+ http_decoder_string_init(&header->val, MAX_HEADER_VALUE_CACHE_SIZE);
+ }
+ }
+ table->header_index++;
+ break;
+ case HTTP_ITEM_BODY:
+ http_decoder_string_commit(&table->body);
+ break;
+ default:
+ abort();
+ break;
+ }
+}
+
+void http_decoder_table_reset(struct http_decoder_table *table, enum http_item type)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ struct http_decoder_header *header = NULL;
+ assert(table);
+
+ switch (type) {
+ case HTTP_ITEM_URI:
+ http_decoder_string_reset(&table->uri);
+ break;
+ case HTTP_ITEM_STATUS:
+ http_decoder_string_reset(&table->status);
+ break;
+ case HTTP_ITEM_METHOD:
+ http_decoder_string_reset(&table->method);
+ break;
+ case HTTP_ITEM_VERSION:
+ http_decoder_string_reset(&table->version);
+ break;
+ case HTTP_ITEM_HDRKEY:
+ header = &table->headers[table->header_index];
+ http_decoder_string_reset(&header->key);
+ break;
+ case HTTP_ITEM_HDRVAL:
+ header = &table->headers[table->header_index];
+ http_decoder_string_reset(&header->val);
+ break;
+ case HTTP_ITEM_BODY:
+ http_decoder_string_reset(&table->body);
+ break;
+ default:
+ abort();
+ break;
+ }
+}
+
+void http_decoder_table_reinit(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ struct http_decoder_header *header = NULL;
+ assert(table);
+
+ http_decoder_string_reinit(&table->uri);
+ http_decoder_string_reinit(&table->status);
+ http_decoder_string_reinit(&table->method);
+ http_decoder_string_reinit(&table->version);
+ for (size_t i = 0; i < table->header_iter; i++) {
+ header = &table->headers[i];
+ http_decoder_string_reinit(&header->key);
+ http_decoder_string_reinit(&header->val);
+ }
+
+ http_decoder_string_reinit(&table->body);
+}
+
+void http_decoder_table_dump(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return;
+ }
+
+ http_decoder_string_dump(&table->uri, "uri");
+ http_decoder_string_dump(&table->status, "status");
+ http_decoder_string_dump(&table->method, "method");
+ http_decoder_string_dump(&table->version, "version");
+ http_decoder_string_dump(&table->body, "body");
+
+ for (size_t i = 0; i < table->header_cnt; i++) {
+ struct http_decoder_header *header = &table->headers[i];
+ if (NULL == header) {
+ continue;
+ }
+
+ http_decoder_string_dump(&header->key, "key");
+ http_decoder_string_dump(&header->val, "val");
+ }
+}
+
+int http_decoder_table_get_uri(struct http_decoder_table *table, struct hstring *out)
+{
+ if (NULL == table || NULL == out) {
+ return -1;
+ }
+ return http_decoder_string_get(&table->uri, out);
+}
+
+int http_decoder_table_get_method(struct http_decoder_table *table, struct hstring *out)
+{
+ if (NULL == table || NULL == out) {
+ return -1;
+ }
+ return http_decoder_string_get(&table->method, out);
+}
+
+int http_decoder_table_get_status(struct http_decoder_table *table, struct hstring *out)
+{
+ if (NULL == table || NULL == out) {
+ return -1;
+ }
+ return http_decoder_string_get(&table->status, out);
+}
+
+int http_decoder_table_get_version(struct http_decoder_table *table, struct hstring *out)
+{
+ if (NULL == table || NULL == out) {
+ return -1;
+ }
+ return http_decoder_string_get(&table->version, out);
+}
+
+int http_decoder_table_get_body(struct http_decoder_table *table, struct hstring *out)
+{
+ if (NULL == table || NULL == out) {
+ return -1;
+ }
+ return http_decoder_string_get(&table->body, out);
+}
+
+int http_decoder_table_get_header(struct http_decoder_table *table, struct hstring *key,
+ struct http_header *hdr_result)
+{
+ if (NULL == table || NULL == key->str || 0 == key->str_len || NULL == hdr_result) {
+ return -1;
+ }
+
+ for (size_t i = 0; i < table->header_cnt; i++) {
+ struct http_decoder_header *tmp_header = &table->headers[i];
+ if (tmp_header->key.commit.str_len != key->str_len) {
+ continue;
+ }
+
+ if (http_decoder_string_state(&tmp_header->key) == STRING_STATE_COMMIT &&
+ http_decoder_string_state(&tmp_header->val) == STRING_STATE_COMMIT) {
+ struct hstring tmp_key;
+ http_decoder_string_get(&tmp_header->key, &tmp_key);
+
+ if (tmp_key.str_len == key->str_len &&
+ (0 == strncasecmp(tmp_key.str, key->str, key->str_len))) {
+ http_decoder_string_get(&tmp_header->key, &hdr_result->key);
+ http_decoder_string_get(&tmp_header->val, &hdr_result->val);
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int http_decoder_table_iter_header(struct http_decoder_table *table,
+ struct http_header *hdr)
+{
+ if (NULL == table || NULL == hdr) {
+ return -1;
+ }
+ if (table->header_iter >= table->header_cnt) {
+ return -1;
+ }
+
+ struct http_decoder_header *tmp_header = &table->headers[table->header_iter];
+ if (tmp_header != NULL) {
+ if (http_decoder_string_state(&tmp_header->key) == STRING_STATE_COMMIT &&
+ http_decoder_string_state(&tmp_header->val) == STRING_STATE_COMMIT) {
+
+ http_decoder_string_get(&tmp_header->key, &hdr->key);
+ http_decoder_string_get(&tmp_header->val, &hdr->val);
+ table->header_iter++;
+ return 0;
+ }
+ }
+
+ hdr->key.str = NULL;
+ hdr->key.str_len = 0;
+ hdr->val.str = NULL;
+ hdr->val.str_len = 0;
+
+ return -1;
+}
+
+int http_decoder_table_reset_header_iter(struct http_decoder_table *table)
+{
+ table->header_iter = 0;
+ return 0;
+}
+
+int http_decoder_table_has_parsed_header(struct http_decoder_table *table)
+{
+ if (NULL == table || (table->header_iter == table->header_index)) {
+ return 0;
+ }
+
+ struct http_decoder_header *tmp_header = &table->headers[table->header_iter];
+ if (http_decoder_string_state(&tmp_header->key) == STRING_STATE_COMMIT &&
+ http_decoder_string_state(&tmp_header->val) == STRING_STATE_COMMIT) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int http_decoder_table_header_complete(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return -1;
+ }
+ return table->header_complete;
+}
+
+void http_decoder_table_set_header_complete(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return;
+ }
+ table->header_complete = 1;
+}
+
+void http_decoder_table_reset_header_complete(struct http_decoder_table *table)
+{
+ if (NULL == table) {
+ return;
+ }
+ table->header_complete = 0;
+} \ No newline at end of file