1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
#pragma once
#include <stdint.h>
#include <stddef.h>
#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 <bits/types/struct_iovec.h>
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
|