forked from swoole/swoole-src
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathswoole_http.h
340 lines (301 loc) Β· 10 KB
/
swoole_http.h
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| Copyright (c) 2012-2015 The Swoole Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <[email protected]> |
+----------------------------------------------------------------------+
*/
#pragma once
#include "thirdparty/swoole_http_parser.h"
#include "thirdparty/multipart_parser.h"
#ifdef SW_HAVE_ZLIB
#include <zlib.h>
#endif
#ifdef SW_USE_HTTP2
#include "thirdparty/nghttp2/nghttp2.h"
#endif
enum http_header_flag
{
HTTP_HEADER_SERVER = 1u << 1,
HTTP_HEADER_CONNECTION = 1u << 2,
HTTP_HEADER_CONTENT_LENGTH = 1u << 3,
HTTP_HEADER_DATE = 1u << 4,
HTTP_HEADER_CONTENT_TYPE = 1u << 5,
HTTP_HEADER_TRANSFER_ENCODING = 1u << 6,
HTTP_HEADER_ACCEPT_ENCODING = 1u << 7,
};
enum http_compress_method
{
HTTP_COMPRESS_GZIP = 1,
HTTP_COMPRESS_DEFLATE,
HTTP_COMPRESS_BR,
};
struct http_request
{
int version;
char *path;
uint32_t path_len;
const char *ext;
uint32_t ext_len;
uint8_t post_form_urlencoded;
zval zdata;
size_t body_length;
#ifdef SW_USE_HTTP2
swString *h2_data_buffer;
#endif
// Notice: Do not change the order
zval *zobject;
zval _zobject;
zval *zserver;
zval _zserver;
zval *zheader;
zval _zheader;
zval *zget;
zval _zget;
zval *zpost;
zval _zpost;
zval *zcookie;
zval _zcookie;
zval *zfiles;
zval _zfiles;
zval *ztmpfiles;
zval _ztmpfiles;
};
struct http_response
{
enum swoole_http_method method;
int version;
int status;
char* reason;
// Notice: Do not change the order
zval *zobject;
zval _zobject;
zval *zheader;
zval _zheader;
zval *zcookie;
zval _zcookie;
zval *ztrailer;
zval _ztrailer;
};
struct http_context
{
int fd;
uint32_t completed :1;
uint32_t end :1;
uint32_t send_header :1;
#ifdef SW_HAVE_ZLIB
uint32_t enable_compression :1;
uint32_t accept_compression :1;
#endif
uint32_t chunk :1;
uint32_t keepalive :1;
uint32_t websocket :1;
uint32_t upgrade :1;
uint32_t detached :1;
uint32_t parse_cookie :1;
uint32_t parse_body :1;
uint32_t co_socket :1;
#ifdef SW_HAVE_ZLIB
int8_t compression_level;
int8_t compression_method;
#endif
#ifdef SW_USE_HTTP2
void* stream;
#endif
http_request request;
http_response response;
swoole_http_parser parser;
multipart_parser *mt_parser;
uint16_t input_var_num;
char *current_header_name;
size_t current_header_name_len;
char *current_input_name;
char *current_form_data_name;
size_t current_form_data_name_len;
zval *current_multipart_header;
const char *upload_tmp_dir;
void *private_data;
void *private_data_2;
bool (*send)(http_context* ctx, const char *data, size_t length);
bool (*sendfile)(http_context* ctx, const char *file, uint32_t l_file, off_t offset, size_t length);
bool (*close)(http_context* ctx);
};
extern zend_class_entry *swoole_http_server_ce;
extern zend_class_entry *swoole_http_request_ce;
extern zend_class_entry *swoole_http_response_ce;
extern swString *swoole_http_buffer;
extern swString *swoole_http_form_data_buffer;
#ifdef SW_HAVE_ZLIB
extern swString *swoole_zlib_buffer;
#endif
#define http_strncasecmp(const_str, at, length) \
((length >= sizeof(const_str)-1) && \
(strncasecmp(at, ZEND_STRL(const_str)) == 0))
http_context* swoole_http_context_new(int fd);
http_context* swoole_http_context_get(zval *zobject, const bool check_end);
void swoole_http_context_free(http_context *ctx);
static sw_inline zval* swoole_http_init_and_read_property(zend_class_entry *ce, zval *zobject, zval** zproperty_store_pp, const char *name, size_t name_len)
{
if (UNEXPECTED(!*zproperty_store_pp))
{
// Notice: swoole http server properties can not be unset anymore, so we can read it without checking
zval rv, *property = zend_read_property(ce, zobject, name, name_len, 0, &rv);
array_init(property);
*zproperty_store_pp = (zval *) (zproperty_store_pp + 1);
**zproperty_store_pp = *property;
}
return *zproperty_store_pp;
}
int swoole_http_parse_form_data(http_context *ctx, const char *boundary_str, int boundary_len);
void swoole_http_parse_cookie(zval *array, const char *at, size_t length);
void swoole_http_server_init_context(swServer *serv, http_context *ctx);
size_t swoole_http_requset_parse(http_context *ctx, const char *data, size_t length);
bool swoole_http_response_set_header(http_context *ctx, const char *k, size_t klen, const char *v, size_t vlen, bool ucwords);
void swoole_http_response_end(http_context *ctx, zval *zdata, zval *return_value);
#ifdef SW_HAVE_ZLIB
int swoole_http_response_compress(swString *body, int method, int level);
void swoole_http_get_compression_method(http_context *ctx, const char *accept_encoding, size_t length);
const char* swoole_http_get_content_encoding(http_context *ctx);
static sw_inline voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
{
return (voidpf) safe_emalloc(items, size, 0);
}
static sw_inline void php_zlib_free(voidpf opaque, voidpf address)
{
efree((void *)address);
}
#endif
static int http_parse_set_cookies(const char *at, size_t length, zval *cookies, zval *zset_cookie_headers)
{
const char *key = at;
zval val;
size_t key_len = 0, val_len = 0;
const char *p, *eof = at + length;
// key
p = (char *) memchr(at, '=', length);
if (p)
{
key_len = p - at;
}
if (key_len == 0 || key_len >= length - 1)
{
swWarn("cookie key format is wrong");
return SW_ERR;
}
if (key_len > SW_HTTP_COOKIE_KEYLEN)
{
swWarn("cookie[%.8s...] name length %zu is exceed the max name len %d", key, key_len, SW_HTTP_COOKIE_KEYLEN);
return SW_ERR;
}
add_next_index_stringl(zset_cookie_headers, (char *) at, length);
// val
p++;
eof = (char*) memchr(p, ';', at + length - p);
if (!eof)
{
eof = at + length;
}
val_len = eof - p;
if (val_len > SW_HTTP_COOKIE_VALLEN)
{
swWarn("cookie[%.*s]'s value[v=%.8s...] length %d is exceed the max value len %d", (int) key_len, key, p, (int) val_len, SW_HTTP_COOKIE_VALLEN);
return SW_ERR;
}
ZVAL_STRINGL(&val, p, val_len);
Z_STRLEN(val) = php_url_decode(Z_STRVAL(val), val_len);
add_assoc_zval_ex(cookies, at, key_len, &val);
return SW_OK;
}
int swoole_websocket_onMessage(swServer *serv, swEventData *req);
int swoole_websocket_onHandshake(swServer *serv, swListenPort *port, http_context *ctx);
void swoole_websocket_onOpen(http_context *ctx);
void swoole_websocket_onRequest(http_context *ctx);
bool swoole_websocket_handshake(http_context *ctx);
#ifdef SW_USE_HTTP2
int swoole_http2_server_onFrame(swServer *serv, swConnection *conn, swEventData *req);
int swoole_http2_server_do_response(http_context *ctx, swString *body);
void swoole_http2_server_session_free(swConnection *conn);
void swoole_http2_response_end(http_context *ctx, zval *zdata, zval *return_value);
int swoole_http2_server_ping(http_context *ctx);
namespace swoole { namespace http2 {
//-----------------------------------namespace begin--------------------------------------------
class headers
{
public:
headers(size_t size) : size(size), index(0)
{
nvs = (nghttp2_nv *) ecalloc(size, sizeof(nghttp2_nv));
}
inline nghttp2_nv* get()
{
return nvs;
}
inline size_t len()
{
return index;
}
void reserve_one()
{
index++;
}
inline void add(
size_t index,
const char *name, size_t name_len,
const char *value, size_t value_len,
const uint8_t flags = NGHTTP2_NV_FLAG_NONE)
{
if (sw_likely(index < size || nvs[index].name == nullptr))
{
nghttp2_nv *nv = &nvs[index];
name = zend_str_tolower_dup(name, name_len); // auto to lower
nv->name = (uchar*) name;
nv->namelen = name_len;
nv->value = (uchar*) emalloc(value_len);
memcpy(nv->value, value, value_len);
nv->valuelen = value_len;
nv->flags = flags | NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE;
swTraceLog(SW_TRACE_HTTP2,"name=(%zu)[%.*s], value=(%zu)[%.*s]", name_len, (int) name_len, name, value_len, (int) value_len, value);
}
else
{
php_swoole_fatal_error(E_WARNING, "unexpect http2 header [%.*s] (duplicated or overflow)", (int) name_len, name);
}
}
inline void add(
const char *name, size_t name_len,
const char *value, size_t value_len,
const uint8_t flags = NGHTTP2_NV_FLAG_NONE
)
{
add(index++, name, name_len, value, value_len, flags);
}
~headers()
{
for (size_t i = 0; i < size; ++i)
{
if (sw_likely(nvs[i].name/* && nvs[i].value */))
{
efree((void *) nvs[i].name);
efree((void *) nvs[i].value);
}
}
efree(nvs);
}
private:
nghttp2_nv *nvs;
size_t size;
size_t index;
};
//-----------------------------------namespace end--------------------------------------------
}}
#endif