#pragma once #include #include #include "stellar/session.h" #include "stellar/http.h" #include "llhttp.h" #include "uthash/utarray.h" #include "http_decoder_decompress.h" #ifdef __cplusplus extern "C" { #endif #define HTTP_HEADER_FIELD_RESERVE_NUM (16) #define HTTP_HEADER_FIELD_NAME_HOST "Host" #define HTTP_HEADER_FIELD_NAME_USER_AGENT "User-Agent" #define HTTP_HEADER_FIELD_NAME_REFERER "Referer" #define HTTP_HEADER_FIELD_NAME_COOKIE "Cookie" #define HTTP_HEADER_FIELD_NAME_SET_COOKIE "Set-Cookie" #define HTTP_HEADER_FIELD_NAME_CONTENT_TYPE "Content-Type" #define HTTP_HEADER_FIELD_NAME_CONTENT_LENGTH "Content-Length" #define HTTP_HEADER_FIELD_NAME_CONTENT_ENCODING "Content-Encoding" #define HTTP_HEADER_FIELD_NAME_TRANSFER_ENCODING "Transfer-Encoding" enum http_event { __HTTP_EVENT_RESERVED = 0, 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_body { char *body; size_t body_sz; size_t offset; // accumulated int is_finished; }; #ifndef hstring #include typedef struct iovec hstring; #endif struct http_half_data { enum flow_type flow_dir; uint32_t transaction_seq; // seq of this half flow, is last http_lalf->transaction_num value union { struct http_request_line req_line; struct http_status_line status_line; }; /* headers */ struct http_buffer *cached_header_buffer; // maybe null hstring joint_url; // malloc, need be free enum http_content_encoding content_encoding_type; int transfer_encoding_is_chunked; // -1: not set, 0: false, 1: true UT_array *ut_filed_array; // inner struct, need to transform to header->field_array struct http_header header; /* body */ struct http_body raw_body; struct http_content_decompress *decompress; struct http_body decompress_body; }; struct http_half_parser { llhttp_t llhttp_parser; llhttp_settings_t settings; struct http_half *half_ref; // used in llhttp callback context to get flow }; enum http_stage { HTTP_STAGE_INIT = 0, HTTP_STAGE_PENDING = 1, /* body without Content-Length, no Chunk-Encoding */ HTTP_STAGE_HEADER_PARTIAL = 2, HTTP_STAGE_BODY = 3, }; struct http_stage_shaper { enum http_stage stage; char *data; size_t data_len; long long remain_content_length; const char *headers_start; // the first header field name const char *headers_end; // the last char of \r\n\r\n struct http_buffer *headers_cache; /* ownership move to struct http_decoder_half_data when headers completed */ }; struct http_half_buffer { int is_malloc; // need free int ref_count; // +1 when push a new message char *buffer; size_t buffer_size; }; enum http_half_llhttp_stage_type { LLHTTP_STAGE_MESSAGE_BEGIN = 0, LLHTTP_STAGE_URI, LLHTTP_STAGE_METHOD, LLHTTP_STAGE_STATUS, LLHTTP_STAGE_VERSION, LLHTTP_STAGE_HEADER_FIELD, LLHTTP_STAGE_HEADER_FIELD_COMPLETE, LLHTTP_STAGE_HEADER_VALUE, LLHTTP_STAGE_HEADER_VALUE_COMPLETE, LLHTTP_STAGE_HEADERS_COMPLETE, LLHTTP_STAGE_BODY, LLHTTP_STAGE_MESSAGE_COMPLETE, __LLHTTP_STAGE_MAX, }; struct http_half_llhttp_stage { const char *first_header_name_ptr; const char *last_header_value_complete_ptr; /* at + length + 4 \r\n\r\n) */ const char *last_headers_complete_ptr; enum http_half_llhttp_stage_type llhttp_last_stage; uint8_t llhttp_cb_count[__LLHTTP_STAGE_MAX]; }; struct http_half { struct session *sess_ref; struct http *http_env_ref; uint32_t transaction_num; // accumulated of all flows in this session enum http_event event; // struct http_stage_shaper shaper; struct http_half_parser parser; struct http_half_data *flow_data; // malloc when every transaction start, ownership move to message when message completed struct http_buffer *cached_header_buffer; struct http_half_llhttp_stage half_stage; }; void http_half_free(struct http_half *half); void http_half_data_free(struct http_half_data *half_data); void http_flow_parser_init(struct http_half_parser *flow_parser, enum llhttp_type type); void http_flow_body_decompress(struct http_half_data *flow_data, const char *zipdata, size_t zipdatalen); void http_event_handler(struct http_half *half, enum http_event event, struct http *httpd_env); int http_flow_stage_shaping(struct http_half *half, const char *newdata, size_t newdata_len); int http_half_flow_process(struct http_half *half, const char *newdata, size_t newdata_len); int http_get_header_field_count(struct http_half_data *flow_data); void http_flow_append_header_filed(struct http_half_data *flow_data, const char *at, size_t length); void http_flow_append_header_value(struct http_half_data *flow_data, const char *at, size_t length); #ifdef __cplusplus } #endif