✨ feat(integration decoders): http and glimpse_detector
compile pass, todo test
This commit is contained in:
14
decoders/http/CMakeLists.txt
Normal file
14
decoders/http/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
add_definitions(-fPIC)
|
||||
|
||||
set(HTTP_SRC ${DEPS_SRC} http_decoder.cpp http_decoder_utils.cpp http_decoder_half.cpp
|
||||
http_decoder_table.cpp http_decoder_string.cpp http_content_decompress.cpp
|
||||
http_decoder_result_queue.cpp http_decoder_stat.cpp http_decoder_tunnel.cpp)
|
||||
|
||||
add_library(http_decoder STATIC ${HTTP_SRC})
|
||||
set_target_properties(http_decoder PROPERTIES LINK_FLAGS "-Wl,--version-script=${PROJECT_SOURCE_DIR}/src/version.map")
|
||||
target_include_directories(http_decoder PUBLIC ${CMAKE_SOURCE_DIR}/deps/)
|
||||
target_link_libraries(http_decoder z llhttp-static fieldstat4)
|
||||
target_link_libraries(http_decoder brotli-dec-static brotli-common-static )
|
||||
set_target_properties(http_decoder PROPERTIES PREFIX "")
|
||||
|
||||
#install(TARGETS http_decoder LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/plugin/${lib_name} COMPONENT LIBRARIES)
|
||||
254
decoders/http/http_content_decompress.cpp
Normal file
254
decoders/http/http_content_decompress.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
**********************************************************************************************
|
||||
* File: http_content_decompress.c
|
||||
* Description:
|
||||
* Authors: LuWenPeng <luwenpeng@geedgenetworks.com>
|
||||
* Date: 2022-10-31
|
||||
* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
|
||||
***********************************************************************************************
|
||||
*/
|
||||
#include <zlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <brotli/decode.h>
|
||||
#include "http_decoder_inc.h"
|
||||
|
||||
#define HTTP_DECOMPRESS_BUFFER_SIZE (4096)
|
||||
|
||||
struct http_content_decompress {
|
||||
enum http_content_encoding encoding;
|
||||
z_stream *z_stream_ptr;
|
||||
BrotliDecoderState *br_state;
|
||||
char *buffer;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
enum http_content_encoding
|
||||
http_content_encoding_str2int(const char *content_encoding)
|
||||
{
|
||||
if (strcasestr(content_encoding, "gzip") != NULL) {
|
||||
return HTTP_CONTENT_ENCODING_GZIP;
|
||||
}
|
||||
if (strcasestr(content_encoding, "deflate") != NULL) {
|
||||
return HTTP_CONTENT_ENCODING_DEFLATE;
|
||||
}
|
||||
if (strcasestr(content_encoding, "br") != NULL) {
|
||||
return HTTP_CONTENT_ENCODING_BR;
|
||||
}
|
||||
return HTTP_CONTENT_ENCODING_NONE;
|
||||
}
|
||||
|
||||
const char *
|
||||
http_content_encoding_int2str(enum http_content_encoding content_encoding)
|
||||
{
|
||||
if (content_encoding == HTTP_CONTENT_ENCODING_GZIP) {
|
||||
return "gzip";
|
||||
}
|
||||
if (content_encoding == HTTP_CONTENT_ENCODING_DEFLATE) {
|
||||
return "deflate";
|
||||
}
|
||||
if (content_encoding == HTTP_CONTENT_ENCODING_BR) {
|
||||
return "br";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
struct http_content_decompress *
|
||||
http_content_decompress_create(enum http_content_encoding encoding)
|
||||
{
|
||||
struct http_content_decompress *decompress =
|
||||
CALLOC(struct http_content_decompress, 1);
|
||||
assert(decompress);
|
||||
|
||||
decompress->encoding = encoding;
|
||||
decompress->z_stream_ptr = NULL;
|
||||
decompress->br_state = NULL;
|
||||
|
||||
if (encoding == HTTP_CONTENT_ENCODING_GZIP
|
||||
|| encoding == HTTP_CONTENT_ENCODING_DEFLATE) {
|
||||
decompress->z_stream_ptr = CALLOC(z_stream, 1);
|
||||
assert(decompress->z_stream_ptr);
|
||||
|
||||
decompress->z_stream_ptr->zalloc = NULL;
|
||||
decompress->z_stream_ptr->zfree = NULL;
|
||||
decompress->z_stream_ptr->opaque = NULL;
|
||||
decompress->z_stream_ptr->avail_in = 0;
|
||||
decompress->z_stream_ptr->next_in = Z_NULL;
|
||||
|
||||
if (encoding == HTTP_CONTENT_ENCODING_GZIP) {
|
||||
if (inflateInit2(decompress->z_stream_ptr, MAX_WBITS + 16)
|
||||
!= Z_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (encoding == HTTP_CONTENT_ENCODING_DEFLATE) {
|
||||
if (inflateInit2(decompress->z_stream_ptr, -MAX_WBITS) != Z_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (encoding == HTTP_CONTENT_ENCODING_BR) {
|
||||
decompress->br_state = BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
||||
if (decompress->br_state == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return decompress;
|
||||
|
||||
error:
|
||||
http_content_decompress_destroy(decompress);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void http_content_decompress_destroy(struct http_content_decompress *decompress)
|
||||
{
|
||||
if (NULL == decompress) {
|
||||
return;
|
||||
}
|
||||
if (decompress->z_stream_ptr != NULL) {
|
||||
inflateEnd(decompress->z_stream_ptr);
|
||||
FREE(decompress->z_stream_ptr);
|
||||
}
|
||||
if (decompress->br_state) {
|
||||
BrotliDecoderDestroyInstance(decompress->br_state);
|
||||
decompress->br_state = NULL;
|
||||
}
|
||||
FREE(decompress->buffer);
|
||||
FREE(decompress);
|
||||
}
|
||||
|
||||
static int
|
||||
http_content_decompress_write_zlib(struct http_content_decompress *decompress,
|
||||
const char *indata, size_t indata_len,
|
||||
char **outdata, size_t *outdata_len)
|
||||
{
|
||||
z_stream *z_stream_ptr = decompress->z_stream_ptr;
|
||||
z_stream_ptr->avail_in = (unsigned int)indata_len;
|
||||
z_stream_ptr->next_in = (unsigned char *)indata;
|
||||
z_stream_ptr->avail_out = (unsigned int)decompress->buffer_size;
|
||||
z_stream_ptr->next_out = (unsigned char *)decompress->buffer;
|
||||
|
||||
*outdata = NULL;
|
||||
*outdata_len = 0;
|
||||
|
||||
do {
|
||||
int ret = inflate(z_stream_ptr, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT
|
||||
|| ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
|
||||
(void)inflateEnd(z_stream_ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t have = decompress->buffer_size - z_stream_ptr->avail_out;
|
||||
if (have > 0) {
|
||||
if (0 == z_stream_ptr->avail_out) {
|
||||
fprintf(stderr, "realloc outbuffer,before: %zu bytes, after :%zu B\n", decompress->buffer_size , decompress->buffer_size + have); ;
|
||||
decompress->buffer_size += have;
|
||||
decompress->buffer = REALLOC(char, decompress->buffer,
|
||||
decompress->buffer_size);
|
||||
*outdata = decompress->buffer;
|
||||
*outdata_len = *outdata_len + have;
|
||||
// http_decoder_log(DEBUG, "%s realloc outbuffer %zu bytes",
|
||||
// http_content_encoding_int2str(decompress->encoding),
|
||||
// decompress->buffer_size);
|
||||
z_stream_ptr->avail_out = have;
|
||||
z_stream_ptr->next_out = (unsigned char *)decompress->buffer +
|
||||
(decompress->buffer_size - have);
|
||||
} else {
|
||||
*outdata = decompress->buffer;
|
||||
*outdata_len = have;
|
||||
}
|
||||
}
|
||||
if(Z_STREAM_END == ret){
|
||||
break;
|
||||
}
|
||||
} while (z_stream_ptr->avail_in != 0);
|
||||
decompress->buffer = NULL;
|
||||
decompress->buffer_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
http_content_decompress_write_br(struct http_content_decompress *decompress,
|
||||
const char *indata, size_t indata_len,
|
||||
char **outdata, size_t *outdata_len)
|
||||
{
|
||||
size_t available_in = indata_len;
|
||||
const unsigned char *next_in = (const unsigned char *)indata;
|
||||
size_t available_out = decompress->buffer_size;
|
||||
unsigned char *next_out = (unsigned char *)decompress->buffer;
|
||||
|
||||
*outdata = NULL;
|
||||
*outdata_len = 0;
|
||||
|
||||
for (;;) {
|
||||
int ret = BrotliDecoderDecompressStream(decompress->br_state, &available_in,
|
||||
&next_in, &available_out, &next_out, 0);
|
||||
size_t have = decompress->buffer_size - available_out;
|
||||
if (have > 0) {
|
||||
if (0 == available_out) {
|
||||
decompress->buffer_size += have;
|
||||
decompress->buffer = REALLOC(char, decompress->buffer,
|
||||
decompress->buffer_size);
|
||||
*outdata = decompress->buffer;
|
||||
*outdata_len = *outdata_len + have;
|
||||
available_out = have;
|
||||
next_out = (unsigned char *)decompress->buffer +
|
||||
(decompress->buffer_size - have);
|
||||
} else {
|
||||
*outdata = decompress->buffer;
|
||||
*outdata_len = have;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == BROTLI_DECODER_RESULT_SUCCESS ||
|
||||
ret == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
||||
decompress->buffer =NULL;
|
||||
decompress->buffer_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret == BROTLI_DECODER_RESULT_ERROR) {
|
||||
//BrotliDecoderErrorCode errcode =
|
||||
BrotliDecoderGetErrorCode(decompress->br_state);
|
||||
*outdata = NULL;
|
||||
*outdata_len = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(ret == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
int http_content_decompress_write(struct http_content_decompress *decompress,
|
||||
const char *indata, size_t indata_len,
|
||||
char **outdata, size_t *outdata_len)
|
||||
{
|
||||
assert(decompress);
|
||||
assert(indata);
|
||||
assert(indata_len > 0);
|
||||
assert(outdata);
|
||||
assert(outdata_len);
|
||||
|
||||
*outdata = NULL;
|
||||
*outdata_len = 0;
|
||||
|
||||
if(NULL == decompress->buffer ){
|
||||
decompress->buffer = CALLOC(char, HTTP_DECOMPRESS_BUFFER_SIZE);
|
||||
assert(decompress->buffer);
|
||||
decompress->buffer_size = HTTP_DECOMPRESS_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (decompress->encoding == HTTP_CONTENT_ENCODING_GZIP ||
|
||||
decompress->encoding == HTTP_CONTENT_ENCODING_DEFLATE) {
|
||||
return http_content_decompress_write_zlib(decompress, indata, indata_len,
|
||||
outdata, outdata_len);
|
||||
}
|
||||
if (decompress->encoding == HTTP_CONTENT_ENCODING_BR) {
|
||||
return http_content_decompress_write_br(decompress, indata, indata_len,
|
||||
outdata, outdata_len);
|
||||
}
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
52
decoders/http/http_content_decompress.h
Normal file
52
decoders/http/http_content_decompress.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
**********************************************************************************************
|
||||
* File: http_content_decompress.h
|
||||
* Description:
|
||||
* Authors: LuWenPeng <luwenpeng@geedgenetworks.com>
|
||||
* Date: 2022-10-31
|
||||
* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
|
||||
***********************************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _HTTP_CONTENT_DECOMPRESS_H_
|
||||
#define _HTTP_CONTENT_DECOMPRESS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
enum http_content_encoding {
|
||||
HTTP_CONTENT_ENCODING_NONE = 0,
|
||||
HTTP_CONTENT_ENCODING_GZIP = 1 << 1,
|
||||
HTTP_CONTENT_ENCODING_DEFLATE = 1 << 2,
|
||||
HTTP_CONTENT_ENCODING_BR = 1 << 3,
|
||||
};
|
||||
|
||||
struct http_content_decompress;
|
||||
|
||||
enum http_content_encoding
|
||||
http_content_encoding_str2int(const char *content_encoding);
|
||||
|
||||
const char *
|
||||
http_content_encoding_int2str(enum http_content_encoding content_encoding);
|
||||
|
||||
struct http_content_decompress *
|
||||
http_content_decompress_create(enum http_content_encoding encoding);
|
||||
|
||||
void http_content_decompress_destroy(struct http_content_decompress *decompress);
|
||||
|
||||
// return 0 : success
|
||||
// return -1 : error
|
||||
int http_content_decompress_write(struct http_content_decompress *decompress,
|
||||
const char *indata, size_t indata_len,
|
||||
char **outdata, size_t *outdata_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1209
decoders/http/http_decoder.cpp
Normal file
1209
decoders/http/http_decoder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1216
decoders/http/http_decoder_half.cpp
Normal file
1216
decoders/http/http_decoder_half.cpp
Normal file
File diff suppressed because it is too large
Load Diff
105
decoders/http/http_decoder_half.h
Normal file
105
decoders/http/http_decoder_half.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#ifndef _HTTP_DECODER_HALF_H_
|
||||
#define _HTTP_DECODER_HALF_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "stellar/session.h"
|
||||
#include "stellar/http.h"
|
||||
#include "http_content_decompress.h"
|
||||
#include "http_decoder_result_queue.h"
|
||||
#include "llhttp.h"
|
||||
|
||||
// only one http event is fired at a time
|
||||
enum http_event {
|
||||
HTTP_EVENT_REQ_INIT = 1 << 1,
|
||||
HTTP_EVENT_REQ_LINE = 1 << 2,
|
||||
HTTP_EVENT_REQ_HDR = 1 << 3,
|
||||
HTTP_EVENT_REQ_HDR_END = 1 << 4,
|
||||
HTTP_EVENT_REQ_BODY_BEGIN = 1 << 5,
|
||||
HTTP_EVENT_REQ_BODY_DATA = 1 << 6,
|
||||
HTTP_EVENT_REQ_BODY_END = 1 << 7,
|
||||
HTTP_EVENT_REQ_END = 1 << 8,
|
||||
|
||||
HTTP_EVENT_RES_INIT = 1 << 9,
|
||||
HTTP_EVENT_RES_LINE = 1 << 10,
|
||||
HTTP_EVENT_RES_HDR = 1 << 11,
|
||||
HTTP_EVENT_RES_HDR_END = 1 << 12,
|
||||
HTTP_EVENT_RES_BODY_BEGIN = 1 << 13,
|
||||
HTTP_EVENT_RES_BODY_DATA = 1 << 14,
|
||||
HTTP_EVENT_RES_BODY_END = 1 << 15,
|
||||
HTTP_EVENT_RES_END = 1 << 16,
|
||||
};
|
||||
|
||||
struct http_event_context {
|
||||
struct http_decoder_exdata *ref_httpd_ctx;
|
||||
nmx_pool_t *ref_mempool;
|
||||
struct session *ref_session;
|
||||
struct http_decoder_result_queue *ref_queue;
|
||||
};
|
||||
|
||||
struct http_decoder_half;
|
||||
struct http_decoder_half_data;
|
||||
|
||||
typedef void http_event_cb(enum http_event event, struct http_decoder_half_data **data,
|
||||
struct http_event_context *ev_ctx, void *httpd_plugin_env);
|
||||
|
||||
struct http_decoder_half *
|
||||
http_decoder_half_new(struct http_decoder_exdata *hd_ctx, nmx_pool_t *mempool, http_event_cb *event_cb,
|
||||
enum llhttp_type http_type, int decompress_switch, struct http_decoder_env *httpd_env,long long start_seq);
|
||||
|
||||
void http_decoder_half_free(nmx_pool_t *mempool, struct http_decoder_half *half);
|
||||
|
||||
void http_decoder_half_reinit(struct http_decoder_half *half,
|
||||
struct http_decoder_result_queue *queue,
|
||||
nmx_pool_t *mempool, struct session *sess);
|
||||
|
||||
int http_decoder_half_parse(int proxy_enable, struct http_decoder_half *half, const char *data, size_t data_len);
|
||||
|
||||
long long http_decoder_half_trans_count(struct http_decoder_half *half);
|
||||
|
||||
//http decoder half data API
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_half_data_new(nmx_pool_t *mempool);
|
||||
|
||||
void http_decoder_half_data_free(nmx_pool_t *mempool, struct http_decoder_half_data *data);
|
||||
|
||||
int http_decoder_half_data_get_request_line(struct http_decoder_half_data *data,
|
||||
struct http_request_line *line);
|
||||
|
||||
int http_decoder_half_data_get_response_line(struct http_decoder_half_data *data,
|
||||
struct http_response_line *line);
|
||||
|
||||
int http_decoder_half_data_get_header(const struct http_decoder_half_data *data,
|
||||
const hstring *key, struct http_header *hdr_res);
|
||||
|
||||
int http_decoder_half_data_iter_header(struct http_decoder_half_data *data,
|
||||
struct http_header *header);
|
||||
int http_decoder_half_data_reset_header_iter(struct http_decoder_half_data *req_data);
|
||||
int http_decoder_half_data_has_parsed_header(struct http_decoder_half_data *data);
|
||||
|
||||
int http_decoder_half_data_get_raw_body(const struct http_decoder_half_data *data, hstring *body);
|
||||
|
||||
int http_decoder_half_data_get_decompress_body(const struct http_decoder_half_data *data, hstring *body);
|
||||
void http_half_get_lastest_decompress_buffer(struct http_decoder_half_data *data, hstring *decompress_body);
|
||||
void http_half_decompress_buffer_free(struct http_decoder_half_data *data, hstring *decompress_body);
|
||||
void http_decoder_half_data_dump(struct http_decoder_half *half);
|
||||
|
||||
void http_decoder_get_host_feed_url(struct http_decoder_half *half);
|
||||
void http_decoder_get_url(struct http_decoder_half_data *hfdata, nmx_pool_t *mempool);
|
||||
int http_half_data_get_decode_url(struct http_decoder_half_data *res_data, hstring *url);
|
||||
void http_decoder_join_url(struct http_decoder_half_data *hfdata,
|
||||
nmx_pool_t *mempool,
|
||||
const struct http_header *host_hdr);
|
||||
int http_decoder_join_url_finally(struct http_event_context *ev_ctx,
|
||||
struct http_decoder_half_data *hfdata,
|
||||
nmx_pool_t *mempool);
|
||||
int http_half_data_get_url(struct http_decoder_half_data *res_data, hstring *url);
|
||||
int http_half_data_get_transaction_seq(struct http_decoder_half_data *hf_data);
|
||||
|
||||
void http_half_data_update_commit_index(struct http_decoder_half_data * half_data);
|
||||
void http_half_pre_context_free(struct session *sess, struct http_decoder_exdata *exdata);
|
||||
void http_half_update_state(struct http_decoder_half_data *hf_data, enum http_event state);
|
||||
int http_half_data_get_total_parsed_header_count(struct http_decoder_half_data * half_data);
|
||||
void http_half_get_max_transaction_seq(struct http_decoder_exdata *exdata, long long *max_req_seq, long long *max_res_seq);
|
||||
|
||||
enum http_content_encoding http_half_data_get_content_encoding(struct http_decoder_half_data *hf_data);
|
||||
#endif
|
||||
162
decoders/http/http_decoder_inc.h
Normal file
162
decoders/http/http_decoder_inc.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
**********************************************************************************************
|
||||
* File: http_decoder_inc.h
|
||||
* Description:
|
||||
* Authors: Liu WenTan <liuwentan@geedgenetworks.com>
|
||||
* Date: 2024-01-10
|
||||
* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
|
||||
***********************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef _HTTP_DECODER_INC_H_
|
||||
#define _HTTP_DECODER_INC_H_
|
||||
|
||||
#ifndef __USE_MISC
|
||||
#define __USE_MISC 1
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#include <bits/types/struct_iovec.h>
|
||||
#include "stellar/stellar.h"
|
||||
#include "stellar/layer.h"
|
||||
#include "stellar/packet.h"
|
||||
#include "stellar/utils.h"
|
||||
#include "stellar/session.h"
|
||||
#include "stellar/stellar_mq.h"
|
||||
#include "stellar/stellar_exdata.h"
|
||||
|
||||
#include "nmx_pool/nmx_palloc.h"
|
||||
#include "stellar/utils.h"
|
||||
#include "stellar/http.h"
|
||||
#include "http_decoder_result_queue.h"
|
||||
#include "http_decoder_half.h"
|
||||
#include "http_decoder_table.h"
|
||||
#include "http_decoder_result_queue.h"
|
||||
#include "http_decoder_utils.h"
|
||||
#include "http_decoder_stat.h"
|
||||
#include "http_decoder_tunnel.h"
|
||||
#include "fieldstat/fieldstat_easy.h"
|
||||
#include "toml/toml.h"
|
||||
|
||||
#ifndef likely
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
#endif
|
||||
|
||||
#define MEMPOOL_CALLOC(pool, type, number) ((type *)nmx_pcalloc(pool, sizeof(type) * number))
|
||||
#define MEMPOOL_REALLOC(pool)
|
||||
#define MEMPOOL_FREE(pool, p) nmx_pfree(pool, p)
|
||||
|
||||
#define ENABLE_MEMPOOL 0
|
||||
#if ENABLE_MEMPOOL
|
||||
#define HD_CALLOC(pool, type, number) MEMPOOL_CALLOC(pool, number, type)
|
||||
#define HD_FREE(pool, p) MEMPOOL_FREE(pool, p)
|
||||
#else
|
||||
#define HD_CALLOC(pool, type, number) CALLOC(type, number)
|
||||
#define HD_FREE(pool, p) FREE(p)
|
||||
#endif
|
||||
|
||||
#define HTTP_IDENTIFY_LEN 16
|
||||
#define HD_RESULT_QUEUE_LEN 16
|
||||
|
||||
#define DEFAULT_STAT_OUTPUT_INTERVAL 1
|
||||
#define DEFAULT_STAT_INTERVAL_PKTS 1000
|
||||
#define DEFAULT_MEMPOOL_SIZE (32 * 1024)
|
||||
|
||||
#define HTTPD_CFG_FILE "./etc/http/http_decoder.toml"
|
||||
#define FILEDSTAT_OUTPUT_FILE "./metrics/http_decoder_fs4.json"
|
||||
|
||||
#define HTTP_CTX_NOT_HTTP "__NOT_HTTP_SESS__"
|
||||
#define HTTP_CTX_IS_HTTP "__FAKE_HTTP_CTX__"
|
||||
|
||||
struct http_decoder_config
|
||||
{
|
||||
int decompress_switch;
|
||||
int stat_interval_pkts; // call fieldstat_incrby every stat_interval_pkts
|
||||
int stat_output_interval;
|
||||
int proxy_enable;
|
||||
size_t result_queue_len; // per session result queue length
|
||||
size_t mempool_size; // per session mempool size
|
||||
};
|
||||
|
||||
/**
|
||||
* NOTE: http_message don't have the ownership of data
|
||||
*/
|
||||
struct http_message
|
||||
{
|
||||
uint8_t flow_type;
|
||||
enum http_message_type type;
|
||||
size_t queue_index;
|
||||
struct http_decoder_result_queue *ref_queue;
|
||||
hstring raw_payload;//cause tcp reorder, maybe receive many tcp segments for one packet
|
||||
hstring decompress_payload;
|
||||
hstring tunnel_payload;
|
||||
};
|
||||
|
||||
struct http_decoder
|
||||
{
|
||||
struct http_decoder_half *c2s_half;
|
||||
struct http_decoder_half *s2c_half;
|
||||
};
|
||||
|
||||
enum httpd_topic_index{
|
||||
HTTPD_TOPIC_TCP_STREAM_INDEX = 0,
|
||||
HTTPD_TOPIC_HTTP_MSG_INDEX,
|
||||
HTTPD_TOPIC_HTTP_TUNNEL_INDEX,
|
||||
HTTPD_TOPIC_INDEX_MAX,
|
||||
};
|
||||
|
||||
struct http_decoder_exdata
|
||||
{
|
||||
int sub_topic_id; //tcp_stream
|
||||
int pub_topic_id; //http message or http tunnel msg
|
||||
struct http_decoder_result_queue *queue;
|
||||
struct http_decoder *decoder;
|
||||
nmx_pool_t *mempool;
|
||||
enum http_tunnel_state tunnel_state;
|
||||
int in_tunnel_is_http;
|
||||
};
|
||||
|
||||
// struct http_decoder_context{
|
||||
// int array_size;
|
||||
// struct http_decoder_exdata **exdata_array; //raw tcp stream for http msg; http tunnel for inner http transaction.
|
||||
// };
|
||||
|
||||
struct http_topic_exdata_compose{
|
||||
enum httpd_topic_index index;
|
||||
const char *topic_name;
|
||||
on_session_msg_cb_func *on_msg_cb;
|
||||
stellar_msg_free_cb_func *msg_free_cb;
|
||||
const char *exdata_name;
|
||||
stellar_exdata_free *exdata_free_cb;
|
||||
int sub_topic_id; //as consumer
|
||||
int exdata_id;
|
||||
};
|
||||
|
||||
struct http_decoder_env
|
||||
{
|
||||
struct stellar *st;
|
||||
int plugin_id;
|
||||
struct http_topic_exdata_compose topic_exdata_compose[HTTPD_TOPIC_INDEX_MAX];
|
||||
struct http_decoder_config hd_cfg;
|
||||
struct http_decoder_stat hd_stat;
|
||||
};
|
||||
|
||||
struct http_message;
|
||||
|
||||
struct http_message *http_message_new(enum http_message_type type, struct http_decoder_result_queue *queue,
|
||||
int queue_index, unsigned char flow_type);
|
||||
struct http_message *http_body_message_new(enum http_message_type type, struct http_decoder_result_queue *queue,
|
||||
int queue_index, uint8_t flow_type, hstring *raw_payload);
|
||||
int http_topic_exdata_compose_get_index(const struct http_decoder_env *httpd_env, int by_topic_id);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
148
decoders/http/http_decoder_result_queue.cpp
Normal file
148
decoders/http/http_decoder_result_queue.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
**********************************************************************************************
|
||||
* File: http_decoder_result_queue.c
|
||||
* Description:
|
||||
* Authors: Liuwentan <liuwentan@geedgenetworks.com>
|
||||
* Date: 2024-01-15
|
||||
* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
|
||||
***********************************************************************************************
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include "http_decoder_inc.h"
|
||||
|
||||
struct http_decoder_result_queue *
|
||||
http_decoder_result_queue_new(nmx_pool_t *mempool, size_t queue_size)
|
||||
{
|
||||
struct http_decoder_result_queue *queue =
|
||||
MEMPOOL_CALLOC(mempool, struct http_decoder_result_queue, 1);
|
||||
assert(queue);
|
||||
|
||||
queue->req_index = 0;
|
||||
queue->res_index = 0;
|
||||
queue->queue_size = queue_size;
|
||||
queue->array = MEMPOOL_CALLOC(mempool, struct http_decoder_result,
|
||||
queue->queue_size);
|
||||
assert(queue->array);
|
||||
return queue;
|
||||
}
|
||||
|
||||
void http_decoder_result_queue_free(nmx_pool_t *mempool, struct http_decoder_result_queue *queue)
|
||||
{
|
||||
if (NULL == queue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (queue->array != NULL) {
|
||||
for (size_t i = 0; i < queue->queue_size; i++) {
|
||||
if (queue->array[i].req_data != NULL) {
|
||||
http_decoder_half_data_free(mempool, queue->array[i].req_data);
|
||||
queue->array[i].req_data = NULL;
|
||||
}
|
||||
|
||||
if (queue->array[i].res_data != NULL) {
|
||||
http_decoder_half_data_free(mempool, queue->array[i].res_data);
|
||||
queue->array[i].res_data = NULL;
|
||||
}
|
||||
}
|
||||
MEMPOOL_FREE(mempool, queue->array);
|
||||
}
|
||||
MEMPOOL_FREE(mempool, queue);
|
||||
}
|
||||
|
||||
void http_decoder_result_queue_inc_req_index(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
assert(queue);
|
||||
queue->req_index++;
|
||||
queue->req_index = queue->req_index % queue->queue_size;
|
||||
}
|
||||
|
||||
void http_decoder_result_queue_inc_res_index(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
assert(queue);
|
||||
queue->res_index++;
|
||||
queue->res_index = queue->res_index % queue->queue_size;
|
||||
}
|
||||
|
||||
size_t http_decoder_result_queue_req_index(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
assert(queue);
|
||||
return queue->req_index;
|
||||
}
|
||||
|
||||
size_t http_decoder_result_queue_res_index(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
assert(queue);
|
||||
return queue->res_index;
|
||||
}
|
||||
|
||||
int http_decoder_result_queue_push_req(struct http_decoder_result_queue *queue,
|
||||
struct http_decoder_half_data *req_data)
|
||||
{
|
||||
if (NULL == queue || NULL == req_data) {
|
||||
return -1;
|
||||
}
|
||||
assert(queue->array[queue->req_index].req_data == NULL);
|
||||
if (queue->array[queue->req_index].req_data != NULL) {
|
||||
return -1;
|
||||
}
|
||||
queue->array[queue->req_index].req_data = req_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_decoder_result_queue_push_res(struct http_decoder_result_queue *queue,
|
||||
struct http_decoder_half_data *res_data)
|
||||
{
|
||||
if (NULL == queue || NULL == res_data) {
|
||||
return -1;
|
||||
}
|
||||
assert(queue->array[queue->res_index].res_data == NULL);
|
||||
if (queue->array[queue->res_index].res_data != NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
queue->array[queue->res_index].res_data = res_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_pop_req(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
if (NULL == queue) {
|
||||
return NULL;
|
||||
}
|
||||
struct http_decoder_half_data *req_data = queue->array[queue->req_index].req_data;
|
||||
queue->array[queue->req_index].req_data = NULL;
|
||||
return req_data;
|
||||
}
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_pop_res(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
if (NULL == queue) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct http_decoder_half_data *res_data = queue->array[queue->res_index].res_data;
|
||||
queue->array[queue->res_index].res_data = NULL;
|
||||
return res_data;
|
||||
}
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_peek_req(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
if (NULL == queue) {
|
||||
return NULL;
|
||||
}
|
||||
assert(queue->req_index < queue->queue_size);
|
||||
return queue->array[queue->req_index].req_data;
|
||||
}
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_peek_res(struct http_decoder_result_queue *queue)
|
||||
{
|
||||
if (NULL == queue) {
|
||||
return NULL;
|
||||
}
|
||||
assert(queue->res_index < queue->queue_size);
|
||||
return queue->array[queue->res_index].res_data;
|
||||
}
|
||||
61
decoders/http/http_decoder_result_queue.h
Normal file
61
decoders/http/http_decoder_result_queue.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
**********************************************************************************************
|
||||
* File: http_decoder_result_queue.h
|
||||
* Description:
|
||||
* Authors: Liuwentan <liuwentan@geedgenetworks.com>
|
||||
* Date: 2024-01-15
|
||||
* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
|
||||
***********************************************************************************************
|
||||
*/
|
||||
#ifndef _HTTP_DECODER_RESULT_QUEUE_H_
|
||||
#define _HTTP_DECODER_RESULT_QUEUE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "nmx_pool/nmx_palloc.h"
|
||||
#include "http_decoder_half.h"
|
||||
|
||||
struct http_decoder_result {
|
||||
struct http_decoder_half_data *req_data;
|
||||
struct http_decoder_half_data *res_data;
|
||||
};
|
||||
|
||||
struct http_decoder_result_queue {
|
||||
size_t req_index;
|
||||
size_t res_index;
|
||||
size_t queue_size;
|
||||
struct http_decoder_result *array;
|
||||
};
|
||||
|
||||
struct http_decoder_result_queue *
|
||||
http_decoder_result_queue_new(nmx_pool_t *mempool, size_t queue_size);
|
||||
|
||||
void http_decoder_result_queue_free(nmx_pool_t *mempool,
|
||||
struct http_decoder_result_queue *queue);
|
||||
|
||||
void http_decoder_result_queue_inc_req_index(struct http_decoder_result_queue *queue);
|
||||
|
||||
void http_decoder_result_queue_inc_res_index(struct http_decoder_result_queue *queue);
|
||||
|
||||
size_t http_decoder_result_queue_req_index(struct http_decoder_result_queue *queue);
|
||||
|
||||
size_t http_decoder_result_queue_res_index(struct http_decoder_result_queue *queue);
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_pop_req(struct http_decoder_result_queue *queue);
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_pop_res(struct http_decoder_result_queue *queue);
|
||||
|
||||
int http_decoder_result_queue_push_req(struct http_decoder_result_queue *queue,
|
||||
struct http_decoder_half_data *req_data);
|
||||
|
||||
int http_decoder_result_queue_push_res(struct http_decoder_result_queue *queue,
|
||||
struct http_decoder_half_data *res_data);
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_peek_req(struct http_decoder_result_queue *queue);
|
||||
|
||||
struct http_decoder_half_data *
|
||||
http_decoder_result_queue_peek_res(struct http_decoder_result_queue *queue);
|
||||
|
||||
#endif
|
||||
121
decoders/http/http_decoder_stat.cpp
Normal file
121
decoders/http/http_decoder_stat.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "http_decoder_inc.h"
|
||||
|
||||
static const struct hd_stat_config_tuple g_httpd_stat_tuple[HTTPD_STAT_MAX] =
|
||||
{
|
||||
{HTTPD_STAT_BYTES_C2S, "bytes_c2s"},
|
||||
{HTTPD_STAT_BYTES_S2C, "bytes_s2c"},
|
||||
{HTTPD_STAT_TCP_SEG_C2S, "tcp_seg_c2s"},
|
||||
{HTTPD_STAT_TCP_SEG_S2C, "tcp_seg_s2c"},
|
||||
{HTTPD_STAT_HEADERS_C2S, "headers_c2s"},
|
||||
{HTTPD_STAT_HEADERS_S2C, "headers_s2c"},
|
||||
{HTTPD_STAT_ZIP_BYTES, "zip_bytes"},
|
||||
{HTTPD_STAT_UNZIP_BYTES, "unzip_bytes"},
|
||||
{HTTPD_STAT_URL_BYTES, "url_bytes"},
|
||||
{HTTPD_STAT_SESSION_NEW, "session_new"},
|
||||
{HTTPD_STAT_SESSION_FREE, "session_free"},
|
||||
{HTTPD_STAT_SESSION_EXCEPTION, "sess_exception"},
|
||||
{HTTPD_STAT_TUNNEL, "tunnel"},
|
||||
{HTTPD_STAT_TRANSACTION_NEW, "trans_new"},
|
||||
{HTTPD_STAT_TRANSACTION_FREE, "trans_free"},
|
||||
{HTTPD_STAT_ASYMMETRY_SESSION_C2S, "asymmetry_sess_c2s"},
|
||||
{HTTPD_STAT_ASYMMETRY_SESSION_S2C, "asymmetry_sess_s2c"},
|
||||
{HTTPD_STAT_ASYMMETRY_TRANSACTION_C2S, "asymmetry_trans_c2s"},
|
||||
{HTTPD_STAT_ASYMMETRY_TRANSACTION_S2C, "asymmetry_trans_s2c"},
|
||||
{HTTPD_STAT_PARSE_ERR, "parse_err"},
|
||||
};
|
||||
|
||||
void http_decoder_stat_free(struct http_decoder_stat *hd_stat)
|
||||
{
|
||||
if(hd_stat->timer_pid != 0){
|
||||
pthread_cancel(hd_stat->timer_pid);
|
||||
}
|
||||
if(hd_stat->stats != NULL){
|
||||
free(hd_stat->stats);
|
||||
}
|
||||
if(hd_stat->fse != NULL){
|
||||
fieldstat_easy_free(hd_stat->fse);
|
||||
}
|
||||
}
|
||||
|
||||
static void *httpd_stat_timer_thread(void *arg)
|
||||
{
|
||||
pthread_setname_np(pthread_self(), "http_decoder_timer_thread");
|
||||
struct http_decoder_stat *hd_stat = (struct http_decoder_stat *)arg;
|
||||
struct timespec res;
|
||||
while(1){
|
||||
clock_gettime(CLOCK_MONOTONIC, &res);
|
||||
hd_stat->current_time_ms = (res.tv_sec * 1000) + (res.tv_nsec / 1000000);
|
||||
usleep(800);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int http_decoder_stat_init(struct http_decoder_stat *hd_stat, int thread_max, int stat_interval_pkts, int stat_interval_time)
|
||||
{
|
||||
assert(sizeof(g_httpd_stat_tuple)/sizeof(struct hd_stat_config_tuple) == HTTPD_STAT_MAX);
|
||||
if(sizeof(g_httpd_stat_tuple)/sizeof(struct hd_stat_config_tuple) != HTTPD_STAT_MAX){
|
||||
fprintf(stderr, "enum http_decoder_stat_type number not match with g_httpd_stat_tuple!");
|
||||
return -1;
|
||||
}
|
||||
hd_stat->fse = fieldstat_easy_new(thread_max, "http_decoder_statistics", NULL, 0);
|
||||
if (NULL == hd_stat->fse)
|
||||
{
|
||||
fprintf(stderr, "fieldstat_easy_new failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < HTTPD_STAT_MAX; i++)
|
||||
{
|
||||
hd_stat->field_stat_id[i] = fieldstat_easy_register_counter(hd_stat->fse, g_httpd_stat_tuple[i].name);
|
||||
if (hd_stat->field_stat_id[i] < 0)
|
||||
{
|
||||
fprintf(stderr, "fieldstat_easy_register_counter %s failed.", g_httpd_stat_tuple[i].name);
|
||||
fieldstat_easy_free(hd_stat->fse);
|
||||
hd_stat->fse = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = fieldstat_easy_enable_auto_output(hd_stat->fse, FILEDSTAT_OUTPUT_FILE, stat_interval_time);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "fieldstat_easy_enable_auto_output failed.");
|
||||
fieldstat_easy_free(hd_stat->fse);
|
||||
hd_stat->fse = NULL;
|
||||
return -1;
|
||||
}
|
||||
hd_stat->stats = (struct hd_statistics *)calloc(thread_max, sizeof(struct hd_statistics));
|
||||
hd_stat->stat_interval_pkts = stat_interval_pkts;
|
||||
hd_stat->stat_interval_time = stat_interval_time;
|
||||
pthread_create(&hd_stat->timer_pid, NULL, httpd_stat_timer_thread, hd_stat);
|
||||
pthread_detach(hd_stat->timer_pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void http_decoder_stat_update(struct http_decoder_stat *hd_stat, int thread_id, enum http_decoder_stat_type type, long long value)
|
||||
{
|
||||
assert(hd_stat);
|
||||
assert(thread_id >= 0);
|
||||
assert(type < HTTPD_STAT_MAX);
|
||||
|
||||
if(unlikely(hd_stat->stats == NULL)){
|
||||
return;
|
||||
}
|
||||
|
||||
struct hd_statistics *cur_hds = &hd_stat->stats[thread_id];
|
||||
|
||||
cur_hds->counter[type] += value;
|
||||
cur_hds->batch[type]++;
|
||||
|
||||
if(cur_hds->batch[type] >= hd_stat->stat_interval_pkts
|
||||
|| cur_hds->time_ms[type] + 1000 < hd_stat->current_time_ms){
|
||||
fieldstat_easy_counter_incrby(hd_stat->fse, thread_id, hd_stat->field_stat_id[type], NULL, 0, cur_hds->counter[type]);
|
||||
cur_hds->counter[type] = 0;
|
||||
cur_hds->batch[type] = 0;
|
||||
cur_hds->time_ms[type] = hd_stat->current_time_ms;
|
||||
}
|
||||
}
|
||||
57
decoders/http/http_decoder_stat.h
Normal file
57
decoders/http/http_decoder_stat.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef _HTTP_DECODER_STAT_H_
|
||||
#define _HTTP_DECODER_STAT_H_ 1
|
||||
|
||||
#include <fieldstat/fieldstat_easy.h>
|
||||
enum http_decoder_stat_type
|
||||
{
|
||||
HTTPD_STAT_BYTES_C2S = 0,
|
||||
HTTPD_STAT_BYTES_S2C,
|
||||
HTTPD_STAT_TCP_SEG_C2S,
|
||||
HTTPD_STAT_TCP_SEG_S2C,
|
||||
HTTPD_STAT_HEADERS_C2S,
|
||||
HTTPD_STAT_HEADERS_S2C,
|
||||
HTTPD_STAT_ZIP_BYTES, //only if Content-Encoding is gzip, deflate, br
|
||||
HTTPD_STAT_UNZIP_BYTES, //only if Content-Encoding is gzip, deflate, br
|
||||
HTTPD_STAT_URL_BYTES,
|
||||
HTTPD_STAT_SESSION_NEW,
|
||||
HTTPD_STAT_SESSION_FREE,
|
||||
HTTPD_STAT_SESSION_EXCEPTION, // rst, kickout, lost packet, etc.
|
||||
HTTPD_STAT_TUNNEL,
|
||||
HTTPD_STAT_TRANSACTION_NEW,
|
||||
HTTPD_STAT_TRANSACTION_FREE,
|
||||
HTTPD_STAT_ASYMMETRY_SESSION_C2S,
|
||||
HTTPD_STAT_ASYMMETRY_SESSION_S2C,
|
||||
HTTPD_STAT_ASYMMETRY_TRANSACTION_C2S,
|
||||
HTTPD_STAT_ASYMMETRY_TRANSACTION_S2C,
|
||||
HTTPD_STAT_PARSE_ERR,
|
||||
HTTPD_STAT_MAX,
|
||||
};
|
||||
|
||||
struct hd_stat_config_tuple
|
||||
{
|
||||
enum http_decoder_stat_type type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct hd_statistics
|
||||
{
|
||||
long long time_ms[HTTPD_STAT_MAX];
|
||||
long long counter[HTTPD_STAT_MAX];
|
||||
int batch[HTTPD_STAT_MAX]; //call fieldstat_easy_counter_incrby() per batch
|
||||
}__attribute__ ((aligned (64)));
|
||||
|
||||
struct http_decoder_stat
|
||||
{
|
||||
pthread_t timer_pid;
|
||||
long long current_time_ms;
|
||||
struct fieldstat_easy *fse;
|
||||
int stat_interval_pkts; // call fieldstat_incrby every stat_interval_pkts
|
||||
int stat_interval_time; //second
|
||||
int field_stat_id[HTTPD_STAT_MAX];
|
||||
struct hd_statistics *stats; //size is thread number
|
||||
};
|
||||
|
||||
int http_decoder_stat_init(struct http_decoder_stat *hd_stat, int thread_max, int stat_interval_pkts, int stat_interval_time);
|
||||
void http_decoder_stat_free(struct http_decoder_stat *hd_stat);
|
||||
void http_decoder_stat_update(struct http_decoder_stat *hd_stat, int thread_id, enum http_decoder_stat_type type, long long value);
|
||||
#endif
|
||||
260
decoders/http/http_decoder_string.cpp
Normal file
260
decoders/http/http_decoder_string.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "http_decoder_inc.h"
|
||||
|
||||
static const char *string_state_to_desc(enum string_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case STRING_STATE_INIT:
|
||||
return "init";
|
||||
break;
|
||||
case STRING_STATE_REFER:
|
||||
return "refer";
|
||||
break;
|
||||
case STRING_STATE_CACHE:
|
||||
return "cache";
|
||||
break;
|
||||
case STRING_STATE_COMMIT:
|
||||
return "commit";
|
||||
break;
|
||||
default:
|
||||
return "unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_string_refer(struct http_decoder_string *rstr,
|
||||
const char *at, size_t length)
|
||||
{
|
||||
if (NULL == rstr) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rstr->state) {
|
||||
case STRING_STATE_INIT:
|
||||
case STRING_STATE_CACHE:
|
||||
rstr->refer.iov_base = (char *)at;
|
||||
rstr->refer.iov_len = length;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->state = STRING_STATE_REFER;
|
||||
}
|
||||
|
||||
static void string_refer2cache(struct http_decoder_string *rstr)
|
||||
{
|
||||
if (0 == rstr->refer.iov_len) {
|
||||
return;
|
||||
}
|
||||
if (rstr->cache.iov_len >= rstr->max_cache_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t length = rstr->cache.iov_len + rstr->refer.iov_len;
|
||||
if (length > rstr->max_cache_size) {
|
||||
length = rstr->max_cache_size;
|
||||
}
|
||||
|
||||
if (NULL == rstr->cache.iov_base) {
|
||||
rstr->cache.iov_base = CALLOC(char, length + 1);
|
||||
memcpy(rstr->cache.iov_base, rstr->refer.iov_base, length);
|
||||
} else {
|
||||
rstr->cache.iov_base = REALLOC(char, rstr->cache.iov_base, length + 1);
|
||||
memcpy((char *)rstr->cache.iov_base + rstr->cache.iov_len, rstr->refer.iov_base,
|
||||
(length - rstr->cache.iov_len));
|
||||
}
|
||||
|
||||
rstr->cache.iov_len = length;
|
||||
rstr->refer.iov_base = NULL;
|
||||
rstr->refer.iov_len = 0;
|
||||
}
|
||||
|
||||
static void string_commit2cache(struct http_decoder_string *rstr)
|
||||
{
|
||||
if (rstr->cache.iov_len == rstr->commit.iov_len &&
|
||||
rstr->cache.iov_base == rstr->commit.iov_base) {
|
||||
rstr->commit.iov_base = NULL;
|
||||
rstr->commit.iov_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//Only http header key need to backward to cache
|
||||
size_t length = 0;
|
||||
if (rstr->commit.iov_len > rstr->max_cache_size) {
|
||||
length = rstr->max_cache_size;
|
||||
} else {
|
||||
length = rstr->commit.iov_len;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
if (NULL == rstr->cache.iov_base) {
|
||||
rstr->cache.iov_base = CALLOC(char, length + 1);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
memcpy(rstr->cache.iov_base, rstr->commit.iov_base, length);
|
||||
rstr->cache.iov_len = length;
|
||||
|
||||
rstr->commit.iov_base = NULL;
|
||||
rstr->commit.iov_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_string_cache(struct http_decoder_string *rstr)
|
||||
{
|
||||
if (NULL == rstr) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rstr->state) {
|
||||
case STRING_STATE_REFER:
|
||||
string_refer2cache(rstr);
|
||||
break;
|
||||
case STRING_STATE_CACHE:
|
||||
break;
|
||||
case STRING_STATE_COMMIT:
|
||||
//commit backward to cache
|
||||
string_commit2cache(rstr);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
rstr->state = STRING_STATE_CACHE;
|
||||
}
|
||||
|
||||
void http_decoder_string_commit(struct http_decoder_string *rstr)
|
||||
{
|
||||
if (NULL == rstr) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rstr->state) {
|
||||
case STRING_STATE_REFER:
|
||||
if (rstr->cache.iov_len) {
|
||||
http_decoder_string_cache(rstr);
|
||||
|
||||
rstr->commit.iov_base = rstr->cache.iov_base;
|
||||
rstr->commit.iov_len = rstr->cache.iov_len;
|
||||
// not overwrite rstr->cache.iov_base
|
||||
} else {
|
||||
rstr->commit.iov_base = rstr->refer.iov_base;
|
||||
rstr->commit.iov_len = rstr->refer.iov_len;
|
||||
|
||||
rstr->refer.iov_base = NULL;
|
||||
rstr->refer.iov_len = 0;
|
||||
}
|
||||
break;
|
||||
case STRING_STATE_CACHE:
|
||||
rstr->commit.iov_base = rstr->cache.iov_base;
|
||||
rstr->commit.iov_len = rstr->cache.iov_len;
|
||||
// not overwrite rstr->cache.iov_base
|
||||
break;
|
||||
default:
|
||||
//abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->state = STRING_STATE_COMMIT;
|
||||
}
|
||||
|
||||
void http_decoder_string_reset(struct http_decoder_string *rstr)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
switch (rstr->state) {
|
||||
case STRING_STATE_INIT:
|
||||
case STRING_STATE_REFER:
|
||||
case STRING_STATE_CACHE:
|
||||
case STRING_STATE_COMMIT:
|
||||
FREE(rstr->cache.iov_base);
|
||||
memset(rstr, 0, sizeof(struct http_decoder_string));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->state = STRING_STATE_INIT;
|
||||
}
|
||||
|
||||
|
||||
void http_decoder_string_init(struct http_decoder_string *rstr,
|
||||
size_t max_cache_size)
|
||||
{
|
||||
rstr->max_cache_size = max_cache_size;
|
||||
}
|
||||
|
||||
void http_decoder_string_reinit(struct http_decoder_string *rstr)
|
||||
{
|
||||
if (rstr->state == STRING_STATE_CACHE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rstr->state == STRING_STATE_COMMIT &&
|
||||
rstr->cache.iov_base == rstr->commit.iov_base &&
|
||||
rstr->cache.iov_len == rstr->commit.iov_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rstr->cache.iov_base != NULL) {
|
||||
FREE(rstr->cache.iov_base);
|
||||
rstr->cache.iov_len = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
rstr->refer.iov_base = NULL;
|
||||
rstr->refer.iov_len = 0;
|
||||
rstr->commit.iov_base = NULL;
|
||||
rstr->commit.iov_len = 0;
|
||||
rstr->state = STRING_STATE_INIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
enum string_state http_decoder_string_state(const struct http_decoder_string *rstr)
|
||||
{
|
||||
return rstr->state;
|
||||
}
|
||||
|
||||
int http_decoder_string_get(const struct http_decoder_string *rstr, hstring *out)
|
||||
{
|
||||
if (NULL == rstr || NULL == out) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (http_decoder_string_state(rstr) == STRING_STATE_COMMIT) {
|
||||
out->iov_base = rstr->commit.iov_base;
|
||||
out->iov_len = rstr->commit.iov_len;
|
||||
} else {
|
||||
out->iov_base = NULL;
|
||||
out->iov_len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void http_decoder_string_dump(struct http_decoder_string *rstr, const char *desc)
|
||||
{
|
||||
if (NULL == rstr) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *refer_str = safe_dup((char *)rstr->refer.iov_base, rstr->refer.iov_len);
|
||||
char *cache_str = safe_dup((char *)rstr->cache.iov_base, rstr->cache.iov_len);
|
||||
char *commit_str = safe_dup((char *)rstr->commit.iov_base, rstr->commit.iov_len);
|
||||
|
||||
printf("%s: state: %s, refer: {len: %02zu, iov_base: %s}, cache: {len: %02zu, iov_base: %s}, commit: {len: %02zu, iov_base: %s}\n",
|
||||
desc, string_state_to_desc(rstr->state),
|
||||
rstr->refer.iov_len, refer_str,
|
||||
rstr->cache.iov_len, cache_str,
|
||||
rstr->commit.iov_len, commit_str);
|
||||
|
||||
FREE(refer_str);
|
||||
FREE(cache_str);
|
||||
FREE(commit_str);
|
||||
}
|
||||
74
decoders/http/http_decoder_string.h
Normal file
74
decoders/http/http_decoder_string.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef _HTTP_DECODER_STRING_H_
|
||||
#define _HTTP_DECODER_STRING_H_
|
||||
|
||||
#include "stellar/http.h"
|
||||
|
||||
enum string_state {
|
||||
STRING_STATE_INIT,
|
||||
STRING_STATE_REFER,
|
||||
STRING_STATE_CACHE,
|
||||
STRING_STATE_COMMIT,
|
||||
};
|
||||
|
||||
/* state transition diagram
|
||||
* +----------+
|
||||
* | |
|
||||
* \|/ |
|
||||
* +------+ |
|
||||
* | init | |
|
||||
* +------+ |
|
||||
* | |
|
||||
* +---->| |
|
||||
* | \|/ |
|
||||
* | +-------+ |
|
||||
* | | refer |--+ |
|
||||
* | +-------+ | |
|
||||
* | | | |
|
||||
* | \|/ | |
|
||||
* | +-------+ | |
|
||||
* +--| cache | | |
|
||||
* +-------+ | |
|
||||
* | | |
|
||||
* |<------+ |
|
||||
* \|/ |
|
||||
* +--------+ |
|
||||
* | commit | |
|
||||
* +--------+ |
|
||||
* | |
|
||||
* \|/ |
|
||||
* +--------+ |
|
||||
* | reset |----+
|
||||
* +--------+
|
||||
*/
|
||||
|
||||
|
||||
//http decoder string
|
||||
struct http_decoder_string {
|
||||
hstring refer; // shallow copy
|
||||
hstring cache; // deep copy
|
||||
hstring commit;
|
||||
|
||||
enum string_state state;
|
||||
size_t max_cache_size;
|
||||
};
|
||||
|
||||
void http_decoder_string_refer(struct http_decoder_string *rstr,
|
||||
const char *at, size_t length);
|
||||
|
||||
void http_decoder_string_cache(struct http_decoder_string *rstr);
|
||||
|
||||
void http_decoder_string_commit(struct http_decoder_string *rstr);
|
||||
|
||||
void http_decoder_string_reset(struct http_decoder_string *rstr);
|
||||
|
||||
void http_decoder_string_init(struct http_decoder_string *rstr,
|
||||
size_t max_cache_size);
|
||||
|
||||
void http_decoder_string_reinit(struct http_decoder_string *rstr);
|
||||
|
||||
enum string_state http_decoder_string_state(const struct http_decoder_string *rstr);
|
||||
|
||||
int http_decoder_string_get(const struct http_decoder_string *rstr, hstring *out);
|
||||
|
||||
void http_decoder_string_dump(struct http_decoder_string *rstr, const char *desc);
|
||||
#endif
|
||||
534
decoders/http/http_decoder_table.cpp
Normal file
534
decoders/http/http_decoder_table.cpp
Normal file
@@ -0,0 +1,534 @@
|
||||
#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; //current parsing header
|
||||
size_t header_iter; //plugins iterate cursor
|
||||
size_t commit_header_index; //pushed to plugins, whether has called http_message_header_next()
|
||||
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);
|
||||
table->commit_header_index = 0;
|
||||
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.iov_base != NULL) {
|
||||
FREE(table->uri.cache.iov_base);
|
||||
}
|
||||
if (table->status.cache.iov_base != NULL) {
|
||||
FREE(table->status.cache.iov_base);
|
||||
}
|
||||
if (table->method.cache.iov_base != NULL) {
|
||||
FREE(table->method.cache.iov_base);
|
||||
}
|
||||
if (table->version.cache.iov_base != NULL) {
|
||||
FREE(table->version.cache.iov_base);
|
||||
}
|
||||
if (table->body.cache.iov_base != NULL) {
|
||||
FREE(table->body.cache.iov_base);
|
||||
}
|
||||
|
||||
if (table->headers != NULL) {
|
||||
for (size_t i = 0; i < table->header_cnt; i++) {
|
||||
if (table->headers[i].key.cache.iov_base != NULL) {
|
||||
FREE(table->headers[i].key.cache.iov_base);
|
||||
}
|
||||
|
||||
if (table->headers[i].val.cache.iov_base != NULL) {
|
||||
FREE(table->headers[i].val.cache.iov_base);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
assert(table);
|
||||
struct http_decoder_header *header = NULL;
|
||||
|
||||
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++) {
|
||||
for (size_t i = 0; i < table->commit_header_index; i++) {
|
||||
//todo, reset header_index, avoid realloc headers as much as possible
|
||||
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(const struct http_decoder_table *table, hstring *out)
|
||||
{
|
||||
if (NULL == table || NULL == out) {
|
||||
return -1;
|
||||
}
|
||||
return http_decoder_string_get(&table->uri, out);
|
||||
}
|
||||
|
||||
int http_decoder_table_get_method(const struct http_decoder_table *table, hstring *out)
|
||||
{
|
||||
if (NULL == table || NULL == out) {
|
||||
return -1;
|
||||
}
|
||||
return http_decoder_string_get(&table->method, out);
|
||||
}
|
||||
|
||||
int http_decoder_table_get_status(const struct http_decoder_table *table, hstring *out)
|
||||
{
|
||||
if (NULL == table || NULL == out) {
|
||||
return -1;
|
||||
}
|
||||
return http_decoder_string_get(&table->status, out);
|
||||
}
|
||||
|
||||
int http_decoder_table_get_version(const struct http_decoder_table *table, hstring *out)
|
||||
{
|
||||
if (NULL == table || NULL == out) {
|
||||
return -1;
|
||||
}
|
||||
return http_decoder_string_get(&table->version, out);
|
||||
}
|
||||
|
||||
int http_decoder_table_get_body(const struct http_decoder_table *table, hstring *out)
|
||||
{
|
||||
if (NULL == table || NULL == out) {
|
||||
return -1;
|
||||
}
|
||||
return http_decoder_string_get(&table->body, out);
|
||||
}
|
||||
|
||||
int http_decoder_table_get_header(const struct http_decoder_table *table, const hstring *key,
|
||||
struct http_header *hdr_result)
|
||||
{
|
||||
for (size_t i = 0; i < table->header_cnt; i++) {
|
||||
const struct http_decoder_header *tmp_header = &table->headers[i];
|
||||
if (tmp_header->key.commit.iov_len != key->iov_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (http_decoder_string_state(&tmp_header->key) == STRING_STATE_COMMIT &&
|
||||
http_decoder_string_state(&tmp_header->val) == STRING_STATE_COMMIT) {
|
||||
hstring tmp_key;
|
||||
http_decoder_string_get(&tmp_header->key, &tmp_key);
|
||||
|
||||
if (tmp_key.iov_len == key->iov_len &&
|
||||
(0 == strncasecmp((char *)tmp_key.iov_base, (char *)key->iov_base, key->iov_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 1;
|
||||
}
|
||||
}
|
||||
|
||||
hdr->key.iov_base = NULL;
|
||||
hdr->key.iov_len = 0;
|
||||
hdr->val.iov_base = NULL;
|
||||
hdr->val.iov_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)) {
|
||||
if (NULL == table || (table->commit_header_index == table->header_index)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const 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;
|
||||
}
|
||||
|
||||
void http_decoder_table_update_commit_index(struct http_decoder_table *table)
|
||||
{
|
||||
table->commit_header_index = table->header_index;
|
||||
}
|
||||
|
||||
int http_decoder_table_get_total_parsed_header(struct http_decoder_table *table)
|
||||
{
|
||||
return table->header_index;
|
||||
}
|
||||
80
decoders/http/http_decoder_table.h
Normal file
80
decoders/http/http_decoder_table.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef _HTTP_DECODER_TABLE_H_
|
||||
#define _HTTP_DECODER_TABLE_H_
|
||||
#include <stddef.h>
|
||||
#include "stellar/http.h"
|
||||
#include "http_decoder_inc.h"
|
||||
#include "http_decoder_string.h"
|
||||
|
||||
enum http_item {
|
||||
HTTP_ITEM_URI = 0x01,
|
||||
HTTP_ITEM_STATUS = 0x02,
|
||||
HTTP_ITEM_METHOD = 0x03,
|
||||
HTTP_ITEM_VERSION = 0x04,
|
||||
HTTP_ITEM_HDRKEY = 0x05,
|
||||
HTTP_ITEM_HDRVAL = 0x06,
|
||||
HTTP_ITEM_BODY = 0x07,
|
||||
};
|
||||
|
||||
struct http_decoder_table;
|
||||
struct http_decoder_table *http_decoder_table_new(nmx_pool_t *mempool);
|
||||
|
||||
void http_decoder_table_free(struct http_decoder_table *table);
|
||||
|
||||
enum string_state
|
||||
http_decoder_table_state(struct http_decoder_table *table, enum http_item type);
|
||||
|
||||
void http_decoder_table_refer(struct http_decoder_table *table, enum http_item type,
|
||||
const char *at, size_t len);
|
||||
|
||||
void http_decoder_table_cache(struct http_decoder_table *table, enum http_item type);
|
||||
|
||||
void http_decoder_table_commit(struct http_decoder_table *table, enum http_item type);
|
||||
|
||||
void http_decoder_table_reset(struct http_decoder_table *table, enum http_item type);
|
||||
|
||||
void http_decoder_table_reinit(struct http_decoder_table *table);
|
||||
|
||||
void http_decoder_table_dump(struct http_decoder_table *table);
|
||||
|
||||
int http_decoder_table_get_uri(const struct http_decoder_table *table, hstring *out);
|
||||
|
||||
int http_decoder_table_get_method(const struct http_decoder_table *table, hstring *out);
|
||||
|
||||
int http_decoder_table_get_status(const struct http_decoder_table *table, hstring *out);
|
||||
|
||||
int http_decoder_table_get_version(const struct http_decoder_table *table, hstring *out);
|
||||
|
||||
int http_decoder_table_get_body(const struct http_decoder_table *table, hstring *out);
|
||||
|
||||
int http_decoder_table_get_header(const struct http_decoder_table *table,
|
||||
const hstring *key,
|
||||
struct http_header *hdr_res);
|
||||
|
||||
int http_decoder_table_iter_header(struct http_decoder_table *table,
|
||||
struct http_header *hdr);
|
||||
int http_decoder_table_reset_header_iter(struct http_decoder_table *table);
|
||||
/**
|
||||
* @brief Is there a parsed header
|
||||
*
|
||||
* @retval yes(1) no(0)
|
||||
*/
|
||||
int http_decoder_table_has_parsed_header(struct http_decoder_table *table);
|
||||
|
||||
/**
|
||||
* @brief If headers have been parsed completely
|
||||
*
|
||||
* @retval yes(1) no(0)
|
||||
*/
|
||||
int http_decoder_table_header_complete(struct http_decoder_table *table);
|
||||
|
||||
/**
|
||||
* @brief set flag for headers parsed completely
|
||||
*/
|
||||
void http_decoder_table_set_header_complete(struct http_decoder_table *table);
|
||||
|
||||
void http_decoder_table_reset_header_complete(struct http_decoder_table *table);
|
||||
|
||||
void http_decoder_table_update_commit_index(struct http_decoder_table *table);
|
||||
|
||||
int http_decoder_table_get_total_parsed_header(struct http_decoder_table *table);
|
||||
#endif
|
||||
107
decoders/http/http_decoder_tunnel.cpp
Normal file
107
decoders/http/http_decoder_tunnel.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include "http_decoder_inc.h"
|
||||
#include "llhttp.h"
|
||||
|
||||
struct http_tunnel_message
|
||||
{
|
||||
enum http_tunnel_message_type type;
|
||||
hstring tunnel_payload;
|
||||
};
|
||||
|
||||
|
||||
int httpd_tunnel_identify(struct http_decoder_env *httpd_env, int curdir, struct http_decoder_half_data *hfdata)
|
||||
{
|
||||
if(0 == httpd_env->hd_cfg.proxy_enable){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(FLOW_DIRECTION_C2S == curdir){
|
||||
struct http_request_line reqline = {};
|
||||
http_decoder_half_data_get_request_line(hfdata, &reqline);
|
||||
if(0 == strncasecmp_safe("CONNECT", (char *)reqline.method.iov_base,
|
||||
7, reqline.method.iov_len)){
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
struct http_response_line resline = {};
|
||||
http_decoder_half_data_get_response_line(hfdata, &resline);
|
||||
if(resline.status_code == HTTP_STATUS_OK
|
||||
&& 0 == strncasecmp_safe("Connection established", (char *)resline.status.iov_base,
|
||||
strlen("Connection established"), resline.status.iov_len)){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int httpd_is_tunnel_session(const struct http_decoder_env *httpd_env, const struct http_decoder_exdata *ex_data)
|
||||
{
|
||||
if(0 == httpd_env->hd_cfg.proxy_enable){
|
||||
return 0;
|
||||
}
|
||||
return (ex_data && ex_data->tunnel_state != HTTP_TUN_NON);
|
||||
}
|
||||
|
||||
int httpd_in_tunnel_transmitting(const struct http_decoder_env *httpd_env, struct http_decoder_exdata *ex_data)
|
||||
{
|
||||
if(0 == httpd_env->hd_cfg.proxy_enable){
|
||||
return 0;
|
||||
}
|
||||
return (ex_data && ex_data->tunnel_state >= HTTP_TUN_INNER_STARTING);
|
||||
}
|
||||
|
||||
enum http_tunnel_message_type httpd_tunnel_state_to_msg(const struct http_decoder_exdata *ex_data)
|
||||
{
|
||||
if(ex_data->tunnel_state == HTTP_TUN_INNER_STARTING){
|
||||
return HTTP_TUNNEL_OPENING;
|
||||
}
|
||||
if(ex_data->tunnel_state == HTTP_TUN_INNER_TRANS){
|
||||
return HTTP_TUNNEL_ACTIVE;
|
||||
}
|
||||
return HTTP_TUNNEL_MSG_MAX;
|
||||
}
|
||||
|
||||
void httpd_tunnel_state_update(struct http_decoder_exdata *ex_data)
|
||||
{
|
||||
if(ex_data->tunnel_state == HTTP_TUN_INNER_STARTING){
|
||||
ex_data->tunnel_state = HTTP_TUN_INNER_TRANS;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_push_tunnel_data(struct session *sess, const struct http_decoder_exdata *exdata, enum http_tunnel_message_type type, const char *payload, uint16_t payload_len)
|
||||
{
|
||||
struct http_tunnel_message *tmsg = (struct http_tunnel_message *)CALLOC(struct http_tunnel_message, 1);
|
||||
tmsg->type = type;
|
||||
tmsg->tunnel_payload.iov_base = (char *)payload;
|
||||
tmsg->tunnel_payload.iov_len = payload_len;
|
||||
session_mq_publish_message(sess, exdata->pub_topic_id, tmsg);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void http_tunnel_message_get_payload(const struct http_tunnel_message *tmsg,
|
||||
hstring *tunnel_payload)
|
||||
{
|
||||
if (unlikely(NULL == tmsg || tunnel_payload == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
tunnel_payload->iov_base = tmsg->tunnel_payload.iov_base;
|
||||
tunnel_payload->iov_len = tmsg->tunnel_payload.iov_len;
|
||||
}
|
||||
|
||||
enum http_tunnel_message_type http_tunnel_message_type_get(const struct http_tunnel_message *tmsg)
|
||||
{
|
||||
return tmsg->type;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
35
decoders/http/http_decoder_tunnel.h
Normal file
35
decoders/http/http_decoder_tunnel.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "http_decoder_inc.h"
|
||||
#include "http_decoder_half.h"
|
||||
|
||||
enum http_tunnel_state{
|
||||
HTTP_TUN_NON = 0, // init, or not tunnel session
|
||||
HTTP_TUN_C2S_HDR_START, //CONNECT ...
|
||||
HTTP_TUN_C2S_END, //CONNECT request end
|
||||
HTTP_TUN_S2C_START, // HTTP 200 connet established
|
||||
HTTP_TUN_INNER_STARTING, // http inner tunnel protocol starting
|
||||
HTTP_TUN_INNER_TRANS, // http inner tunnel protocol transmitting
|
||||
};
|
||||
|
||||
/************************************************************
|
||||
* HTTP TUNNEL WITH CONNECT METHOD.
|
||||
*************************************************************/
|
||||
struct http_tunnel_message;
|
||||
#define HTTP_DECODER_TUNNEL_TOPIC "HTTP_DECODER_TUNNEL_MESSAGE"
|
||||
|
||||
enum http_tunnel_message_type {
|
||||
HTTP_TUNNEL_OPENING,
|
||||
HTTP_TUNNEL_ACTIVE,
|
||||
HTTP_TUNNEL_CLOSING,
|
||||
HTTP_TUNNEL_MSG_MAX
|
||||
};
|
||||
enum http_tunnel_message_type http_tunnel_message_type_get(const struct http_tunnel_message *tmsg);
|
||||
void http_tunnel_message_get_payload(const struct http_tunnel_message *tmsg, struct iovec *tunnel_payload);
|
||||
|
||||
|
||||
int httpd_tunnel_identify(struct http_decoder_env *httpd_env, int curdir, struct http_decoder_half_data *hfdata);
|
||||
int httpd_is_tunnel_session(const struct http_decoder_env *httpd_env, const struct http_decoder_exdata *ex_data);
|
||||
int httpd_in_tunnel_transmitting(const struct http_decoder_env *httpd_env, struct http_decoder_exdata *ex_data);
|
||||
void httpd_tunnel_state_update(struct http_decoder_exdata *ex_data);
|
||||
void http_decoder_push_tunnel_data(struct session *sess, const struct http_decoder_exdata *exdata, enum http_tunnel_message_type type, const char *payload, uint16_t payload_len);
|
||||
enum http_tunnel_message_type httpd_tunnel_state_to_msg(const struct http_decoder_exdata *ex_data);
|
||||
309
decoders/http/http_decoder_utils.cpp
Normal file
309
decoders/http/http_decoder_utils.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "stellar/http.h"
|
||||
#include "http_decoder_inc.h"
|
||||
|
||||
char *safe_dup(const char *str, size_t len)
|
||||
{
|
||||
if (str == NULL || len == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char *dup = CALLOC(char, len + 1);
|
||||
memcpy(dup, str, len);
|
||||
return dup;
|
||||
}
|
||||
|
||||
int strncasecmp_safe(const char *fix_s1, const char *dyn_s2, size_t fix_n1, size_t dyn_n2)
|
||||
{
|
||||
if (fix_s1 == NULL || dyn_s2 == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (fix_n1 != dyn_n2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return strncasecmp(fix_s1, dyn_s2, fix_n1);
|
||||
}
|
||||
|
||||
const char *http_message_type_to_string(enum http_message_type type)
|
||||
{
|
||||
const char *sname = "unknown_msg_type";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HTTP_MESSAGE_REQ_LINE:
|
||||
sname = "HTTP_MESSAGE_REQ_LINE";
|
||||
break;
|
||||
case HTTP_MESSAGE_REQ_HEADER:
|
||||
sname = "HTTP_MESSAGE_REQ_HEADER";
|
||||
break;
|
||||
case HTTP_MESSAGE_REQ_HEADER_END:
|
||||
sname = "HTTP_MESSAGE_REQ_HEADER_END";
|
||||
break;
|
||||
case HTTP_MESSAGE_REQ_BODY_START:
|
||||
sname = "HTTP_MESSAGE_REQ_BODY_START";
|
||||
break;
|
||||
case HTTP_MESSAGE_REQ_BODY:
|
||||
sname = "HTTP_MESSAGE_REQ_BODY";
|
||||
break;
|
||||
case HTTP_MESSAGE_REQ_BODY_END:
|
||||
sname = "HTTP_MESSAGE_REQ_BODY_END";
|
||||
break;
|
||||
case HTTP_MESSAGE_RES_LINE:
|
||||
sname = "HTTP_MESSAGE_RES_LINE";
|
||||
break;
|
||||
case HTTP_MESSAGE_RES_HEADER:
|
||||
sname = "HTTP_MESSAGE_RES_HEADER";
|
||||
break;
|
||||
case HTTP_MESSAGE_RES_HEADER_END:
|
||||
sname = "HTTP_MESSAGE_RES_HEADER_END";
|
||||
break;
|
||||
case HTTP_MESSAGE_RES_BODY_START:
|
||||
sname = "HTTP_MESSAGE_RES_BODY_START";
|
||||
break;
|
||||
case HTTP_MESSAGE_RES_BODY:
|
||||
sname = "HTTP_MESSAGE_RES_BODY";
|
||||
break;
|
||||
case HTTP_MESSAGE_RES_BODY_END:
|
||||
sname = "HTTP_MESSAGE_RES_BODY_END";
|
||||
break;
|
||||
case HTTP_TRANSACTION_START:
|
||||
sname = "HTTP_TRANSACTION_START";
|
||||
break;
|
||||
case HTTP_TRANSACTION_END:
|
||||
sname = "HTTP_TRANSACTION_END";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return sname;
|
||||
}
|
||||
|
||||
int http_message_type_is_req(struct session *sess, enum http_message_type msg_type)
|
||||
{
|
||||
int is_req_msg = 0;
|
||||
|
||||
switch (msg_type)
|
||||
{
|
||||
case HTTP_MESSAGE_REQ_LINE:
|
||||
case HTTP_MESSAGE_REQ_HEADER:
|
||||
case HTTP_MESSAGE_REQ_HEADER_END:
|
||||
case HTTP_MESSAGE_REQ_BODY_START:
|
||||
case HTTP_MESSAGE_REQ_BODY:
|
||||
case HTTP_MESSAGE_REQ_BODY_END:
|
||||
is_req_msg = 1;
|
||||
break;
|
||||
|
||||
case HTTP_MESSAGE_RES_LINE:
|
||||
case HTTP_MESSAGE_RES_HEADER:
|
||||
case HTTP_MESSAGE_RES_HEADER_END:
|
||||
case HTTP_MESSAGE_RES_BODY_START:
|
||||
case HTTP_MESSAGE_RES_BODY:
|
||||
case HTTP_MESSAGE_RES_BODY_END:
|
||||
is_req_msg = 0;
|
||||
break;
|
||||
|
||||
case HTTP_TRANSACTION_START:
|
||||
case HTTP_TRANSACTION_END:
|
||||
{
|
||||
enum flow_direction cur_dir = session_get_current_flow_direction(sess);
|
||||
if (FLOW_DIRECTION_C2S == cur_dir)
|
||||
{
|
||||
is_req_msg = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_req_msg = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
fprintf(stderr, "unknow message type:%d\n", (int)msg_type);
|
||||
break;
|
||||
}
|
||||
return is_req_msg;
|
||||
}
|
||||
|
||||
int http_event_is_req(enum http_event event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case HTTP_EVENT_REQ_INIT:
|
||||
case HTTP_EVENT_REQ_LINE:
|
||||
case HTTP_EVENT_REQ_HDR:
|
||||
case HTTP_EVENT_REQ_HDR_END:
|
||||
case HTTP_EVENT_REQ_BODY_BEGIN:
|
||||
case HTTP_EVENT_REQ_BODY_DATA:
|
||||
case HTTP_EVENT_REQ_BODY_END:
|
||||
case HTTP_EVENT_REQ_END:
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_RES_INIT:
|
||||
case HTTP_EVENT_RES_LINE:
|
||||
case HTTP_EVENT_RES_HDR:
|
||||
case HTTP_EVENT_RES_HDR_END:
|
||||
case HTTP_EVENT_RES_BODY_BEGIN:
|
||||
case HTTP_EVENT_RES_BODY_DATA:
|
||||
case HTTP_EVENT_RES_BODY_END:
|
||||
case HTTP_EVENT_RES_END:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
fprintf(stderr, "unknow event type:%d\n", (int)event);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int stellar_session_mq_get_topic_id_reliable(struct stellar *st, const char *topic_name, stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg)
|
||||
{
|
||||
int topic_id = stellar_mq_get_topic_id(st, topic_name);
|
||||
if (topic_id < 0)
|
||||
{
|
||||
topic_id = stellar_mq_create_topic(st, topic_name, msg_free_cb, msg_free_arg);
|
||||
}
|
||||
return topic_id;
|
||||
}
|
||||
|
||||
static const unsigned char __g_httpd_hextable[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
|
||||
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
|
||||
0, 10, 11, 12, 13, 14, 15 /* 0x60 - 0x66 */
|
||||
};
|
||||
|
||||
/* the input is a single hex digit */
|
||||
#define onehex2dec(x) __g_httpd_hextable[x - '0']
|
||||
|
||||
#include <ctype.h>
|
||||
// https://github.com/curl/curl/blob/2e930c333658725657b94a923d175c6622e0f41d/lib/urlapi.c
|
||||
void httpd_url_decode(const char *string, size_t length, char *ostring, size_t *olen)
|
||||
{
|
||||
size_t alloc = length;
|
||||
char *ns = ostring;
|
||||
|
||||
while (alloc)
|
||||
{
|
||||
unsigned char in = (unsigned char)*string;
|
||||
if (('%' == in) && (alloc > 2) &&
|
||||
isxdigit(string[1]) && isxdigit(string[2]))
|
||||
{
|
||||
/* this is two hexadecimal digits following a '%' */
|
||||
in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]);
|
||||
string += 3;
|
||||
alloc -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
string++;
|
||||
alloc--;
|
||||
}
|
||||
*ns++ = (char)in;
|
||||
}
|
||||
*ns = 0; /* terminate it */
|
||||
|
||||
if (olen)
|
||||
/* store output size */
|
||||
*olen = ns - ostring;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int httpd_url_is_encoded(const char *url, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (url[i] == '%')
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void httpd_set_tcp_addr(const struct tcphdr *tcph, struct httpd_session_addr *addr, enum flow_direction fdir)
|
||||
{
|
||||
if (FLOW_DIRECTION_C2S == fdir)
|
||||
{
|
||||
addr->sport = tcph->th_sport;
|
||||
addr->dport = tcph->th_dport;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr->sport = tcph->th_dport;
|
||||
addr->dport = tcph->th_sport;
|
||||
}
|
||||
}
|
||||
static void httpd_set_ipv4_addr(const struct ip *ip4h, struct httpd_session_addr *addr, enum flow_direction fdir)
|
||||
{
|
||||
addr->ipver = 4;
|
||||
if (FLOW_DIRECTION_C2S == fdir)
|
||||
{
|
||||
addr->saddr4 = ip4h->ip_src.s_addr;
|
||||
addr->daddr4 = ip4h->ip_dst.s_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr->saddr4 = ip4h->ip_dst.s_addr;
|
||||
addr->daddr4 = ip4h->ip_src.s_addr;
|
||||
}
|
||||
}
|
||||
static void httpd_set_ipv6_addr(const struct ip6_hdr *ip6h, struct httpd_session_addr *addr, enum flow_direction fdir)
|
||||
{
|
||||
addr->ipver = 6;
|
||||
if (FLOW_DIRECTION_C2S == fdir)
|
||||
{
|
||||
memcpy(&addr->saddr6, &ip6h->ip6_src, sizeof(struct in6_addr));
|
||||
memcpy(&addr->daddr6, &ip6h->ip6_dst, sizeof(struct in6_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&addr->saddr6, &ip6h->ip6_dst, sizeof(struct in6_addr));
|
||||
memcpy(&addr->daddr6, &ip6h->ip6_src, sizeof(struct in6_addr));
|
||||
}
|
||||
}
|
||||
|
||||
void httpd_session_get_addr(const struct session *sess, struct httpd_session_addr *addr)
|
||||
{
|
||||
if (sess == NULL || addr == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
enum flow_direction fdir = session_get_current_flow_direction(sess);
|
||||
const struct packet *raw_pkt = session_get_first_packet(sess, fdir);
|
||||
if (NULL == raw_pkt)
|
||||
{
|
||||
addr->ipver = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
struct layer pkt_layer = {};
|
||||
PACKET_FOREACH_LAYER_REVERSE(raw_pkt, pkt_layer)
|
||||
{
|
||||
if (pkt_layer.proto == LAYER_PROTO_TCP)
|
||||
{
|
||||
httpd_set_tcp_addr(pkt_layer.hdr.tcp, addr, fdir);
|
||||
}
|
||||
else if (pkt_layer.proto == LAYER_PROTO_IPV4)
|
||||
{
|
||||
httpd_set_ipv4_addr(pkt_layer.hdr.ip4, addr, fdir);
|
||||
break;
|
||||
}
|
||||
else if (pkt_layer.proto == LAYER_PROTO_IPV6)
|
||||
{
|
||||
httpd_set_ipv6_addr(pkt_layer.hdr.ip6, addr, fdir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
80
decoders/http/http_decoder_utils.h
Normal file
80
decoders/http/http_decoder_utils.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <cstddef>
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#include <bits/types/struct_iovec.h>
|
||||
#include "stellar/stellar.h"
|
||||
#include "stellar/utils.h"
|
||||
#include "stellar/session.h"
|
||||
#include "stellar/stellar_mq.h"
|
||||
#include "stellar/stellar_exdata.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
char *safe_dup(const char *str, size_t len);
|
||||
int strncasecmp_safe(const char *fix_s1, const char *dyn_s2, size_t fix_n1, size_t dyn_n2);
|
||||
const char *http_message_type_to_string(enum http_message_type type);
|
||||
int http_message_type_is_req(struct session *sess, enum http_message_type msg_type);
|
||||
int http_event_is_req(enum http_event event);
|
||||
int stellar_session_mq_get_topic_id_reliable(struct stellar *st, const char *topic_name, stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg);
|
||||
void httpd_url_decode(const char *string, size_t length, char *ostring, size_t *olen);
|
||||
int httpd_url_is_encoded(const char *url, size_t len);
|
||||
/******************************************************************************
|
||||
* Logger
|
||||
******************************************************************************/
|
||||
|
||||
enum http_decoder_log_level {
|
||||
DEBUG = 0x11,
|
||||
WARN = 0x12,
|
||||
INFO = 0x13,
|
||||
ERROR = 0x14,
|
||||
};
|
||||
|
||||
#ifndef http_decoder_log
|
||||
#define http_decoder_log(level, format, ...) \
|
||||
{ \
|
||||
switch (level) \
|
||||
{ \
|
||||
case DEBUG: \
|
||||
fprintf(stdout, "HTTP_DECODER [DEBUG] " format "\n", ##__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
break; \
|
||||
case WARN: \
|
||||
fprintf(stdout, "HTTP_DECODER [WARN] " format "\n", ##__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
break; \
|
||||
case INFO: \
|
||||
fprintf(stdout, "HTTP_DECODER [INFO] " format "\n", ##__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
break; \
|
||||
case ERROR: \
|
||||
fprintf(stderr, "HTTP_DECODER [ERROR] " format "\n", ##__VA_ARGS__); \
|
||||
fflush(stderr); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
struct httpd_session_addr
|
||||
{
|
||||
uint8_t ipver; /* 4 or 6 */
|
||||
uint16_t sport; /* network order */
|
||||
uint16_t dport; /* network order */
|
||||
union
|
||||
{
|
||||
uint32_t saddr4;
|
||||
uint32_t daddr4;
|
||||
struct in6_addr saddr6;
|
||||
struct in6_addr daddr6;
|
||||
};
|
||||
};
|
||||
void httpd_session_get_addr(const struct session *sess, struct httpd_session_addr *addr);
|
||||
11
decoders/http/version.map
Normal file
11
decoders/http/version.map
Normal file
@@ -0,0 +1,11 @@
|
||||
VERS_3.0{
|
||||
global:
|
||||
extern "C" {
|
||||
http_message_*;
|
||||
http_decoder_init;
|
||||
http_decoder_exit;
|
||||
http_decoder_tcp_stream_msg_cb;
|
||||
http_tunnel_message_*;
|
||||
};
|
||||
local: *;
|
||||
};
|
||||
Reference in New Issue
Block a user