Fix gh-issue #16
[m6w6/ext-http] / src / php_http_message.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 static void message_headers(php_http_message_t *msg, php_http_buffer_t *str);
16
17 zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info)
18 {
19 php_http_message_t *old = *message;
20
21 /* advance message */
22 if (!old || old->type || zend_hash_num_elements(&old->hdrs)) {
23 (*message) = php_http_message_init(NULL, 0, NULL);
24 (*message)->parent = old;
25 if (headers) {
26 (*headers) = &((*message)->hdrs);
27 }
28 }
29
30 if (info) {
31 php_http_message_set_info(*message, info);
32 }
33
34 return old != *message;
35 }
36
37 php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type, php_http_message_body_t *body)
38 {
39 if (!message) {
40 message = emalloc(sizeof(*message));
41 }
42 memset(message, 0, sizeof(*message));
43
44 php_http_message_set_type(message, type);
45 message->http.version.major = 1;
46 message->http.version.minor = 1;
47 zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
48 message->body = body ? body : php_http_message_body_init(NULL, NULL);
49
50 return message;
51 }
52
53 php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type)
54 {
55 int free_msg = !message;
56 zval *sval, tval;
57 php_http_message_body_t *mbody;
58
59 switch (type) {
60 case PHP_HTTP_REQUEST:
61 mbody = php_http_env_get_request_body();
62 php_http_message_body_addref(mbody);
63 message = php_http_message_init(message, type, mbody);
64 if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) {
65 php_http_version_parse(&message->http.version, Z_STRVAL_P(sval));
66 }
67 if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1))) {
68 message->http.info.request.method = estrdup(Z_STRVAL_P(sval));
69 }
70 if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1))) {
71 message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), ~0);
72 }
73 php_http_env_get_request_headers(&message->hdrs);
74 break;
75
76 case PHP_HTTP_RESPONSE:
77 message = php_http_message_init(NULL, type, NULL);
78 if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line)) {
79 if (!(message->http.info.response.code = SG(sapi_headers).http_response_code)) {
80 message->http.info.response.code = 200;
81 }
82 message->http.info.response.status = estrdup(php_http_env_get_response_status_for_code(message->http.info.response.code));
83 }
84
85 php_http_env_get_response_headers(&message->hdrs);
86 if (php_output_get_level()) {
87 if (php_output_get_status() & PHP_OUTPUT_SENT) {
88 php_error_docref(NULL, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(), php_output_get_start_lineno());
89 goto error;
90 } else if (SUCCESS != php_output_get_contents(&tval)) {
91 php_error_docref(NULL, E_WARNING, "Could not fetch response body");
92 goto error;
93 } else {
94 php_http_message_body_append(message->body, Z_STRVAL(tval), Z_STRLEN(tval));
95 zval_dtor(&tval);
96 }
97 }
98 break;
99
100 default:
101 error:
102 if (free_msg) {
103 if (message) {
104 php_http_message_free(&message);
105 }
106 } else {
107 message = NULL;
108 }
109 break;
110 }
111
112 return message;
113 }
114
115 php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy)
116 {
117 php_http_message_parser_t p;
118 php_http_buffer_t buf;
119 unsigned flags = PHP_HTTP_MESSAGE_PARSER_CLEANUP;
120 int free_msg;
121
122 php_http_buffer_from_string_ex(&buf, str, len);
123 php_http_message_parser_init(&p);
124
125 if ((free_msg = !msg)) {
126 msg = php_http_message_init(NULL, 0, NULL);
127 }
128
129 if (greedy) {
130 flags |= PHP_HTTP_MESSAGE_PARSER_GREEDY;
131 }
132 if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(&p, &buf, flags, &msg)) {
133 if (free_msg) {
134 php_http_message_free(&msg);
135 }
136 msg = NULL;
137 }
138
139 php_http_message_parser_dtor(&p);
140 php_http_buffer_dtor(&buf);
141
142 return msg;
143 }
144
145 zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len)
146 {
147 zval *ret;
148 char *key;
149 ALLOCA_FLAG(free_key);
150
151 key = do_alloca(key_len + 1, free_key);
152
153 memcpy(key, key_str, key_len);
154 key[key_len] = '\0';
155 php_http_pretty_key(key, key_len, 1, 1);
156
157 ret = zend_symtable_str_find(&msg->hdrs, key, key_len);
158
159 free_alloca(key, free_key);
160
161 return ret;
162 }
163
164 zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary)
165 {
166 zend_string *ct = php_http_message_header_string(msg, ZEND_STRL("Content-Type"));
167 zend_bool is_multipart = 0;
168
169 if (ct) {
170 php_http_params_opts_t popts;
171 HashTable params;
172
173 ZEND_INIT_SYMTABLE(&params);
174 php_http_params_opts_default_get(&popts);
175 popts.input.str = ct->val;
176 popts.input.len = ct->len;
177
178 if (php_http_params_parse(&params, &popts)) {
179 zval *cur, *arg;
180 zend_string *ct_str;
181 zend_ulong index;
182
183 zend_hash_internal_pointer_reset(&params);
184
185 if ((cur = zend_hash_get_current_data(&params))
186 && (Z_TYPE_P(cur) == IS_ARRAY)
187 && (HASH_KEY_IS_STRING == zend_hash_get_current_key(&params, &ct_str, &index))
188 ) {
189 if (php_http_match(ct_str->val, "multipart", PHP_HTTP_MATCH_WORD)) {
190 is_multipart = 1;
191
192 /* get boundary */
193 if (boundary
194 && (arg = zend_hash_str_find(Z_ARRVAL_P(cur), ZEND_STRL("arguments")))
195 && Z_TYPE_P(arg) == IS_ARRAY
196 ) {
197 zval *val;
198 php_http_arrkey_t key;
199
200 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arg), key.h, key.key, val)
201 {
202 if (key.key && key.key->len == lenof("boundary") && !strcasecmp(key.key->val, "boundary")) {
203 zend_string *bnd = zval_get_string(val);
204
205 if (bnd->len) {
206 *boundary = estrndup(bnd->val, bnd->len);
207 }
208 zend_string_release(bnd);
209 }
210 }
211 ZEND_HASH_FOREACH_END();
212 }
213 }
214 }
215 }
216 zend_hash_destroy(&params);
217 zend_string_release(ct);
218 }
219
220 return is_multipart;
221 }
222
223 /* */
224 void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type)
225 {
226 /* just act if different */
227 if (type != message->type) {
228
229 /* free request info */
230 switch (message->type) {
231 case PHP_HTTP_REQUEST:
232 PTR_FREE(message->http.info.request.method);
233 PTR_FREE(message->http.info.request.url);
234 break;
235
236 case PHP_HTTP_RESPONSE:
237 PTR_FREE(message->http.info.response.status);
238 break;
239
240 default:
241 break;
242 }
243
244 message->type = type;
245 memset(&message->http, 0, sizeof(message->http));
246 }
247 }
248
249 void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info)
250 {
251 php_http_message_set_type(message, info->type);
252 message->http.version = info->http.version;
253 switch (message->type) {
254 case PHP_HTTP_REQUEST:
255 PTR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? php_http_url_copy(PHP_HTTP_INFO(info).request.url, 0) : NULL);
256 PTR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL);
257 break;
258
259 case PHP_HTTP_RESPONSE:
260 PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code;
261 PTR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL);
262 break;
263
264 default:
265 break;
266 }
267 }
268
269 void php_http_message_update_headers(php_http_message_t *msg)
270 {
271 zval h;
272 size_t size;
273 zend_string *cl;
274
275 if (php_http_message_body_stream(msg->body)->readfilters.head) {
276 /* if a read stream filter is attached to the body the caller must also care for the headers */
277 } else if (php_http_message_header(msg, ZEND_STRL("Content-Range"))) {
278 /* don't mess around with a Content-Range message */
279 } else if ((size = php_http_message_body_size(msg->body))) {
280 ZVAL_LONG(&h, size);
281 zend_hash_str_update(&msg->hdrs, "Content-Length", lenof("Content-Length"), &h);
282
283 if (msg->body->boundary) {
284 char *str;
285 size_t len;
286 zend_string *ct;
287
288 if (!(ct = php_http_message_header_string(msg, ZEND_STRL("Content-Type")))) {
289 len = spprintf(&str, 0, "multipart/form-data; boundary=\"%s\"", msg->body->boundary);
290 ZVAL_STR(&h, php_http_cs2zs(str, len));
291 zend_hash_str_update(&msg->hdrs, "Content-Type", lenof("Content-Type"), &h);
292 } else if (!php_http_match(ct->val, "boundary=", PHP_HTTP_MATCH_WORD)) {
293 len = spprintf(&str, 0, "%s; boundary=\"%s\"", ct->val, msg->body->boundary);
294 ZVAL_STR(&h, php_http_cs2zs(str, len));
295 zend_hash_str_update(&msg->hdrs, "Content-Type", lenof("Content-Type"), &h);
296 zend_string_release(ct);
297 } else {
298 zend_string_release(ct);
299 }
300 }
301 } else if ((cl = php_http_message_header_string(msg, ZEND_STRL("Content-Length")))) {
302 if (!zend_string_equals_literal(cl, "0")) {
303 /* body->size == 0, so get rid of old Content-Length */
304 zend_hash_str_del(&msg->hdrs, ZEND_STRL("Content-Length"));
305 }
306 zend_string_release(cl);
307 } else if (msg->type == PHP_HTTP_REQUEST) {
308 if (!php_http_message_header(msg, ZEND_STRL("Transfer-Encoding"))) {
309 /* no filter, no CR, no size, no TE, no CL */
310 if (0 <= php_http_select_str(msg->http.info.request.method, 3, "POST", "PUT", "PATCH")) {
311 /* quoting RFC7230#section-3.3.2
312 A user agent SHOULD send a Content-Length in a request message when
313 no Transfer-Encoding is sent and the request method defines a meaning
314 for an enclosed payload body. For example, a Content-Length header
315 field is normally sent in a POST request even when the value is 0
316 (indicating an empty payload body). A user agent SHOULD NOT send a
317 Content-Length header field when the request message does not contain
318 a payload body and the method semantics do not anticipate such a
319 body.
320 */
321 ZVAL_LONG(&h, 0);
322 zend_hash_str_update(&msg->hdrs, "Content-Length", lenof("Content-Length"), &h);
323 }
324 }
325 }
326 }
327
328 static void message_headers(php_http_message_t *msg, php_http_buffer_t *str)
329 {
330 char *tmp = NULL;
331
332 switch (msg->type) {
333 case PHP_HTTP_REQUEST:
334 php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF));
335 PTR_FREE(tmp);
336 break;
337
338 case PHP_HTTP_RESPONSE:
339 php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF));
340 PTR_FREE(tmp);
341 break;
342
343 default:
344 break;
345 }
346
347 php_http_message_update_headers(msg);
348 php_http_header_to_string(str, &msg->hdrs);
349 }
350
351 void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg)
352 {
353 php_http_buffer_t str;
354
355 php_http_buffer_init_ex(&str, 0x1000, 0);
356 message_headers(msg, &str);
357 cb(cb_arg, str.data, str.used);
358 php_http_buffer_dtor(&str);
359
360 if (php_http_message_body_size(msg->body)) {
361 cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF));
362 php_http_message_body_to_callback(msg->body, cb, cb_arg, 0, 0);
363 }
364 }
365
366 void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length)
367 {
368 php_http_buffer_t str;
369 char *data;
370
371 php_http_buffer_init_ex(&str, 0x1000, 0);
372 message_headers(msg, &str);
373 if (php_http_message_body_size(msg->body)) {
374 php_http_buffer_appends(&str, PHP_HTTP_CRLF);
375 php_http_message_body_to_callback(msg->body, (php_http_pass_callback_t) php_http_buffer_append, &str, 0, 0);
376 }
377
378 data = php_http_buffer_data(&str, string, length);
379 if (!string) {
380 efree(data);
381 }
382
383 php_http_buffer_dtor(&str);
384 }
385
386 void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length)
387 {
388 char *buf;
389 php_http_buffer_t str;
390 php_http_message_t *msg;
391
392 php_http_buffer_init(&str);
393
394 msg = message = php_http_message_reverse(message);
395 do {
396 php_http_message_to_callback(message, (php_http_pass_callback_t) php_http_buffer_append, &str);
397 php_http_buffer_appends(&str, PHP_HTTP_CRLF);
398 } while ((message = message->parent));
399 php_http_message_reverse(msg);
400
401 buf = php_http_buffer_data(&str, string, length);
402 if (!string) {
403 efree(buf);
404 }
405
406 php_http_buffer_dtor(&str);
407 }
408
409 php_http_message_t *php_http_message_reverse(php_http_message_t *msg)
410 {
411 size_t i, c = php_http_message_count(msg);
412
413 if (c > 1) {
414 php_http_message_t *tmp = msg, **arr;
415
416 arr = ecalloc(c, sizeof(**arr));
417 for (i = 0; i < c; ++i) {
418 arr[i] = tmp;
419 tmp = tmp->parent;
420 }
421 arr[0]->parent = NULL;
422 for (i = 0; i < c-1; ++i) {
423 arr[i+1]->parent = arr[i];
424 }
425
426 msg = arr[c-1];
427 efree(arr);
428 }
429
430 return msg;
431 }
432
433 php_http_message_t *php_http_message_zip(php_http_message_t *dst, php_http_message_t *src)
434 {
435 php_http_message_t *tmp_dst, *tmp_src, *ret = dst;
436
437 while (dst && src) {
438 tmp_dst = dst->parent;
439 tmp_src = src->parent;
440 dst->parent = src;
441 if (tmp_dst) {
442 src->parent = tmp_dst;
443 }
444 src = tmp_src;
445 dst = tmp_dst;
446 }
447
448 return ret;
449 }
450
451 php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents)
452 {
453 php_http_message_t *temp, *copy = NULL;
454 php_http_info_t info;
455
456 if (from) {
457 info.type = from->type;
458 info.http = from->http;
459
460 copy = temp = php_http_message_init(to, 0, php_http_message_body_copy(from->body, NULL));
461 php_http_message_set_info(temp, &info);
462 zend_hash_copy(&temp->hdrs, &from->hdrs, (copy_ctor_func_t) zval_add_ref);
463
464 if (parents) while (from->parent) {
465 info.type = from->parent->type;
466 info.http = from->parent->http;
467
468 temp->parent = php_http_message_init(NULL, 0, php_http_message_body_copy(from->parent->body, NULL));
469 php_http_message_set_info(temp->parent, &info);
470 array_copy(&from->parent->hdrs, &temp->parent->hdrs);
471
472
473 temp = temp->parent;
474 from = from->parent;
475 }
476 }
477
478 return copy;
479 }
480
481 void php_http_message_dtor(php_http_message_t *message)
482 {
483 if (message) {
484 zend_hash_destroy(&message->hdrs);
485 php_http_message_body_free(&message->body);
486
487 switch (message->type) {
488 case PHP_HTTP_REQUEST:
489 PTR_SET(message->http.info.request.method, NULL);
490 PTR_SET(message->http.info.request.url, NULL);
491 break;
492
493 case PHP_HTTP_RESPONSE:
494 PTR_SET(message->http.info.response.status, NULL);
495 break;
496
497 default:
498 break;
499 }
500 }
501 }
502
503 void php_http_message_free(php_http_message_t **message)
504 {
505 if (*message) {
506 if ((*message)->parent) {
507 php_http_message_free(&(*message)->parent);
508 }
509 php_http_message_dtor(*message);
510 efree(*message);
511 *message = NULL;
512 }
513 }
514
515 static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *rv);
516 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot);
517
518 static zend_object_handlers php_http_message_object_handlers;
519 static HashTable php_http_message_object_prophandlers;
520
521 static void php_http_message_object_prophandler_hash_dtor(zval *pData)
522 {
523 pefree(Z_PTR_P(pData), 1);
524 }
525
526 typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v);
527
528 typedef struct php_http_message_object_prophandler {
529 php_http_message_object_prophandler_func_t read;
530 php_http_message_object_prophandler_func_t write;
531 } php_http_message_object_prophandler_t;
532
533 static ZEND_RESULT_CODE php_http_message_object_add_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_func_t read, php_http_message_object_prophandler_func_t write) {
534 php_http_message_object_prophandler_t h = { read, write };
535 if (!zend_hash_str_add_mem(&php_http_message_object_prophandlers, prop_str, prop_len, (void *) &h, sizeof(h))) {
536 return FAILURE;
537 }
538 return SUCCESS;
539 }
540 static php_http_message_object_prophandler_t *php_http_message_object_get_prophandler(zend_string *name_str) {
541 return zend_hash_str_find_ptr(&php_http_message_object_prophandlers, name_str->val, name_str->len);
542 }
543 static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value) {
544 RETVAL_LONG(obj->message->type);
545 }
546 static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value) {
547 php_http_message_set_type(obj->message, zval_get_long(value));
548 }
549 static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value) {
550 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
551 RETVAL_STRING(obj->message->http.info.request.method);
552 } else {
553 RETVAL_NULL();
554 }
555 }
556 static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value) {
557 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
558 zend_string *zs = zval_get_string(value);
559 PTR_SET(obj->message->http.info.request.method, estrndup(zs->val, zs->len));
560 zend_string_release(zs);
561 }
562 }
563 static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value) {
564 char *url_str;
565 size_t url_len;
566
567 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url && php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0)) {
568 RETVAL_STR(php_http_cs2zs(url_str, url_len));
569 } else {
570 RETVAL_NULL();
571 }
572 }
573 static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value) {
574 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
575 PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, ~0));
576 }
577 }
578 static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value) {
579 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
580 RETVAL_STRING(obj->message->http.info.response.status);
581 } else {
582 RETVAL_NULL();
583 }
584 }
585 static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value) {
586 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
587 zend_string *zs = zval_get_string(value);
588 PTR_SET(obj->message->http.info.response.status, estrndup(zs->val, zs->len));
589 zend_string_release(zs);
590 }
591 }
592 static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value) {
593 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
594 RETVAL_LONG(obj->message->http.info.response.code);
595 } else {
596 RETVAL_NULL();
597 }
598 }
599 static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value) {
600 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
601 obj->message->http.info.response.code = zval_get_long(value);
602 PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code)));
603 }
604 }
605 static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value) {
606 char *version_str;
607 size_t version_len;
608
609 php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL);
610 RETVAL_STR(php_http_cs2zs(version_str, version_len));
611 }
612 static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value) {
613 zend_string *zs = zval_get_string(value);
614 php_http_version_parse(&obj->message->http.version, zs->val);
615 zend_string_release(zs);
616 }
617 static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value ) {
618 array_init(return_value);
619 array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
620 }
621 static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value) {
622 HashTable *headers;
623 zval *orig_value = value;
624
625 if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) {
626 convert_to_array_ex(value);
627 }
628 headers = HASH_OF(value);
629
630 zend_hash_clean(&obj->message->hdrs);
631 array_copy(headers, &obj->message->hdrs);
632
633 if (orig_value != value) {
634 zval_ptr_dtor(value);
635 }
636 }
637 static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value) {
638 if (obj->body) {
639 RETVAL_OBJECT(&obj->body->zo, 1);
640 } else {
641 RETVAL_NULL();
642 }
643 }
644 static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value) {
645 php_http_message_object_set_body(obj, value);
646 }
647 static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value) {
648 if (obj->message->parent) {
649 RETVAL_OBJECT(&obj->parent->zo, 1);
650 } else {
651 RETVAL_NULL();
652 }
653 }
654 static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value) {
655 if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry)) {
656 php_http_message_object_t *parent_obj = PHP_HTTP_OBJ(NULL, value);
657
658 if (obj->message->parent) {
659 zend_objects_store_del(&obj->parent->zo);
660 }
661 Z_ADDREF_P(value);
662 obj->parent = parent_obj;
663 obj->message->parent = parent_obj->message;
664 }
665 }
666
667 #define PHP_HTTP_MESSAGE_OBJECT_INIT(obj) \
668 do { \
669 if (!obj->message) { \
670 obj->message = php_http_message_init(NULL, 0, NULL); \
671 } \
672 } while(0)
673
674
675 void php_http_message_object_reverse(zval *zmsg, zval *return_value)
676 {
677 size_t i;
678 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, zmsg);
679
680 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
681
682 /* count */
683 i = php_http_message_count(obj->message);
684
685 if (i > 1) {
686 php_http_message_object_t **objects;
687 int last;
688
689 objects = ecalloc(i, sizeof(**objects));
690
691 /* we are the first message */
692 objects[0] = obj;
693
694 /* fetch parents */
695 for (i = 1; obj->parent; ++i) {
696 objects[i] = obj = obj->parent;
697 }
698
699 /* reorder parents */
700 for (last = --i; i; --i) {
701 objects[i]->message->parent = objects[i-1]->message;
702 objects[i]->parent = objects[i-1];
703 }
704
705 objects[0]->message->parent = NULL;
706 objects[0]->parent = NULL;
707
708 /* add ref, because we previously have not been a parent message */
709 Z_ADDREF_P(zmsg);
710 /* no addref, because we've been a parent message previously */
711 RETVAL_OBJECT(&objects[last]->zo, 0);
712
713 efree(objects);
714 } else {
715 RETURN_ZVAL(zmsg, 1, 0);
716 }
717 }
718
719 void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top)
720 {
721 php_http_message_t *save_parent_msg = NULL;
722 php_http_message_object_t *save_parent_obj = NULL, *obj = PHP_HTTP_OBJ(NULL, this_ptr);
723 php_http_message_object_t *prepend_obj = PHP_HTTP_OBJ(NULL, prepend);
724
725 if (!top) {
726 save_parent_obj = obj->parent;
727 save_parent_msg = obj->message->parent;
728 } else {
729 /* iterate to the most parent object */
730 while (obj->parent) {
731 obj = obj->parent;
732 }
733 }
734
735 /* prepend */
736 obj->parent = prepend_obj;
737 obj->message->parent = prepend_obj->message;
738
739 /* add ref */
740 Z_ADDREF_P(prepend);
741
742 if (!top) {
743 prepend_obj->parent = save_parent_obj;
744 prepend_obj->message->parent = save_parent_msg;
745 }
746 }
747
748 ZEND_RESULT_CODE php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval *zbody)
749 {
750 php_stream *s;
751 zend_string *body_str;
752 php_http_message_body_t *body;
753 php_http_message_body_object_t *body_obj;
754
755 switch (Z_TYPE_P(zbody)) {
756 case IS_RESOURCE:
757 php_stream_from_zval_no_verify(s, zbody);
758 if (!s) {
759 php_http_throw(unexpected_val, "The stream is not a valid resource", NULL);
760 return FAILURE;
761 }
762
763 is_resource:
764
765 body = php_http_message_body_init(NULL, s);
766 if (!(body_obj = php_http_message_body_object_new_ex(php_http_message_body_class_entry, body))) {
767 php_http_message_body_free(&body);
768 return FAILURE;
769 }
770 break;
771
772 case IS_OBJECT:
773 if (instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry)) {
774 Z_ADDREF_P(zbody);
775 body_obj = PHP_HTTP_OBJ(NULL, zbody);
776 break;
777 }
778 /* no break */
779
780 default:
781 body_str = zval_get_string(zbody);
782 s = php_stream_temp_new();
783 php_stream_write(s, body_str->val, body_str->len);
784 zend_string_release(body_str);
785 goto is_resource;
786
787 }
788
789 if (!body_obj->body) {
790 body_obj->body = php_http_message_body_init(NULL, NULL);
791 }
792 if (msg_obj->body) {
793 zend_objects_store_del(&msg_obj->body->zo);
794 }
795 if (msg_obj->message) {
796 php_http_message_body_free(&msg_obj->message->body);
797 msg_obj->message->body = body_obj->body;
798 } else {
799 msg_obj->message = php_http_message_init(NULL, 0, body_obj->body);
800 }
801 php_http_message_body_addref(body_obj->body);
802 msg_obj->body = body_obj;
803
804 return SUCCESS;
805 }
806
807 ZEND_RESULT_CODE php_http_message_object_init_body_object(php_http_message_object_t *obj)
808 {
809 php_http_message_body_addref(obj->message->body);
810 return php_http_new((void *) &obj->body, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body);
811 }
812
813 zend_object *php_http_message_object_new(zend_class_entry *ce)
814 {
815 return &php_http_message_object_new_ex(ce, NULL)->zo;
816 }
817
818 php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg)
819 {
820 php_http_message_object_t *o;
821
822 o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
823 zend_object_std_init(&o->zo, ce);
824 object_properties_init(&o->zo, ce);
825
826 if (msg) {
827 o->message = msg;
828 if (msg->parent) {
829 o->parent = php_http_message_object_new_ex(ce, msg->parent);
830 }
831 o->body = php_http_message_body_object_new_ex(php_http_message_body_class_entry, php_http_message_body_init(&msg->body, NULL));
832 }
833
834 o->zo.handlers = &php_http_message_object_handlers;
835
836 return o;
837 }
838
839 zend_object *php_http_message_object_clone(zval *this_ptr)
840 {
841 php_http_message_object_t *new_obj = NULL;
842 php_http_message_object_t *old_obj = PHP_HTTP_OBJ(NULL, this_ptr);
843
844 new_obj = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL));
845 zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
846
847 return &new_obj->zo;
848 }
849
850 void php_http_message_object_free(zend_object *object)
851 {
852 php_http_message_object_t *o = PHP_HTTP_OBJ(object, NULL);
853
854 if (!Z_ISUNDEF(o->iterator)) {
855 zval_ptr_dtor(&o->iterator);
856 ZVAL_UNDEF(&o->iterator);
857 }
858 if (o->message) {
859 /* do NOT free recursivly */
860 php_http_message_dtor(o->message);
861 efree(o->message);
862 o->message = NULL;
863 }
864 if (o->parent) {
865 if (GC_REFCOUNT(&o->parent->zo) == 1) {
866 zend_objects_store_del(&o->parent->zo);
867 }
868 zend_objects_store_del(&o->parent->zo);
869 o->parent = NULL;
870 }
871 if (o->body) {
872 if (GC_REFCOUNT(&o->body->zo) == 1) {
873 zend_objects_store_del(&o->body->zo);
874 }
875 zend_objects_store_del(&o->body->zo);
876 o->body = NULL;
877 }
878 zend_object_std_dtor(object);
879 }
880
881 static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *tmp)
882 {
883 zval *return_value;
884 zend_string *member_name = zval_get_string(member);
885 php_http_message_object_prophandler_t *handler = php_http_message_object_get_prophandler(member_name);
886
887 if (!handler || type == BP_VAR_R || type == BP_VAR_IS) {
888 return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp);
889
890 if (handler) {
891 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
892
893 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
894 handler->read(obj, tmp);
895
896 zval_ptr_dtor(return_value);
897 ZVAL_COPY_VALUE(return_value, tmp);
898 }
899 zend_string_release(member_name);
900 return return_value;
901 } else {
902 php_property_proxy_t *proxy;
903 php_property_proxy_object_t *proxy_obj;
904
905 proxy = php_property_proxy_init(object, member_name);
906 proxy_obj = php_property_proxy_object_new_ex(NULL, proxy);
907
908 ZVAL_OBJ(tmp, &proxy_obj->zo);
909 zend_string_release(member_name);
910 return tmp;
911 }
912 }
913
914 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot)
915 {
916 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
917 php_http_message_object_prophandler_t *handler;
918 zend_string *member_name = zval_get_string(member);
919
920 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
921
922 if ((handler = php_http_message_object_get_prophandler(member_name))) {
923 handler->write(obj, value);
924 } else {
925 zend_get_std_object_handlers()->write_property(object, member, value, cache_slot);
926 }
927
928 zend_string_release(member_name);
929 }
930
931 static HashTable *php_http_message_object_get_debug_info(zval *object, int *is_temp)
932 {
933 zval tmp;
934 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
935 HashTable *props = zend_get_std_object_handlers()->get_properties(object);
936 char *ver_str, *url_str = NULL;
937 size_t ver_len, url_len = 0;
938
939 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
940 *is_temp = 0;
941
942 #define UPDATE_PROP(name_str, action_with_tmp) \
943 do { \
944 zend_property_info *pi; \
945 if ((pi = zend_hash_str_find_ptr(&obj->zo.ce->properties_info, name_str, lenof(name_str)))) { \
946 action_with_tmp; \
947 zend_hash_update_ind(props, pi->name, &tmp); \
948 } \
949 } while(0)
950
951 UPDATE_PROP("type", ZVAL_LONG(&tmp, obj->message->type));
952
953 ver_len = spprintf(&ver_str, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor);
954 UPDATE_PROP("httpVersion", ZVAL_STR(&tmp, php_http_cs2zs(ver_str, ver_len)));
955
956 switch (obj->message->type) {
957 case PHP_HTTP_REQUEST:
958 UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0));
959 UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp));
960 UPDATE_PROP("requestMethod", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.request.method)));
961 if (obj->message->http.info.request.url) {
962 php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
963 UPDATE_PROP("requestUrl", ZVAL_STR(&tmp, php_http_cs2zs(url_str, url_len)));
964 } else {
965 UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
966 }
967
968 break;
969
970 case PHP_HTTP_RESPONSE:
971 UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, obj->message->http.info.response.code));
972 UPDATE_PROP("responseStatus", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.response.status)));
973 UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp));
974 UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
975 break;
976
977 case PHP_HTTP_NONE:
978 default:
979 UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0));
980 UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp));
981 UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp));
982 UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
983 break;
984 }
985
986 UPDATE_PROP("headers",
987 array_init(&tmp);
988 array_copy(&obj->message->hdrs, Z_ARRVAL(tmp));
989 );
990
991 UPDATE_PROP("body",
992 if (obj->body) {
993 ZVAL_OBJECT(&tmp, &obj->body->zo, 1);
994 } else {
995 ZVAL_NULL(&tmp);
996 }
997 );
998
999 UPDATE_PROP("parentMessage",
1000 if (obj->message->parent) {
1001 ZVAL_OBJECT(&tmp, &obj->parent->zo, 1);
1002 } else {
1003 ZVAL_NULL(&tmp);
1004 }
1005 );
1006
1007 return props;
1008 }
1009
1010 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___construct, 0, 0, 0)
1011 ZEND_ARG_INFO(0, message)
1012 ZEND_ARG_INFO(0, greedy)
1013 ZEND_END_ARG_INFO();
1014 static PHP_METHOD(HttpMessage, __construct)
1015 {
1016 zend_bool greedy = 1;
1017 zval *zmessage = NULL;
1018 php_http_message_t *msg = NULL;
1019 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1020 zend_error_handling zeh;
1021
1022 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!b", &zmessage, &greedy), invalid_arg, return);
1023
1024 zend_replace_error_handling(EH_THROW, php_http_exception_bad_message_class_entry, &zeh);
1025 if (zmessage && Z_TYPE_P(zmessage) == IS_RESOURCE) {
1026 php_stream *s;
1027 php_http_message_parser_t p;
1028 zend_error_handling zeh;
1029
1030 zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh);
1031 php_stream_from_zval(s, zmessage);
1032 zend_restore_error_handling(&zeh);
1033
1034 if (s && php_http_message_parser_init(&p)) {
1035 unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0);
1036 php_http_buffer_t buf;
1037
1038 php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC);
1039 if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, &buf, s, flags, &msg)) {
1040 if (!EG(exception)) {
1041 php_http_throw(bad_message, "Could not parse message from stream", NULL);
1042 }
1043 }
1044 php_http_buffer_dtor(&buf);
1045 php_http_message_parser_dtor(&p);
1046 }
1047
1048 if (!msg && !EG(exception)) {
1049 php_http_throw(bad_message, "Empty message received from stream", NULL);
1050 }
1051 } else if (zmessage) {
1052 zend_string *zs_msg = zval_get_string(zmessage);
1053
1054 msg = php_http_message_parse(NULL, zs_msg->val, zs_msg->len, greedy);
1055
1056 if (!msg && !EG(exception)) {
1057 php_http_throw(bad_message, "Could not parse message: %.*s", MIN(25, zs_msg->len), zs_msg->val);
1058 }
1059 zend_string_release(zs_msg);
1060 }
1061
1062 if (msg) {
1063 php_http_message_dtor(obj->message);
1064 obj->message = msg;
1065 if (obj->message->parent) {
1066 obj->parent = php_http_message_object_new_ex(obj->zo.ce, obj->message->parent);
1067 }
1068 }
1069 zend_restore_error_handling(&zeh);
1070 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1071 }
1072
1073 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getBody, 0, 0, 0)
1074 ZEND_END_ARG_INFO();
1075 static PHP_METHOD(HttpMessage, getBody)
1076 {
1077 php_http_message_object_t *obj;
1078
1079 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1080
1081 obj = PHP_HTTP_OBJ(NULL, getThis());
1082 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1083
1084 if (!obj->body) {
1085 php_http_message_object_init_body_object(obj);
1086
1087 }
1088 if (obj->body) {
1089 RETVAL_OBJECT(&obj->body->zo, 1);
1090 }
1091 }
1092
1093 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setBody, 0, 0, 1)
1094 ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0)
1095 ZEND_END_ARG_INFO();
1096 static PHP_METHOD(HttpMessage, setBody)
1097 {
1098 zval *zbody;
1099
1100 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zbody, php_http_message_body_class_entry)) {
1101 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1102
1103 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1104 php_http_message_object_prophandler_set_body(obj, zbody);
1105 }
1106 RETVAL_ZVAL(getThis(), 1, 0);
1107 }
1108
1109 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addBody, 0, 0, 1)
1110 ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0)
1111 ZEND_END_ARG_INFO();
1112 static PHP_METHOD(HttpMessage, addBody)
1113 {
1114 zval *new_body;
1115
1116 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &new_body, php_http_message_body_class_entry)) {
1117 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1118 php_http_message_body_object_t *new_obj = PHP_HTTP_OBJ(NULL, new_body);
1119
1120 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1121 php_http_message_body_to_callback(new_obj->body, (php_http_pass_callback_t) php_http_message_body_append, obj->message->body, 0, 0);
1122 }
1123 RETVAL_ZVAL(getThis(), 1, 0);
1124 }
1125
1126 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeader, 0, 0, 1)
1127 ZEND_ARG_INFO(0, header)
1128 ZEND_ARG_INFO(0, into_class)
1129 ZEND_END_ARG_INFO();
1130 static PHP_METHOD(HttpMessage, getHeader)
1131 {
1132 char *header_str;
1133 size_t header_len;
1134 zend_class_entry *header_ce = NULL;
1135
1136 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|C!", &header_str, &header_len, &header_ce)) {
1137 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1138 zval *header;
1139
1140 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1141
1142 if ((header = php_http_message_header(obj->message, header_str, header_len))) {
1143 if (!header_ce) {
1144 RETURN_ZVAL(header, 1, 0);
1145 } else if (instanceof_function(header_ce, php_http_header_class_entry)) {
1146 php_http_object_method_t cb;
1147 zval argv[2];
1148
1149 ZVAL_STRINGL(&argv[0], header_str, header_len);
1150 ZVAL_COPY(&argv[1], header);
1151
1152 object_init_ex(return_value, header_ce);
1153 php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct"));
1154 php_http_object_method_call(&cb, return_value, NULL, 2, argv);
1155 php_http_object_method_dtor(&cb);
1156
1157 zval_ptr_dtor(&argv[0]);
1158 zval_ptr_dtor(&argv[1]);
1159
1160 return;
1161 } else {
1162 php_error_docref(NULL, E_WARNING, "Class '%s' is not as descendant of http\\Header", header_ce->name->val);
1163 }
1164 }
1165 }
1166 RETURN_FALSE;
1167 }
1168
1169 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeaders, 0, 0, 0)
1170 ZEND_END_ARG_INFO();
1171 static PHP_METHOD(HttpMessage, getHeaders)
1172 {
1173 if (SUCCESS == zend_parse_parameters_none()) {
1174 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1175
1176 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1177
1178 array_init(return_value);
1179 array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
1180 }
1181 }
1182
1183 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeader, 0, 0, 1)
1184 ZEND_ARG_INFO(0, header)
1185 ZEND_ARG_INFO(0, value)
1186 ZEND_END_ARG_INFO();
1187 static PHP_METHOD(HttpMessage, setHeader)
1188 {
1189 zval *zvalue = NULL;
1190 char *name_str;
1191 size_t name_len;
1192
1193 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &name_str, &name_len, &zvalue)) {
1194 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1195 char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
1196
1197 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1198
1199 if (!zvalue) {
1200 zend_symtable_str_del(&obj->message->hdrs, name, name_len);
1201 } else {
1202 Z_TRY_ADDREF_P(zvalue);
1203 zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue);
1204 }
1205 efree(name);
1206 }
1207 RETVAL_ZVAL(getThis(), 1, 0);
1208 }
1209
1210 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeaders, 0, 0, 1)
1211 ZEND_ARG_ARRAY_INFO(0, headers, 1)
1212 ZEND_END_ARG_INFO();
1213 static PHP_METHOD(HttpMessage, setHeaders)
1214 {
1215 zval *new_headers = NULL;
1216
1217 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a/!", &new_headers)) {
1218 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1219
1220 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1221
1222 zend_hash_clean(&obj->message->hdrs);
1223 if (new_headers) {
1224 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY);
1225 }
1226 }
1227 RETVAL_ZVAL(getThis(), 1, 0);
1228 }
1229
1230 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeader, 0, 0, 2)
1231 ZEND_ARG_INFO(0, header)
1232 ZEND_ARG_INFO(0, value)
1233 ZEND_END_ARG_INFO();
1234 static PHP_METHOD(HttpMessage, addHeader)
1235 {
1236 zval *zvalue;
1237 char *name_str;
1238 size_t name_len;
1239
1240 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &name_str, &name_len, &zvalue)) {
1241 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1242 char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
1243 zval *header;
1244
1245 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1246
1247 Z_TRY_ADDREF_P(zvalue);
1248 if ((header = php_http_message_header(obj->message, name, name_len))) {
1249 convert_to_array(header);
1250 zend_hash_next_index_insert(Z_ARRVAL_P(header), zvalue);
1251 } else {
1252 zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue);
1253 }
1254 efree(name);
1255 }
1256 RETVAL_ZVAL(getThis(), 1, 0);
1257 }
1258
1259 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeaders, 0, 0, 1)
1260 ZEND_ARG_ARRAY_INFO(0, headers, 0)
1261 ZEND_ARG_INFO(0, append)
1262 ZEND_END_ARG_INFO();
1263 static PHP_METHOD(HttpMessage, addHeaders)
1264 {
1265 zval *new_headers;
1266 zend_bool append = 0;
1267
1268 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &new_headers, &append)) {
1269 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1270
1271 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1272
1273 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
1274 }
1275 RETVAL_ZVAL(getThis(), 1, 0);
1276 }
1277
1278 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getType, 0, 0, 0)
1279 ZEND_END_ARG_INFO();
1280 static PHP_METHOD(HttpMessage, getType)
1281 {
1282 if (SUCCESS == zend_parse_parameters_none()) {
1283 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1284
1285 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1286
1287 RETURN_LONG(obj->message->type);
1288 }
1289 }
1290
1291 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setType, 0, 0, 1)
1292 ZEND_ARG_INFO(0, type)
1293 ZEND_END_ARG_INFO();
1294 static PHP_METHOD(HttpMessage, setType)
1295 {
1296 zend_long type;
1297
1298 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &type)) {
1299 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1300
1301 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1302
1303 php_http_message_set_type(obj->message, type);
1304 }
1305 RETVAL_ZVAL(getThis(), 1, 0);
1306 }
1307
1308 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getInfo, 0, 0, 0)
1309 ZEND_END_ARG_INFO();
1310 static PHP_METHOD(HttpMessage, getInfo)
1311 {
1312 if (SUCCESS == zend_parse_parameters_none()) {
1313 char *str, *tmp = NULL;
1314 size_t len;
1315 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1316
1317 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1318
1319 switch (obj->message->type) {
1320 case PHP_HTTP_REQUEST:
1321 len = spprintf(&str, 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, tmp, ""));
1322 PTR_FREE(tmp);
1323 break;
1324 case PHP_HTTP_RESPONSE:
1325 len = spprintf(&str, 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, tmp, ""));
1326 PTR_FREE(tmp);
1327 break;
1328 default:
1329 RETURN_NULL();
1330 break;
1331 }
1332
1333 RETVAL_STR(php_http_cs2zs(str, len));
1334 }
1335 }
1336
1337 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setInfo, 0, 0, 1)
1338 ZEND_ARG_INFO(0, http_info)
1339 ZEND_END_ARG_INFO();
1340 static PHP_METHOD(HttpMessage, setInfo)
1341 {
1342 char *str;
1343 size_t len;
1344 php_http_message_object_t *obj;
1345 php_http_info_t inf;
1346
1347 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len), invalid_arg, return);
1348
1349 obj = PHP_HTTP_OBJ(NULL, getThis());
1350 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1351
1352 if (!php_http_info_parse(&inf, str)) {
1353 php_http_throw(bad_header, "Could not parse message info '%s'", str);
1354 return;
1355 }
1356
1357 php_http_message_set_info(obj->message, &inf);
1358 php_http_info_dtor(&inf);
1359
1360 RETVAL_ZVAL(getThis(), 1, 0);
1361 }
1362
1363 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHttpVersion, 0, 0, 0)
1364 ZEND_END_ARG_INFO();
1365 static PHP_METHOD(HttpMessage, getHttpVersion)
1366 {
1367 if (SUCCESS == zend_parse_parameters_none()) {
1368 char *str;
1369 size_t len;
1370 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1371
1372 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1373
1374 php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL);
1375 RETURN_STR(php_http_cs2zs(str, len));
1376 }
1377 }
1378
1379 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHttpVersion, 0, 0, 1)
1380 ZEND_ARG_INFO(0, http_version)
1381 ZEND_END_ARG_INFO();
1382 static PHP_METHOD(HttpMessage, setHttpVersion)
1383 {
1384 char *v_str;
1385 size_t v_len;
1386 php_http_version_t version;
1387 php_http_message_object_t *obj;
1388
1389 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &v_str, &v_len), invalid_arg, return);
1390
1391 obj = PHP_HTTP_OBJ(NULL, getThis());
1392 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1393
1394 php_http_expect(php_http_version_parse(&version, v_str), unexpected_val, return);
1395
1396 obj->message->http.version = version;
1397
1398 RETVAL_ZVAL(getThis(), 1, 0);
1399 }
1400
1401 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseCode, 0, 0, 0)
1402 ZEND_END_ARG_INFO();
1403 static PHP_METHOD(HttpMessage, getResponseCode)
1404 {
1405 if (SUCCESS == zend_parse_parameters_none()) {
1406 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1407
1408 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1409
1410 if (obj->message->type != PHP_HTTP_RESPONSE) {
1411 php_error_docref(NULL, E_WARNING, "http\\Message is not if type response");
1412 RETURN_FALSE;
1413 }
1414
1415 RETURN_LONG(obj->message->http.info.response.code);
1416 }
1417 }
1418
1419 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseCode, 0, 0, 1)
1420 ZEND_ARG_INFO(0, response_code)
1421 ZEND_ARG_INFO(0, strict)
1422 ZEND_END_ARG_INFO();
1423 static PHP_METHOD(HttpMessage, setResponseCode)
1424 {
1425 zend_long code;
1426 zend_bool strict = 1;
1427 php_http_message_object_t *obj;
1428
1429 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &code, &strict), invalid_arg, return);
1430
1431 obj = PHP_HTTP_OBJ(NULL, getThis());
1432 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1433
1434 if (obj->message->type != PHP_HTTP_RESPONSE) {
1435 php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
1436 return;
1437 }
1438
1439 if (strict && (code < 100 || code > 599)) {
1440 php_http_throw(invalid_arg, "Invalid response code (100-599): %ld", code);
1441 return;
1442 }
1443
1444 obj->message->http.info.response.code = code;
1445 PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code)));
1446
1447 RETVAL_ZVAL(getThis(), 1, 0);
1448 }
1449
1450 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseStatus, 0, 0, 0)
1451 ZEND_END_ARG_INFO();
1452 static PHP_METHOD(HttpMessage, getResponseStatus)
1453 {
1454 if (SUCCESS == zend_parse_parameters_none()) {
1455 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1456
1457 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1458
1459 if (obj->message->type != PHP_HTTP_RESPONSE) {
1460 php_error_docref(NULL, E_WARNING, "http\\Message is not of type response");
1461 }
1462
1463 if (obj->message->http.info.response.status) {
1464 RETURN_STRING(obj->message->http.info.response.status);
1465 } else {
1466 RETURN_EMPTY_STRING();
1467 }
1468 }
1469 }
1470
1471 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseStatus, 0, 0, 1)
1472 ZEND_ARG_INFO(0, response_status)
1473 ZEND_END_ARG_INFO();
1474 static PHP_METHOD(HttpMessage, setResponseStatus)
1475 {
1476 char *status;
1477 size_t status_len;
1478 php_http_message_object_t *obj;
1479
1480 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &status, &status_len), invalid_arg, return);
1481
1482 obj = PHP_HTTP_OBJ(NULL, getThis());
1483
1484 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1485
1486 if (obj->message->type != PHP_HTTP_RESPONSE) {
1487 php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
1488 }
1489
1490 PTR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
1491 RETVAL_ZVAL(getThis(), 1, 0);
1492 }
1493
1494 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestMethod, 0, 0, 0)
1495 ZEND_END_ARG_INFO();
1496 static PHP_METHOD(HttpMessage, getRequestMethod)
1497 {
1498 if (SUCCESS == zend_parse_parameters_none()) {
1499 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1500
1501 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1502
1503 if (obj->message->type != PHP_HTTP_REQUEST) {
1504 php_error_docref(NULL, E_WARNING, "http\\Message is not of type request");
1505 RETURN_FALSE;
1506 }
1507
1508 if (obj->message->http.info.request.method) {
1509 RETURN_STRING(obj->message->http.info.request.method);
1510 } else {
1511 RETURN_EMPTY_STRING();
1512 }
1513 }
1514 }
1515
1516 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestMethod, 0, 0, 1)
1517 ZEND_ARG_INFO(0, request_method)
1518 ZEND_END_ARG_INFO();
1519 static PHP_METHOD(HttpMessage, setRequestMethod)
1520 {
1521 char *method;
1522 size_t method_len;
1523 php_http_message_object_t *obj;
1524
1525 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len), invalid_arg, return);
1526
1527 obj = PHP_HTTP_OBJ(NULL, getThis());
1528
1529 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1530
1531 if (obj->message->type != PHP_HTTP_REQUEST) {
1532 php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
1533 return;
1534 }
1535
1536 if (method_len < 1) {
1537 php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string", NULL);
1538 return;
1539 }
1540
1541 PTR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
1542 RETVAL_ZVAL(getThis(), 1, 0);
1543 }
1544
1545 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestUrl, 0, 0, 0)
1546 ZEND_END_ARG_INFO();
1547 static PHP_METHOD(HttpMessage, getRequestUrl)
1548 {
1549 if (SUCCESS == zend_parse_parameters_none()) {
1550 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1551
1552 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1553
1554 if (obj->message->type != PHP_HTTP_REQUEST) {
1555 php_error_docref(NULL, E_WARNING, "http\\Message is not of type request");
1556 RETURN_FALSE;
1557 }
1558
1559 if (obj->message->http.info.request.url) {
1560 char *url_str;
1561 size_t url_len;
1562
1563 php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
1564 RETURN_STR(php_http_cs2zs(url_str, url_len));
1565 } else {
1566 RETURN_EMPTY_STRING();
1567 }
1568 }
1569 }
1570
1571 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1)
1572 ZEND_ARG_INFO(0, url)
1573 ZEND_END_ARG_INFO();
1574 static PHP_METHOD(HttpMessage, setRequestUrl)
1575 {
1576 zval *zurl;
1577 php_http_url_t *url;
1578 php_http_message_object_t *obj;
1579 zend_error_handling zeh;
1580
1581 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zurl), invalid_arg, return);
1582
1583 obj = PHP_HTTP_OBJ(NULL, getThis());
1584
1585 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1586
1587 if (obj->message->type != PHP_HTTP_REQUEST) {
1588 php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
1589 return;
1590 }
1591
1592 zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh);
1593 url = php_http_url_from_zval(zurl, ~0);
1594 zend_restore_error_handling(&zeh);
1595
1596 if (url && php_http_url_is_empty(url)) {
1597 php_http_url_free(&url);
1598 php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL);
1599 } else if (url) {
1600 PTR_SET(obj->message->http.info.request.url, url);
1601 }
1602
1603 RETVAL_ZVAL(getThis(), 1, 0);
1604 }
1605
1606 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getParentMessage, 0, 0, 0)
1607 ZEND_END_ARG_INFO();
1608 static PHP_METHOD(HttpMessage, getParentMessage)
1609 {
1610 php_http_message_object_t *obj;
1611
1612 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1613
1614 obj = PHP_HTTP_OBJ(NULL, getThis());
1615 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1616
1617 if (!obj->message->parent) {
1618 php_http_throw(unexpected_val, "http\\Message has not parent message", NULL);
1619 return;
1620 }
1621
1622 RETVAL_OBJECT(&obj->parent->zo, 1);
1623 }
1624
1625 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___toString, 0, 0, 0)
1626 ZEND_END_ARG_INFO();
1627 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toString, 0, 0, 0)
1628 ZEND_ARG_INFO(0, include_parent)
1629 ZEND_END_ARG_INFO();
1630 static PHP_METHOD(HttpMessage, toString)
1631 {
1632 zend_bool include_parent = 0;
1633
1634 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &include_parent)) {
1635 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1636 char *string;
1637 size_t length;
1638
1639 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1640
1641 if (include_parent) {
1642 php_http_message_serialize(obj->message, &string, &length);
1643 } else {
1644 php_http_message_to_string(obj->message, &string, &length);
1645 }
1646 if (string) {
1647 RETURN_STR(php_http_cs2zs(string, length));
1648 }
1649 }
1650 RETURN_EMPTY_STRING();
1651 }
1652
1653 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toStream, 0, 0, 1)
1654 ZEND_ARG_INFO(0, stream)
1655 ZEND_END_ARG_INFO();
1656 static PHP_METHOD(HttpMessage, toStream)
1657 {
1658 zval *zstream;
1659
1660 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream)) {
1661 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1662 php_stream *s;
1663
1664 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1665
1666 php_stream_from_zval(s, zstream);
1667 php_http_message_to_callback(obj->message, (php_http_pass_callback_t) _php_stream_write, s);
1668 }
1669 }
1670
1671 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toCallback, 0, 0, 1)
1672 ZEND_ARG_INFO(0, callback)
1673 ZEND_END_ARG_INFO();
1674 static PHP_METHOD(HttpMessage, toCallback)
1675 {
1676 php_http_pass_fcall_arg_t fcd;
1677
1678 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fcd.fci, &fcd.fcc)) {
1679 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1680
1681 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1682
1683 ZVAL_COPY(&fcd.fcz, getThis());
1684 php_http_message_to_callback(obj->message, php_http_pass_fcall_callback, &fcd);
1685 zend_fcall_info_args_clear(&fcd.fci, 1);
1686 zval_ptr_dtor(&fcd.fcz);
1687
1688 RETURN_ZVAL(getThis(), 1, 0);
1689 }
1690 }
1691
1692 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_serialize, 0, 0, 0)
1693 ZEND_END_ARG_INFO();
1694 static PHP_METHOD(HttpMessage, serialize)
1695 {
1696 if (SUCCESS == zend_parse_parameters_none()) {
1697 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1698 char *string;
1699 size_t length;
1700
1701 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1702
1703 php_http_message_serialize(obj->message, &string, &length);
1704 RETURN_STR(php_http_cs2zs(string, length));
1705 }
1706 RETURN_EMPTY_STRING();
1707 }
1708
1709 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_unserialize, 0, 0, 1)
1710 ZEND_ARG_INFO(0, serialized)
1711 ZEND_END_ARG_INFO();
1712 static PHP_METHOD(HttpMessage, unserialize)
1713 {
1714 size_t length;
1715 char *serialized;
1716
1717 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized, &length)) {
1718 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1719 php_http_message_t *msg;
1720
1721 if (obj->message) {
1722 /* do not free recursively */
1723 php_http_message_dtor(obj->message);
1724 efree(obj->message);
1725 }
1726 if ((msg = php_http_message_parse(NULL, serialized, length, 1))) {
1727 obj->message = msg;
1728 } else {
1729 obj->message = php_http_message_init(NULL, 0, NULL);
1730 php_error_docref(NULL, E_ERROR, "Could not unserialize http\\Message");
1731 }
1732 }
1733 }
1734
1735 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_detach, 0, 0, 0)
1736 ZEND_END_ARG_INFO();
1737 static PHP_METHOD(HttpMessage, detach)
1738 {
1739 php_http_message_object_t *obj, *new_obj;
1740 php_http_message_t *msg_cpy;
1741
1742 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1743
1744 obj = PHP_HTTP_OBJ(NULL, getThis());
1745 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1746
1747 msg_cpy = php_http_message_copy_ex(obj->message, NULL, 0);
1748 new_obj = php_http_message_object_new_ex(obj->zo.ce, msg_cpy);
1749
1750 RETVAL_OBJ(&new_obj->zo);
1751 }
1752
1753 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_prepend, 0, 0, 1)
1754 ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0)
1755 ZEND_ARG_INFO(0, top)
1756 ZEND_END_ARG_INFO();
1757 static PHP_METHOD(HttpMessage, prepend)
1758 {
1759 zval *prepend;
1760 zend_bool top = 1;
1761 php_http_message_t *msg[2];
1762 php_http_message_object_t *obj, *prepend_obj;
1763
1764 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return);
1765
1766 obj = PHP_HTTP_OBJ(NULL, getThis());
1767 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1768 prepend_obj = PHP_HTTP_OBJ(NULL, prepend);
1769 PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj);
1770
1771 /* safety check */
1772 for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
1773 for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
1774 if (msg[0] == msg[1]) {
1775 php_http_throw(unexpected_val, "Cannot prepend a message located within the same message chain", NULL);
1776 return;
1777 }
1778 }
1779 }
1780
1781 php_http_message_object_prepend(getThis(), prepend, top);
1782 RETURN_ZVAL(getThis(), 1, 0);
1783 }
1784
1785 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_reverse, 0, 0, 0)
1786 ZEND_END_ARG_INFO();
1787 static PHP_METHOD(HttpMessage, reverse)
1788 {
1789 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1790
1791 php_http_message_object_reverse(getThis(), return_value);
1792 }
1793
1794 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_isMultipart, 0, 0, 0)
1795 ZEND_ARG_INFO(1, boundary)
1796 ZEND_END_ARG_INFO();
1797 static PHP_METHOD(HttpMessage, isMultipart)
1798 {
1799 zval *zboundary = NULL;
1800
1801 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zboundary)) {
1802 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1803 char *boundary = NULL;
1804
1805 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1806
1807 if (php_http_message_is_multipart(obj->message, zboundary ? &boundary : NULL)) {
1808 RETVAL_TRUE;
1809 } else {
1810 RETVAL_FALSE;
1811 }
1812
1813 if (zboundary && boundary) {
1814 ZVAL_DEREF(zboundary);
1815 zval_dtor(zboundary);
1816 ZVAL_STR(zboundary, php_http_cs2zs(boundary, strlen(boundary)));
1817 }
1818 }
1819 }
1820
1821 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_splitMultipartBody, 0, 0, 0)
1822 ZEND_END_ARG_INFO();
1823 static PHP_METHOD(HttpMessage, splitMultipartBody)
1824 {
1825 php_http_message_object_t *obj;
1826 php_http_message_t *msg;
1827 char *boundary = NULL;
1828
1829 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1830
1831 obj = PHP_HTTP_OBJ(NULL, getThis());
1832 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1833
1834 if (!php_http_message_is_multipart(obj->message, &boundary)) {
1835 php_http_throw(bad_method_call, "http\\Message is not a multipart message", NULL);
1836 return;
1837 }
1838
1839 php_http_expect(msg = php_http_message_body_split(obj->message->body, boundary), bad_message, return);
1840
1841 PTR_FREE(boundary);
1842
1843 RETURN_OBJ(&php_http_message_object_new_ex(obj->zo.ce, msg)->zo);
1844 }
1845
1846 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_count, 0, 0, 0)
1847 ZEND_END_ARG_INFO();
1848 static PHP_METHOD(HttpMessage, count)
1849 {
1850 zend_long count_mode = -1;
1851
1852 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
1853 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1854
1855 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1856
1857 RETURN_LONG(php_http_message_count(obj->message));
1858 }
1859 }
1860
1861 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_rewind, 0, 0, 0)
1862 ZEND_END_ARG_INFO();
1863 static PHP_METHOD(HttpMessage, rewind)
1864 {
1865 if (SUCCESS == zend_parse_parameters_none()) {
1866 zval *zobj = getThis();
1867 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1868
1869 if (!Z_ISUNDEF(obj->iterator)) {
1870 zval_ptr_dtor(&obj->iterator);
1871 }
1872 ZVAL_COPY(&obj->iterator, zobj);
1873 }
1874 }
1875
1876 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_valid, 0, 0, 0)
1877 ZEND_END_ARG_INFO();
1878 static PHP_METHOD(HttpMessage, valid)
1879 {
1880 if (SUCCESS == zend_parse_parameters_none()) {
1881 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1882
1883 RETURN_BOOL(!Z_ISUNDEF(obj->iterator));
1884 }
1885 }
1886
1887 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_next, 0, 0, 0)
1888 ZEND_END_ARG_INFO();
1889 static PHP_METHOD(HttpMessage, next)
1890 {
1891 if (SUCCESS == zend_parse_parameters_none()) {
1892 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1893
1894 if (!Z_ISUNDEF(obj->iterator)) {
1895 php_http_message_object_t *itr = PHP_HTTP_OBJ(NULL, &obj->iterator);
1896
1897 if (itr->parent) {
1898 zval tmp;
1899
1900 ZVAL_OBJECT(&tmp, &itr->parent->zo, 1);
1901 zval_ptr_dtor(&obj->iterator);
1902 obj->iterator = tmp;
1903 } else {
1904 zval_ptr_dtor(&obj->iterator);
1905 ZVAL_UNDEF(&obj->iterator);
1906 }
1907 }
1908 }
1909 }
1910
1911 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_key, 0, 0, 0)
1912 ZEND_END_ARG_INFO();
1913 static PHP_METHOD(HttpMessage, key)
1914 {
1915 if (SUCCESS == zend_parse_parameters_none()) {
1916 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1917
1918 RETURN_LONG(Z_ISUNDEF(obj->iterator) ? 0 : Z_OBJ_HANDLE(obj->iterator));
1919 }
1920 }
1921
1922 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_current, 0, 0, 0)
1923 ZEND_END_ARG_INFO();
1924 static PHP_METHOD(HttpMessage, current)
1925 {
1926 if (SUCCESS == zend_parse_parameters_none()) {
1927 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1928
1929 if (!Z_ISUNDEF(obj->iterator)) {
1930 RETURN_ZVAL(&obj->iterator, 1, 0);
1931 }
1932 }
1933 }
1934
1935 static zend_function_entry php_http_message_methods[] = {
1936 PHP_ME(HttpMessage, __construct, ai_HttpMessage___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1937 PHP_ME(HttpMessage, getBody, ai_HttpMessage_getBody, ZEND_ACC_PUBLIC)
1938 PHP_ME(HttpMessage, setBody, ai_HttpMessage_setBody, ZEND_ACC_PUBLIC)
1939 PHP_ME(HttpMessage, addBody, ai_HttpMessage_addBody, ZEND_ACC_PUBLIC)
1940 PHP_ME(HttpMessage, getHeader, ai_HttpMessage_getHeader, ZEND_ACC_PUBLIC)
1941 PHP_ME(HttpMessage, setHeader, ai_HttpMessage_setHeader, ZEND_ACC_PUBLIC)
1942 PHP_ME(HttpMessage, addHeader, ai_HttpMessage_addHeader, ZEND_ACC_PUBLIC)
1943 PHP_ME(HttpMessage, getHeaders, ai_HttpMessage_getHeaders, ZEND_ACC_PUBLIC)
1944 PHP_ME(HttpMessage, setHeaders, ai_HttpMessage_setHeaders, ZEND_ACC_PUBLIC)
1945 PHP_ME(HttpMessage, addHeaders, ai_HttpMessage_addHeaders, ZEND_ACC_PUBLIC)
1946 PHP_ME(HttpMessage, getType, ai_HttpMessage_getType, ZEND_ACC_PUBLIC)
1947 PHP_ME(HttpMessage, setType, ai_HttpMessage_setType, ZEND_ACC_PUBLIC)
1948 PHP_ME(HttpMessage, getInfo, ai_HttpMessage_getInfo, ZEND_ACC_PUBLIC)
1949 PHP_ME(HttpMessage, setInfo, ai_HttpMessage_setInfo, ZEND_ACC_PUBLIC)
1950 PHP_ME(HttpMessage, getResponseCode, ai_HttpMessage_getResponseCode, ZEND_ACC_PUBLIC)
1951 PHP_ME(HttpMessage, setResponseCode, ai_HttpMessage_setResponseCode, ZEND_ACC_PUBLIC)
1952 PHP_ME(HttpMessage, getResponseStatus, ai_HttpMessage_getResponseStatus, ZEND_ACC_PUBLIC)
1953 PHP_ME(HttpMessage, setResponseStatus, ai_HttpMessage_setResponseStatus, ZEND_ACC_PUBLIC)
1954 PHP_ME(HttpMessage, getRequestMethod, ai_HttpMessage_getRequestMethod, ZEND_ACC_PUBLIC)
1955 PHP_ME(HttpMessage, setRequestMethod, ai_HttpMessage_setRequestMethod, ZEND_ACC_PUBLIC)
1956 PHP_ME(HttpMessage, getRequestUrl, ai_HttpMessage_getRequestUrl, ZEND_ACC_PUBLIC)
1957 PHP_ME(HttpMessage, setRequestUrl, ai_HttpMessage_setRequestUrl, ZEND_ACC_PUBLIC)
1958 PHP_ME(HttpMessage, getHttpVersion, ai_HttpMessage_getHttpVersion, ZEND_ACC_PUBLIC)
1959 PHP_ME(HttpMessage, setHttpVersion, ai_HttpMessage_setHttpVersion, ZEND_ACC_PUBLIC)
1960 PHP_ME(HttpMessage, getParentMessage, ai_HttpMessage_getParentMessage, ZEND_ACC_PUBLIC)
1961 PHP_ME(HttpMessage, toString, ai_HttpMessage_toString, ZEND_ACC_PUBLIC)
1962 PHP_ME(HttpMessage, toCallback, ai_HttpMessage_toCallback, ZEND_ACC_PUBLIC)
1963 PHP_ME(HttpMessage, toStream, ai_HttpMessage_toStream, ZEND_ACC_PUBLIC)
1964
1965 /* implements Countable */
1966 PHP_ME(HttpMessage, count, ai_HttpMessage_count, ZEND_ACC_PUBLIC)
1967
1968 /* implements Serializable */
1969 PHP_ME(HttpMessage, serialize, ai_HttpMessage_serialize, ZEND_ACC_PUBLIC)
1970 PHP_ME(HttpMessage, unserialize, ai_HttpMessage_unserialize, ZEND_ACC_PUBLIC)
1971
1972 /* implements Iterator */
1973 PHP_ME(HttpMessage, rewind, ai_HttpMessage_rewind, ZEND_ACC_PUBLIC)
1974 PHP_ME(HttpMessage, valid, ai_HttpMessage_valid, ZEND_ACC_PUBLIC)
1975 PHP_ME(HttpMessage, current, ai_HttpMessage_current, ZEND_ACC_PUBLIC)
1976 PHP_ME(HttpMessage, key, ai_HttpMessage_key, ZEND_ACC_PUBLIC)
1977 PHP_ME(HttpMessage, next, ai_HttpMessage_next, ZEND_ACC_PUBLIC)
1978
1979 ZEND_MALIAS(HttpMessage, __toString, toString, ai_HttpMessage___toString, ZEND_ACC_PUBLIC)
1980
1981 PHP_ME(HttpMessage, detach, ai_HttpMessage_detach, ZEND_ACC_PUBLIC)
1982 PHP_ME(HttpMessage, prepend, ai_HttpMessage_prepend, ZEND_ACC_PUBLIC)
1983 PHP_ME(HttpMessage, reverse, ai_HttpMessage_reverse, ZEND_ACC_PUBLIC)
1984
1985 PHP_ME(HttpMessage, isMultipart, ai_HttpMessage_isMultipart, ZEND_ACC_PUBLIC)
1986 PHP_ME(HttpMessage, splitMultipartBody, ai_HttpMessage_splitMultipartBody, ZEND_ACC_PUBLIC)
1987
1988 EMPTY_FUNCTION_ENTRY
1989 };
1990
1991 zend_class_entry *php_http_message_class_entry;
1992
1993 PHP_MINIT_FUNCTION(http_message)
1994 {
1995 zend_class_entry ce = {0};
1996
1997 INIT_NS_CLASS_ENTRY(ce, "http", "Message", php_http_message_methods);
1998 php_http_message_class_entry = zend_register_internal_class(&ce);
1999 php_http_message_class_entry->create_object = php_http_message_object_new;
2000 memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2001 php_http_message_object_handlers.offset = XtOffsetOf(php_http_message_object_t, zo);
2002 php_http_message_object_handlers.clone_obj = php_http_message_object_clone;
2003 php_http_message_object_handlers.free_obj = php_http_message_object_free;
2004 php_http_message_object_handlers.read_property = php_http_message_object_read_prop;
2005 php_http_message_object_handlers.write_property = php_http_message_object_write_prop;
2006 php_http_message_object_handlers.get_debug_info = php_http_message_object_get_debug_info;
2007 php_http_message_object_handlers.get_property_ptr_ptr = NULL;
2008
2009 zend_class_implements(php_http_message_class_entry, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
2010
2011 zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, php_http_message_object_prophandler_hash_dtor, 1);
2012 zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED);
2013 php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type);
2014 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("body"), ZEND_ACC_PROTECTED);
2015 php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body);
2016 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED);
2017 php_http_message_object_add_prophandler(ZEND_STRL("requestMethod"), php_http_message_object_prophandler_get_request_method, php_http_message_object_prophandler_set_request_method);
2018 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED);
2019 php_http_message_object_add_prophandler(ZEND_STRL("requestUrl"), php_http_message_object_prophandler_get_request_url, php_http_message_object_prophandler_set_request_url);
2020 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED);
2021 php_http_message_object_add_prophandler(ZEND_STRL("responseStatus"), php_http_message_object_prophandler_get_response_status, php_http_message_object_prophandler_set_response_status);
2022 zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED);
2023 php_http_message_object_add_prophandler(ZEND_STRL("responseCode"), php_http_message_object_prophandler_get_response_code, php_http_message_object_prophandler_set_response_code);
2024 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED);
2025 php_http_message_object_add_prophandler(ZEND_STRL("httpVersion"), php_http_message_object_prophandler_get_http_version, php_http_message_object_prophandler_set_http_version);
2026 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED);
2027 php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers);
2028 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED);
2029 php_http_message_object_add_prophandler(ZEND_STRL("parentMessage"), php_http_message_object_prophandler_get_parent_message, php_http_message_object_prophandler_set_parent_message);
2030
2031 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE);
2032 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST);
2033 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE);
2034
2035 return SUCCESS;
2036 }
2037
2038 PHP_MSHUTDOWN_FUNCTION(http_message)
2039 {
2040 zend_hash_destroy(&php_http_message_object_prophandlers);
2041
2042 return SUCCESS;
2043 }
2044
2045 /*
2046 * Local variables:
2047 * tab-width: 4
2048 * c-basic-offset: 4
2049 * End:
2050 * vim600: noet sw=4 ts=4 fdm=marker
2051 * vim<600: noet sw=4 ts=4
2052 */