This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
stellar-stellar/decoders/http/http_decoder_half.c

1188 lines
36 KiB
C

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include "http_decoder_private.h"
#include "llhttp.h"
#include "uthash/utlist.h"
struct http_decompress_buffer
{
struct iovec iov;
char is_commit;
struct http_decompress_buffer *next, *prev;
};
struct http_decoder_half_data
{
struct http_decoder_table *table;
int major_version;
int minor_version;
int status_code;
enum http_event state;
enum http_content_encoding content_encoding;
struct http_content_decompress *decompress;
#if 0
char *ref_decompress_body;
size_t decompress_body_len;
#else
struct http_decompress_buffer *decompress_buffer_list;
#endif
int joint_url_complete;
int url_is_encoded;
// http://<host>[:<port>]/<path>?<searchpart>
hstring joint_url;
hstring decoded_url;
long long transaction_index;
};
struct http_decoder_half
{
llhttp_t parser;
llhttp_settings_t settings;
enum llhttp_errno error;
int decompress_switch;
struct http_decoder_env *httpd_env;
// uint8_t is_request_flow;
enum http_event event;
http_event_cb *http_ev_cb;
struct http_event_context *http_ev_ctx;
struct http_decoder_half_data *ref_data;
long long trans_counter;
long long err_counter;
long long transaction_seq; // accumulated
const char *data;
int data_len;
};
// #define HTTP_DECODER_DEBUG
#ifdef HTTP_DECODER_DEBUG
static void printf_debug_info(const char *desc, const char *at, size_t length)
{
if (at)
{
char *temp = http_safe_dup(at, length);
printf("HTTP PARSER STAGE: %s: %s\n", desc, temp);
FREE(temp);
}
else
{
printf("HTTP PARSER STAGE: %s\n", desc);
}
}
#else
#define printf_debug_info(desc, at, length)
#endif
void http_half_decompress_buffer_free(struct http_decoder_half_data *data, hstring *decompress_body)
{
struct http_decompress_buffer *el, *tmp;
DL_FOREACH_SAFE(data->decompress_buffer_list, el, tmp)
{
if (el->iov.iov_base == decompress_body->iov_base && el->iov.iov_len == decompress_body->iov_len)
{
DL_DELETE(data->decompress_buffer_list, el);
if (el->iov.iov_base)
{
FREE(el->iov.iov_base);
}
FREE(el);
break;
}
}
}
void http_half_get_lastest_decompress_buffer(struct http_decoder_half_data *data, hstring *decompress_body)
{
if (data->content_encoding == HTTP_CONTENT_ENCODING_NONE)
{
return;
}
if (data->decompress_buffer_list == NULL)
{
decompress_body->iov_base = NULL;
decompress_body->iov_len = 0;
return;
}
if (data->decompress_buffer_list->prev->is_commit == 1)
{
decompress_body->iov_base = NULL;
decompress_body->iov_len = 0;
return;
}
decompress_body->iov_base = data->decompress_buffer_list->prev->iov.iov_base;
decompress_body->iov_len = data->decompress_buffer_list->prev->iov.iov_len;
data->decompress_buffer_list->prev->is_commit = 1;
}
static void http_decoder_half_data_decompress(struct http_decoder_half_data *data)
{
assert(data);
if (data->content_encoding == HTTP_CONTENT_ENCODING_NONE)
{
return;
}
hstring raw_body = {};
http_decoder_table_get_body(data->table, (char **)&raw_body.iov_base, &raw_body.iov_len);
if (raw_body.iov_base == NULL || raw_body.iov_len == 0)
{
return;
}
if (NULL == data->decompress)
{
data->decompress = http_content_decompress_create(data->content_encoding);
}
assert(data->decompress);
char *local_outdata = NULL;
size_t local_outdata_len = 0;
if (http_content_decompress_write(data->decompress, (char *)raw_body.iov_base,
raw_body.iov_len,
&local_outdata,
&local_outdata_len) == -1)
{
// log error
http_content_decompress_destroy(data->decompress);
data->decompress = NULL;
return;
}
if (local_outdata != NULL && local_outdata_len > 0)
{
struct http_decompress_buffer *decompress_buffer = CALLOC(struct http_decompress_buffer, 1);
assert(decompress_buffer);
decompress_buffer->iov.iov_base = local_outdata;
decompress_buffer->iov.iov_len = local_outdata_len;
DL_APPEND(data->decompress_buffer_list, decompress_buffer);
http_content_decompress_ownership_borrow(data->decompress);
}
}
/* Possible return values 0, -1, `HPE_PAUSED` */
static int on_message_begin(llhttp_t *http)
{
printf_debug_info("on_message_begin", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (half->parser.type == HTTP_REQUEST)
{
half->event = HTTP_EVENT_REQ_INIT;
}
else
{
half->event = HTTP_EVENT_RES_INIT;
}
half->ref_data = NULL;
assert(half->http_ev_cb != NULL);
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env); // http_event_handler()
half->trans_counter++;
half->ref_data->transaction_index = half->transaction_seq++;
return 0;
}
static int on_message_complete(llhttp_t *http)
{
printf_debug_info("on_message_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (half->parser.type == HTTP_REQUEST)
{
if (half->event == HTTP_EVENT_REQ_BODY_DATA)
{
half->event = HTTP_EVENT_REQ_BODY_END;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
}
else
{
if (half->event == HTTP_EVENT_RES_BODY_DATA)
{
half->event = HTTP_EVENT_RES_BODY_END;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
}
// trigger req_end/res_end
if (half->parser.type == HTTP_REQUEST)
{
half->event = HTTP_EVENT_REQ_END;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
else
{
half->event = HTTP_EVENT_RES_END;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
return 0;
}
static int on_reset(llhttp_t *http __attribute__((unused)))
{
printf_debug_info("on_reset", NULL, 0);
return 0;
}
static inline int is_line_crlf(struct http_decoder_half *half)
{
const char *chr_r = (char *)memrchr(half->data, '\r', half->data_len);
const char *chr_n = (char *)memrchr(half->data, '\n', half->data_len);
if (chr_r && chr_n && (chr_r + 1 == chr_n))
{
return 1;
}
return 0;
}
static int on_method(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_method", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_METHOD, at, length);
return 0;
}
/* Information-only callbacks, return value is ignored */
static int on_method_complete(llhttp_t *http)
{
printf_debug_info("on_method_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (is_line_crlf(half) == 0)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_METHOD);
}
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_METHOD);
return 0;
}
/* Possible return values 0, -1, HPE_USER */
static int on_uri(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_uri", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_URI, at, length);
return 0;
}
static void http_decoder_cached_portion_url(struct http_decoder_half *half, const hstring *uri_result)
{
struct http_decoder_half_data *ref_data = half->ref_data;
int uri_skip_len = 0;
if ((uri_result->iov_len) > 7 && (strncasecmp("http://", (char *)uri_result->iov_base, 7) == 0)) // absolute URI
{
uri_skip_len = strlen("http://");
ref_data->joint_url_complete = 1;
}
else
{
ref_data->joint_url_complete = 0;
}
ref_data->joint_url.iov_len = uri_result->iov_len - uri_skip_len;
ref_data->joint_url.iov_base = MEMPOOL_CALLOC(half->http_ev_ctx->ref_mempool, char, ref_data->joint_url.iov_len);
memcpy(ref_data->joint_url.iov_base, (char *)uri_result->iov_base + uri_skip_len, ref_data->joint_url.iov_len);
}
/* Information-only callbacks, return value is ignored */
static int on_uri_complete(llhttp_t *http)
{
printf_debug_info("on_uri_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (is_line_crlf(half) == 0)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_URI);
}
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_URI);
hstring uri_result = {};
http_decoder_table_get_uri(half->ref_data->table, (char **)&uri_result.iov_base, &uri_result.iov_len);
assert(uri_result.iov_base);
http_decoder_cached_portion_url(half, &uri_result);
return 0;
}
/* Possible return values 0, -1, HPE_USER */
static int on_version(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_version", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_VERSION, at, length);
return 0;
}
/* Information-only callbacks, return value is ignored */
static int on_version_complete(llhttp_t *http)
{
printf_debug_info("on_version_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (is_line_crlf(half) == 0)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_VERSION);
}
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_VERSION);
half->ref_data->major_version = llhttp_get_http_major(&half->parser);
half->ref_data->minor_version = llhttp_get_http_minor(&half->parser);
if (half->parser.type == HTTP_REQUEST)
{
half->event = HTTP_EVENT_REQ_LINE;
if (half->http_ev_cb) // http_event_handler()
{
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
}
return 0;
}
/* Possible return values 0, -1, HPE_USER */
static int on_status(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_status", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_STATUS, at, length);
return 0;
}
/* Information-only callbacks, return value is ignored */
static int on_status_complete(llhttp_t *http)
{
printf_debug_info("on_status_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (is_line_crlf(half) == 0)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_STATUS);
}
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_STATUS);
half->ref_data->status_code = llhttp_get_status_code(&half->parser);
if (half->parser.type == HTTP_RESPONSE)
{
half->event = HTTP_EVENT_RES_LINE;
if (half->http_ev_cb != NULL) // http_event_handler()
{
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
}
return 0;
}
/* Possible return values 0, -1, HPE_USER */
static int on_header_field(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_header_field", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_HDRKEY, at, length);
return 0;
}
/* Information-only callbacks, return value is ignored */
static int on_header_field_complete(llhttp_t *http)
{
printf_debug_info("on_header_field_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_HDRKEY);
return 0;
}
/* Possible return values 0, -1, HPE_USER */
static int on_header_value(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_header_value", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_HDRVAL, at, length);
return 0;
}
#define MAX_ENCODING_STR_LEN 8
/* Information-only callbacks, return value is ignored */
static int on_header_value_complete(llhttp_t *http)
{
printf_debug_info("on_header_value_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_HDRKEY) ==
STRING_STATE_CACHE)
{
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_HDRKEY);
}
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_HDRVAL);
if (half->ref_data->content_encoding == HTTP_CONTENT_ENCODING_NONE)
{
struct http_header_field http_hdr = {};
if (http_decoder_table_get_header(half->ref_data->table, (char *)"Content-Encoding", 16, &http_hdr) == 0)
{
half->ref_data->content_encoding = http_content_encoding_str2int(http_hdr.value, http_hdr.value_len);
}
}
if (http->type == HTTP_REQUEST)
{
http_decoder_get_host_feed_url(half);
}
return 0;
}
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
* Possible return values 0, -1, `HPE_PAUSED`
*/
static int on_chunk_header(llhttp_t *http __attribute__((unused)))
{
printf_debug_info("on_chunk_header", NULL, 0);
return 0;
}
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
* Possible return values 0, -1, `HPE_PAUSED`
*/
static int on_chunk_header_complete(llhttp_t *http __attribute__((unused)))
{
printf_debug_info("on_chunk_header_complete", NULL, 0);
return 0;
}
/* Possible return values:
* 0 - Proceed normally
* 1 - Assume that request/response has no body, and proceed to parsing the next message
* 2 - Assume absence of body (as above) and make `llhttp_execute()` return `HPE_PAUSED_UPGRADE`
* -1 - Error `HPE_PAUSED`
*/
static int on_headers_complete(llhttp_t *http)
{
printf_debug_info("on_headers_complete", NULL, 0);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
assert(half->ref_data);
http_decoder_table_set_header_complete(half->ref_data->table);
if (half->parser.type == HTTP_REQUEST)
{
half->event = HTTP_EVENT_REQ_HDR_END;
}
else
{
half->event = HTTP_EVENT_RES_HDR_END;
}
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env); // http_event_handler()
return 0;
}
/* Possible return values 0, -1, HPE_USER */
static int on_body(llhttp_t *http, const char *at, size_t length)
{
printf_debug_info("on_body", at, length);
struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser);
assert(half);
// trigger body_begin event
if (half->parser.type == HTTP_REQUEST)
{
if (half->event == HTTP_EVENT_REQ_HDR_END)
{
half->event = HTTP_EVENT_REQ_BODY_BEGIN;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env); // http_event_handler()
}
}
else
{
if (half->event == HTTP_EVENT_RES_HDR_END)
{
half->event = HTTP_EVENT_RES_BODY_BEGIN;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
}
if (half->ref_data != NULL)
{
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_BODY) ==
STRING_STATE_COMMIT)
{
http_decoder_table_reset(half->ref_data->table, HTTP_ITEM_BODY);
}
http_decoder_table_refer(half->ref_data->table, HTTP_ITEM_BODY, at, length);
http_decoder_table_commit(half->ref_data->table, HTTP_ITEM_BODY);
}
if (1 == half->decompress_switch && half->ref_data->content_encoding != HTTP_CONTENT_ENCODING_NONE)
{
http_decoder_half_data_decompress(half->ref_data);
}
if (half->parser.type == HTTP_REQUEST)
{
half->event = HTTP_EVENT_REQ_BODY_DATA;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env); // http_event_handler()
}
else
{
half->event = HTTP_EVENT_RES_BODY_DATA;
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env);
}
return 0;
}
static void http_decoder_half_init(struct http_decoder_half *half, http_event_cb *http_ev_cb, enum llhttp_type type)
{
llhttp_settings_init(&half->settings);
llhttp_init(&half->parser, type, &half->settings);
// half->is_request_flow = (type == HTTP_REQUEST) ? 1 : 0;
half->settings.on_message_begin = on_message_begin;
half->settings.on_message_complete = on_message_complete;
half->settings.on_reset = on_reset;
half->settings.on_url = on_uri;
half->settings.on_url_complete = on_uri_complete;
half->settings.on_status = on_status;
half->settings.on_status_complete = on_status_complete;
half->settings.on_method = on_method;
half->settings.on_method_complete = on_method_complete;
half->settings.on_version = on_version;
half->settings.on_version_complete = on_version_complete;
half->settings.on_header_field = on_header_field;
half->settings.on_header_field_complete = on_header_field_complete;
half->settings.on_header_value = on_header_value;
half->settings.on_header_value_complete = on_header_value_complete;
half->settings.on_chunk_header = on_chunk_header;
half->settings.on_chunk_complete = on_chunk_header_complete;
half->settings.on_headers_complete = on_headers_complete;
half->settings.on_body = on_body;
half->error = HPE_OK;
half->http_ev_cb = http_ev_cb; // http_event_handler()
half->ref_data = NULL;
}
struct http_decoder_half *http_decoder_half_new(struct http_decoder_exdata *hd_ctx, nmx_pool_t *mempool,
http_event_cb *ev_cb, enum llhttp_type http_type,
int decompress_switch, struct http_decoder_env *httpd_env, long long start_seq)
{
struct http_decoder_half *half = MEMPOOL_CALLOC(mempool, struct http_decoder_half, 1);
assert(half);
half->decompress_switch = decompress_switch;
half->http_ev_ctx = MEMPOOL_CALLOC(mempool, struct http_event_context, 1);
http_decoder_half_init(half, ev_cb, http_type);
half->http_ev_ctx->ref_httpd_ctx = hd_ctx;
half->httpd_env = httpd_env;
half->transaction_seq = start_seq;
return half;
}
void http_decoder_half_free(nmx_pool_t *mempool, struct http_decoder_half *half)
{
if (NULL == half)
{
return;
}
if (half->http_ev_ctx != NULL)
{
MEMPOOL_FREE(mempool, half->http_ev_ctx);
half->http_ev_ctx = NULL;
}
MEMPOOL_FREE(mempool, half);
}
void http_decoder_half_reinit(struct http_decoder_half *half,
struct http_decoder_result_queue *queue,
nmx_pool_t *mempool, struct session *sess)
{
assert(half != NULL);
if (half->ref_data != NULL)
{
http_decoder_table_reinit(half->ref_data->table);
}
half->http_ev_ctx->ref_mempool = mempool;
half->http_ev_ctx->ref_session = sess;
half->http_ev_ctx->ref_queue = queue;
}
static void publish_message_for_parsed_header(struct http_decoder_half *half)
{
if (0 == http_decoder_table_has_parsed_header(half->ref_data->table))
{
return;
}
if (half->parser.type == HTTP_REQUEST)
{
half->event = HTTP_EVENT_REQ_HDR;
}
else
{
half->event = HTTP_EVENT_RES_HDR;
}
half->http_ev_cb(half->event, &half->ref_data, half->http_ev_ctx, half->httpd_env); // http_event_handler();
return;
}
int http_decoder_half_parse(int proxy_enable, struct http_decoder_half *half, const char *data, size_t data_len)
{
assert(half && data);
half->data = (const char *)data;
half->data_len = data_len;
half->error = llhttp_execute(&half->parser, data, data_len);
int ret = 0;
enum llhttp_type type = HTTP_BOTH;
switch (half->error)
{
case HPE_OK:
break;
case HPE_PAUSED:
llhttp_resume(&half->parser);
break;
case HPE_PAUSED_UPGRADE:
if (proxy_enable)
{
llhttp_resume_after_upgrade(&half->parser);
}
ret = 0;
break;
default:
type = (enum llhttp_type)half->parser.type;
llhttp_init(&half->parser, type, &half->settings);
ret = -1;
break;
}
if (ret < 0)
{
// fprintf(stdout,
// "llhttp_execute parse error: %s err_reason:%s\n",
// llhttp_errno_name(half->error), half->parser.reason);
return half->error;
}
if (half->ref_data != NULL)
{
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_URI) == STRING_STATE_REFER)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_URI);
}
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_STATUS) == STRING_STATE_REFER)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_STATUS);
}
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_METHOD) == STRING_STATE_REFER)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_METHOD);
}
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_VERSION) == STRING_STATE_REFER)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_VERSION);
}
if (http_decoder_table_header_complete(half->ref_data->table))
{
http_decoder_table_reset_header_complete(half->ref_data->table);
}
else
{
// if headers are not completed with EOF \r\n\r\n, push the parsed headers so far
publish_message_for_parsed_header(half);
}
enum string_state hdr_key_state =
http_decoder_table_state(half->ref_data->table, HTTP_ITEM_HDRKEY);
enum string_state hdr_val_state =
http_decoder_table_state(half->ref_data->table, HTTP_ITEM_HDRVAL);
/* Truncated in http header key
For example http header k-v => User-Agent: Chrome
case1:
packet1: User- hdr_key_state == STRING_STATE_REFER
packet2: Agent: Chrome
case2:
packet1: User-Agent: hdr_key_state == STRING_STATE_COMMIT
hdr_val_state == STRING_STATE_INIT
packet2: Chrome
*/
if (hdr_key_state == STRING_STATE_REFER ||
(hdr_key_state == STRING_STATE_COMMIT && hdr_val_state == STRING_STATE_INIT))
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_HDRKEY);
}
/* Truncated in http header value
For example http header k-v => User-Agent: Chrome
packet1: User-Agent: Ch hdr_key_state == STRING_STATE_COMMIT
hdr_val_state == STRING_STATE_REFER
packet2: rome
*/
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_HDRVAL) == STRING_STATE_REFER)
{
/* Header key should have been committed
If it's not cached, cache it for next packet to use
*/
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_HDRKEY);
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_HDRVAL);
}
if (http_decoder_table_state(half->ref_data->table, HTTP_ITEM_BODY) == STRING_STATE_REFER)
{
http_decoder_table_cache(half->ref_data->table, HTTP_ITEM_BODY);
}
}
return 0;
}
long long http_decoder_half_trans_count(struct http_decoder_half *half)
{
if (NULL == half)
{
return 0;
}
long long trans_cnt = half->trans_counter;
half->trans_counter = 0;
return trans_cnt;
}
struct http_decoder_half_data *
http_decoder_half_data_new(nmx_pool_t *mempool)
{
struct http_decoder_half_data *data =
MEMPOOL_CALLOC(mempool, struct http_decoder_half_data, 1);
assert(data);
data->table = http_decoder_table_new(mempool);
assert(data->table);
data->major_version = -1;
data->minor_version = -1;
data->status_code = -1;
data->content_encoding = HTTP_CONTENT_ENCODING_NONE;
// data->ref_decompress_body = NULL;
// data->decompress_body_len = 0;
data->decompress_buffer_list = NULL;
return data;
}
static void http_decoder_half_decompress_buf_free(struct http_decoder_half_data *ref_data)
{
if (ref_data == NULL)
{
return;
}
struct http_decompress_buffer *el, *tmp;
DL_FOREACH_SAFE(ref_data->decompress_buffer_list, el, tmp)
{
DL_DELETE(ref_data->decompress_buffer_list, el);
if (el->iov.iov_base != NULL)
{
FREE(el->iov.iov_base);
}
FREE(el);
}
ref_data->decompress_buffer_list = NULL;
}
void http_decoder_half_data_free(nmx_pool_t *mempool, struct http_decoder_half_data *data)
{
if (NULL == data)
{
return;
}
if (data->table != NULL)
{
http_decoder_table_free(data->table);
data->table = NULL;
}
if (data->decompress != NULL)
{
http_content_decompress_destroy(data->decompress);
data->decompress = NULL;
}
if (data->joint_url.iov_base)
{
MEMPOOL_FREE(mempool, data->joint_url.iov_base);
data->joint_url.iov_base = NULL;
data->joint_url_complete = 0;
}
http_decoder_half_decompress_buf_free(data);
MEMPOOL_FREE(mempool, data);
}
int http_decoder_half_data_get_request_line(struct http_decoder_half_data *data,
struct http_request_line *line)
{
http_decoder_table_get_method(data->table, &line->method, &line->method_len);
http_decoder_table_get_uri(data->table, &line->uri, &line->uri_len);
http_decoder_table_get_version(data->table, &line->version, &line->version_len);
line->major_version = data->major_version;
line->minor_version = data->minor_version;
return 0;
}
int http_decoder_half_data_get_response_line(struct http_decoder_half_data *data,
struct http_response_line *line)
{
http_decoder_table_get_version(data->table, &line->version, &line->version_len);
http_decoder_table_get_status(data->table, &line->status, &line->status_len);
line->major_version = data->major_version;
line->minor_version = data->minor_version;
line->status_code = data->status_code;
return 0;
}
int http_decoder_half_data_get_header(const struct http_decoder_half_data *data,
const char *name, size_t name_len,
struct http_header_field *hdr_result)
{
return http_decoder_table_get_header(data->table, name, name_len, hdr_result);
}
int http_decoder_half_data_iter_header(struct http_decoder_half_data *data,
struct http_header_field *header)
{
return http_decoder_table_iter_header((struct http_decoder_table *)data->table, header);
}
int http_decoder_half_data_reset_header_iter(struct http_decoder_half_data *req_data)
{
if (NULL == req_data)
{
return -1;
}
return http_decoder_table_reset_header_iter(req_data->table);
}
int http_decoder_half_data_has_parsed_header(struct http_decoder_half_data *data)
{
if (NULL == data)
{
return 0;
}
return http_decoder_table_has_parsed_header(data->table);
}
int http_decoder_half_data_get_raw_body(const struct http_decoder_half_data *data, const char **body, size_t *body_len)
{
if (NULL == data || NULL == body)
{
return -1;
}
return http_decoder_table_get_body(data->table, (char **)body, body_len);
}
#if 0
int http_decoder_half_data_get_decompress_body(const struct http_decoder_half_data *data, hstring *body)
{
if (HTTP_CONTENT_ENCODING_NONE == data->content_encoding)
{
return http_decoder_table_get_body(data->table, body);
}
body->iov_base = data->ref_decompress_body;
body->iov_len = data->decompress_body_len;
return 0;
}
#endif
void http_decoder_half_data_dump(struct http_decoder_half *half)
{
if (NULL == half || NULL == half->ref_data)
{
return;
}
http_decoder_table_dump(half->ref_data->table);
}
static void using_session_addr_as_host(struct session *ref_session, struct http_header_field *host_result, nmx_pool_t *mempool)
{
#if 1 // in native steallar, can't get the tuple4 from the session yet!!!
struct httpd_session_addr ssaddr = {};
httpd_session_get_addr(ref_session, &ssaddr);
if (ssaddr.ipver != 4 && ssaddr.ipver != 6)
{
host_result->value = MEMPOOL_CALLOC(mempool, char, 1);
sprintf((char *)host_result->value, "%s", "");
host_result->value_len = strlen((char *)host_result->value);
return;
}
char ip_string_buf[INET6_ADDRSTRLEN];
if (4 == ssaddr.ipver)
{
host_result->value = MEMPOOL_CALLOC(mempool, char, (INET_ADDRSTRLEN + 7) /* "ip:port" max length */);
inet_ntop(AF_INET, &ssaddr.daddr4, ip_string_buf, INET_ADDRSTRLEN);
sprintf((char *)host_result->value, "%s:%u", ip_string_buf, ntohs(ssaddr.dport));
host_result->value_len = strlen((char *)host_result->value);
}
else if (6 == ssaddr.ipver)
{
host_result->value = MEMPOOL_CALLOC(mempool, char, (INET6_ADDRSTRLEN + 7) /* "ip:port" max length */);
inet_ntop(AF_INET6, &ssaddr.daddr6, ip_string_buf, INET6_ADDRSTRLEN);
sprintf((char *)host_result->value, "%s:%u", ip_string_buf, ntohs(ssaddr.dport));
host_result->value_len = strlen((char *)host_result->value);
}
else
{
assert(0);
}
#else
host_result->val.iov_base = MEMPOOL_CALLOC(mempool, char, 32);
sprintf((char *)host_result->val.iov_base, "%s", "todo:get_tuple4");
host_result->val.iov_len = strlen((char *)host_result->val.iov_base);
#endif
}
void http_decoder_join_url(struct http_decoder_half_data *hfdata, nmx_pool_t *mempool, const struct http_header_field *host_hdr)
{
int append_slash_len = 0;
if ('/' != ((char *)hfdata->joint_url.iov_base)[0])
{
append_slash_len = 1;
}
int url_cache_str_len = host_hdr->value_len + hfdata->joint_url.iov_len + append_slash_len;
char *url_cache_str = MEMPOOL_CALLOC(mempool, char, url_cache_str_len);
char *ptr = url_cache_str;
memcpy(ptr, host_hdr->value, host_hdr->value_len);
ptr += host_hdr->value_len;
if (append_slash_len)
{
*ptr = '/';
ptr++;
}
memcpy(ptr, hfdata->joint_url.iov_base, hfdata->joint_url.iov_len);
MEMPOOL_FREE(mempool, hfdata->joint_url.iov_base); // free the cached uri buffer
hfdata->joint_url.iov_base = url_cache_str;
hfdata->joint_url.iov_len = url_cache_str_len;
hfdata->joint_url_complete = 1;
}
void http_decoder_get_url(struct http_decoder_half_data *hfdata, nmx_pool_t *mempool)
{
struct http_request_line reqline = {};
http_decoder_half_data_get_request_line(hfdata, &reqline);
if (unlikely(http_strncasecmp_safe("CONNECT", (char *)reqline.method, 7, reqline.method_len) == 0))
{
hfdata->joint_url.iov_base = MEMPOOL_CALLOC(mempool, char, reqline.uri_len + 1);
memcpy(hfdata->joint_url.iov_base, reqline.uri, reqline.uri_len);
hfdata->joint_url.iov_len = reqline.uri_len;
hfdata->joint_url_complete = 1;
}
}
int http_decoder_join_url_finally(struct http_event_context *ev_ctx, struct http_decoder_half_data *hfdata, nmx_pool_t *mempool)
{
if (hfdata->joint_url_complete)
{
return 0;
}
struct http_header_field addr_as_host = {};
using_session_addr_as_host(ev_ctx->ref_session, &addr_as_host, mempool);
http_decoder_join_url(hfdata, mempool, &addr_as_host);
MEMPOOL_FREE(mempool, addr_as_host.value); // free session addr to host buffer
return 1;
}
void http_decoder_get_host_feed_url(struct http_decoder_half *half)
{
if (half->ref_data->joint_url_complete)
{
return;
}
struct http_header_field host_result = {};
int host_header_cnt = http_decoder_half_data_get_header(half->ref_data, (char *)"Host", 4, &host_result);
if (host_header_cnt < 0)
{
return;
}
http_decoder_join_url(half->ref_data, half->http_ev_ctx->ref_mempool, &host_result);
}
int http_half_data_get_url(struct http_decoder_half_data *res_data, const char **url_val, size_t *url_len)
{
if (0 == res_data->joint_url_complete)
{
return -1;
}
*url_val = res_data->joint_url.iov_base;
*url_len = res_data->joint_url.iov_len;
return 0;
}
#if 0
int http_half_data_get_decode_url(struct http_decoder_half_data *res_data, hstring *url)
{
if (0 == res_data->joint_url_complete)
{
return -1;
}
url->iov_base = res_data->decoded_url.iov_base;
url->iov_len = res_data->decoded_url.iov_len;
return 0;
}
#endif
int http_half_data_get_transaction_seq(struct http_decoder_half_data *hf_data)
{
return hf_data->transaction_index;
}
void http_half_data_update_commit_index(struct http_decoder_half_data *half_data)
{
http_decoder_table_update_commit_index(half_data->table);
}
int http_half_data_get_total_parsed_header_count(struct http_decoder_half_data *half_data)
{
return http_decoder_table_get_total_parsed_header(half_data->table);
}
void http_half_pre_context_free(struct session *sess, struct http_decoder_exdata *exdata)
{
struct http_message *msg = NULL;
struct http_decoder_half_data *res_data = NULL;
struct http_decoder_result_queue *queue = NULL;
if (exdata)
{
queue = exdata->queue;
for (size_t i = 0; i < queue->queue_size; i++)
{
struct http_decoder_half_data *req_data = queue->array[i].req_data;
res_data = queue->array[i].res_data;
if ((req_data != NULL) && (NULL == res_data) && (req_data->state < HTTP_EVENT_REQ_END))
{
msg = http_message_new(HTTP_TRANSACTION_END, queue, i, HTTP_REQUEST);
session_mq_publish_message(sess, exdata->pub_topic_id, msg);
}
}
for (size_t i = 0; i < queue->queue_size; i++)
{
res_data = queue->array[i].res_data;
if ((res_data != NULL) && (res_data->state < HTTP_EVENT_RES_END))
{
msg = http_message_new(HTTP_TRANSACTION_END, queue, i, HTTP_RESPONSE);
session_mq_publish_message(sess, exdata->pub_topic_id, msg);
}
}
}
}
void http_half_update_state(struct http_decoder_half_data *hf_data, enum http_event state)
{
hf_data->state = state;
}
void http_half_get_max_transaction_seq(struct http_decoder_exdata *exdata, long long *max_req_seq, long long *max_res_seq)
{
assert(exdata && max_req_seq && max_res_seq);
*max_req_seq = exdata->decoder->c2s_half->transaction_seq;
*max_res_seq = exdata->decoder->s2c_half->transaction_seq;
}
enum http_content_encoding http_half_data_get_content_encoding(struct http_decoder_half_data *hf_data)
{
if (NULL == hf_data)
{
return HTTP_CONTENT_ENCODING_NONE;
}
return hf_data->content_encoding;
}