test fixups from Remi
[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 zend_class_entry *php_http_message_class_entry;
516 zend_class_entry *php_http_message_get_class_entry(void)
517 {
518 return php_http_message_class_entry;
519 }
520
521 static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *rv);
522 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot);
523
524 static zend_object_handlers php_http_message_object_handlers;
525 static HashTable php_http_message_object_prophandlers;
526
527 static void php_http_message_object_prophandler_hash_dtor(zval *pData)
528 {
529 pefree(Z_PTR_P(pData), 1);
530 }
531
532 typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v);
533
534 typedef struct php_http_message_object_prophandler {
535 php_http_message_object_prophandler_func_t read;
536 php_http_message_object_prophandler_func_t write;
537 } php_http_message_object_prophandler_t;
538
539 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) {
540 php_http_message_object_prophandler_t h = { read, write };
541 if (!zend_hash_str_add_mem(&php_http_message_object_prophandlers, prop_str, prop_len, (void *) &h, sizeof(h))) {
542 return FAILURE;
543 }
544 return SUCCESS;
545 }
546 static php_http_message_object_prophandler_t *php_http_message_object_get_prophandler(zend_string *name_str) {
547 return zend_hash_str_find_ptr(&php_http_message_object_prophandlers, name_str->val, name_str->len);
548 }
549 static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value) {
550 RETVAL_LONG(obj->message->type);
551 }
552 static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value) {
553 php_http_message_set_type(obj->message, zval_get_long(value));
554 }
555 static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value) {
556 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
557 RETVAL_STRING(obj->message->http.info.request.method);
558 } else {
559 RETVAL_NULL();
560 }
561 }
562 static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value) {
563 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
564 zend_string *zs = zval_get_string(value);
565 PTR_SET(obj->message->http.info.request.method, estrndup(zs->val, zs->len));
566 zend_string_release(zs);
567 }
568 }
569 static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value) {
570 char *url_str;
571 size_t url_len;
572
573 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)) {
574 RETVAL_STR(php_http_cs2zs(url_str, url_len));
575 } else {
576 RETVAL_NULL();
577 }
578 }
579 static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value) {
580 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
581 PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, ~0));
582 }
583 }
584 static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value) {
585 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
586 RETVAL_STRING(obj->message->http.info.response.status);
587 } else {
588 RETVAL_NULL();
589 }
590 }
591 static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value) {
592 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
593 zend_string *zs = zval_get_string(value);
594 PTR_SET(obj->message->http.info.response.status, estrndup(zs->val, zs->len));
595 zend_string_release(zs);
596 }
597 }
598 static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value) {
599 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
600 RETVAL_LONG(obj->message->http.info.response.code);
601 } else {
602 RETVAL_NULL();
603 }
604 }
605 static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value) {
606 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
607 obj->message->http.info.response.code = zval_get_long(value);
608 PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code)));
609 }
610 }
611 static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value) {
612 char *version_str;
613 size_t version_len;
614
615 php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL);
616 RETVAL_STR(php_http_cs2zs(version_str, version_len));
617 }
618 static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value) {
619 zend_string *zs = zval_get_string(value);
620 php_http_version_parse(&obj->message->http.version, zs->val);
621 zend_string_release(zs);
622 }
623 static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value ) {
624 array_init(return_value);
625 array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
626 }
627 static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value) {
628 HashTable *headers;
629 zval *orig_value = value;
630
631 if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) {
632 convert_to_array_ex(value);
633 }
634 headers = HASH_OF(value);
635
636 zend_hash_clean(&obj->message->hdrs);
637 array_copy(headers, &obj->message->hdrs);
638
639 if (orig_value != value) {
640 zval_ptr_dtor(value);
641 }
642 }
643 static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value) {
644 if (obj->body) {
645 RETVAL_OBJECT(&obj->body->zo, 1);
646 } else {
647 RETVAL_NULL();
648 }
649 }
650 static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value) {
651 php_http_message_object_set_body(obj, value);
652 }
653 static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value) {
654 if (obj->message->parent) {
655 RETVAL_OBJECT(&obj->parent->zo, 1);
656 } else {
657 RETVAL_NULL();
658 }
659 }
660 static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value) {
661 if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry)) {
662 php_http_message_object_t *parent_obj = PHP_HTTP_OBJ(NULL, value);
663
664 if (obj->message->parent) {
665 zend_objects_store_del(&obj->parent->zo);
666 }
667 Z_ADDREF_P(value);
668 obj->parent = parent_obj;
669 obj->message->parent = parent_obj->message;
670 }
671 }
672
673 #define PHP_HTTP_MESSAGE_OBJECT_INIT(obj) \
674 do { \
675 if (!obj->message) { \
676 obj->message = php_http_message_init(NULL, 0, NULL); \
677 } \
678 } while(0)
679
680
681 void php_http_message_object_reverse(zval *zmsg, zval *return_value)
682 {
683 size_t i;
684 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, zmsg);
685
686 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
687
688 /* count */
689 i = php_http_message_count(obj->message);
690
691 if (i > 1) {
692 php_http_message_object_t **objects;
693 int last;
694
695 objects = ecalloc(i, sizeof(**objects));
696
697 /* we are the first message */
698 objects[0] = obj;
699
700 /* fetch parents */
701 for (i = 1; obj->parent; ++i) {
702 objects[i] = obj = obj->parent;
703 }
704
705 /* reorder parents */
706 for (last = --i; i; --i) {
707 objects[i]->message->parent = objects[i-1]->message;
708 objects[i]->parent = objects[i-1];
709 }
710
711 objects[0]->message->parent = NULL;
712 objects[0]->parent = NULL;
713
714 /* add ref, because we previously have not been a parent message */
715 Z_ADDREF_P(zmsg);
716 /* no addref, because we've been a parent message previously */
717 RETVAL_OBJECT(&objects[last]->zo, 0);
718
719 efree(objects);
720 } else {
721 RETURN_ZVAL(zmsg, 1, 0);
722 }
723 }
724
725 void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top)
726 {
727 php_http_message_t *save_parent_msg = NULL;
728 php_http_message_object_t *save_parent_obj = NULL, *obj = PHP_HTTP_OBJ(NULL, this_ptr);
729 php_http_message_object_t *prepend_obj = PHP_HTTP_OBJ(NULL, prepend);
730
731 if (!top) {
732 save_parent_obj = obj->parent;
733 save_parent_msg = obj->message->parent;
734 } else {
735 /* iterate to the most parent object */
736 while (obj->parent) {
737 obj = obj->parent;
738 }
739 }
740
741 /* prepend */
742 obj->parent = prepend_obj;
743 obj->message->parent = prepend_obj->message;
744
745 /* add ref */
746 Z_ADDREF_P(prepend);
747
748 if (!top) {
749 prepend_obj->parent = save_parent_obj;
750 prepend_obj->message->parent = save_parent_msg;
751 }
752 }
753
754 ZEND_RESULT_CODE php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval *zbody)
755 {
756 php_stream *s;
757 zend_string *body_str;
758 php_http_message_body_t *body;
759 php_http_message_body_object_t *body_obj;
760
761 switch (Z_TYPE_P(zbody)) {
762 case IS_RESOURCE:
763 php_stream_from_zval_no_verify(s, zbody);
764 if (!s) {
765 php_http_throw(unexpected_val, "The stream is not a valid resource", NULL);
766 return FAILURE;
767 }
768
769 is_resource:
770
771 body = php_http_message_body_init(NULL, s);
772 if (!(body_obj = php_http_message_body_object_new_ex(php_http_get_message_body_class_entry(), body))) {
773 php_http_message_body_free(&body);
774 return FAILURE;
775 }
776 break;
777
778 case IS_OBJECT:
779 if (instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) {
780 Z_ADDREF_P(zbody);
781 body_obj = PHP_HTTP_OBJ(NULL, zbody);
782 break;
783 }
784 /* no break */
785
786 default:
787 body_str = zval_get_string(zbody);
788 s = php_stream_temp_new();
789 php_stream_write(s, body_str->val, body_str->len);
790 zend_string_release(body_str);
791 goto is_resource;
792
793 }
794
795 if (!body_obj->body) {
796 body_obj->body = php_http_message_body_init(NULL, NULL);
797 }
798 if (msg_obj->body) {
799 zend_objects_store_del(&msg_obj->body->zo);
800 }
801 if (msg_obj->message) {
802 php_http_message_body_free(&msg_obj->message->body);
803 msg_obj->message->body = body_obj->body;
804 } else {
805 msg_obj->message = php_http_message_init(NULL, 0, body_obj->body);
806 }
807 php_http_message_body_addref(body_obj->body);
808 msg_obj->body = body_obj;
809
810 return SUCCESS;
811 }
812
813 ZEND_RESULT_CODE php_http_message_object_init_body_object(php_http_message_object_t *obj)
814 {
815 php_http_message_body_addref(obj->message->body);
816 return php_http_new((void *) &obj->body, php_http_get_message_body_class_entry(), (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body);
817 }
818
819 zend_object *php_http_message_object_new(zend_class_entry *ce)
820 {
821 return &php_http_message_object_new_ex(ce, NULL)->zo;
822 }
823
824 php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg)
825 {
826 php_http_message_object_t *o;
827
828 o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
829 zend_object_std_init(&o->zo, ce);
830 object_properties_init(&o->zo, ce);
831
832 if (msg) {
833 o->message = msg;
834 if (msg->parent) {
835 o->parent = php_http_message_object_new_ex(ce, msg->parent);
836 }
837 o->body = php_http_message_body_object_new_ex(php_http_get_message_body_class_entry(), php_http_message_body_init(&msg->body, NULL));
838 }
839
840 o->zo.handlers = &php_http_message_object_handlers;
841
842 return o;
843 }
844
845 zend_object *php_http_message_object_clone(zval *this_ptr)
846 {
847 php_http_message_object_t *new_obj = NULL;
848 php_http_message_object_t *old_obj = PHP_HTTP_OBJ(NULL, this_ptr);
849
850 new_obj = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL));
851 zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
852
853 return &new_obj->zo;
854 }
855
856 void php_http_message_object_free(zend_object *object)
857 {
858 php_http_message_object_t *o = PHP_HTTP_OBJ(object, NULL);
859
860 if (!Z_ISUNDEF(o->iterator)) {
861 zval_ptr_dtor(&o->iterator);
862 ZVAL_UNDEF(&o->iterator);
863 }
864 if (o->message) {
865 /* do NOT free recursivly */
866 php_http_message_dtor(o->message);
867 efree(o->message);
868 o->message = NULL;
869 }
870 if (o->parent) {
871 if (GC_REFCOUNT(&o->parent->zo) == 1) {
872 zend_objects_store_del(&o->parent->zo);
873 }
874 zend_objects_store_del(&o->parent->zo);
875 o->parent = NULL;
876 }
877 if (o->body) {
878 if (GC_REFCOUNT(&o->body->zo) == 1) {
879 zend_objects_store_del(&o->body->zo);
880 }
881 zend_objects_store_del(&o->body->zo);
882 o->body = NULL;
883 }
884 zend_object_std_dtor(object);
885 }
886
887 static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *tmp)
888 {
889 zval *return_value;
890 zend_string *member_name = zval_get_string(member);
891 php_http_message_object_prophandler_t *handler = php_http_message_object_get_prophandler(member_name);
892
893 if (!handler || type == BP_VAR_R || type == BP_VAR_IS) {
894 return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp);
895
896 if (handler) {
897 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
898
899 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
900 handler->read(obj, tmp);
901
902 zval_ptr_dtor(return_value);
903 ZVAL_COPY_VALUE(return_value, tmp);
904 }
905 zend_string_release(member_name);
906 return return_value;
907 } else {
908 php_property_proxy_t *proxy;
909 php_property_proxy_object_t *proxy_obj;
910
911 proxy = php_property_proxy_init(object, member_name);
912 proxy_obj = php_property_proxy_object_new_ex(NULL, proxy);
913
914 ZVAL_OBJ(tmp, &proxy_obj->zo);
915 zend_string_release(member_name);
916 return tmp;
917 }
918 }
919
920 static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot)
921 {
922 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
923 php_http_message_object_prophandler_t *handler;
924 zend_string *member_name = zval_get_string(member);
925
926 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
927
928 if ((handler = php_http_message_object_get_prophandler(member_name))) {
929 handler->write(obj, value);
930 } else {
931 zend_get_std_object_handlers()->write_property(object, member, value, cache_slot);
932 }
933
934 zend_string_release(member_name);
935 }
936
937 static HashTable *php_http_message_object_get_debug_info(zval *object, int *is_temp)
938 {
939 zval tmp;
940 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
941 HashTable *props = zend_get_std_object_handlers()->get_properties(object);
942 char *ver_str, *url_str = NULL;
943 size_t ver_len, url_len = 0;
944
945 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
946 *is_temp = 0;
947
948 #define UPDATE_PROP(name_str, action_with_tmp) \
949 do { \
950 zend_property_info *pi; \
951 if ((pi = zend_hash_str_find_ptr(&obj->zo.ce->properties_info, name_str, lenof(name_str)))) { \
952 action_with_tmp; \
953 zend_hash_update_ind(props, pi->name, &tmp); \
954 } \
955 } while(0)
956
957 UPDATE_PROP("type", ZVAL_LONG(&tmp, obj->message->type));
958
959 ver_len = spprintf(&ver_str, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor);
960 UPDATE_PROP("httpVersion", ZVAL_STR(&tmp, php_http_cs2zs(ver_str, ver_len)));
961
962 switch (obj->message->type) {
963 case PHP_HTTP_REQUEST:
964 UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0));
965 UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp));
966 UPDATE_PROP("requestMethod", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.request.method)));
967 if (obj->message->http.info.request.url) {
968 php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
969 UPDATE_PROP("requestUrl", ZVAL_STR(&tmp, php_http_cs2zs(url_str, url_len)));
970 } else {
971 UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
972 }
973
974 break;
975
976 case PHP_HTTP_RESPONSE:
977 UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, obj->message->http.info.response.code));
978 UPDATE_PROP("responseStatus", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.response.status)));
979 UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp));
980 UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
981 break;
982
983 case PHP_HTTP_NONE:
984 default:
985 UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0));
986 UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp));
987 UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp));
988 UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
989 break;
990 }
991
992 UPDATE_PROP("headers",
993 array_init(&tmp);
994 array_copy(&obj->message->hdrs, Z_ARRVAL(tmp));
995 );
996
997 UPDATE_PROP("body",
998 if (obj->body) {
999 ZVAL_OBJECT(&tmp, &obj->body->zo, 1);
1000 } else {
1001 ZVAL_NULL(&tmp);
1002 }
1003 );
1004
1005 UPDATE_PROP("parentMessage",
1006 if (obj->message->parent) {
1007 ZVAL_OBJECT(&tmp, &obj->parent->zo, 1);
1008 } else {
1009 ZVAL_NULL(&tmp);
1010 }
1011 );
1012
1013 return props;
1014 }
1015
1016 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___construct, 0, 0, 0)
1017 ZEND_ARG_INFO(0, message)
1018 ZEND_ARG_INFO(0, greedy)
1019 ZEND_END_ARG_INFO();
1020 static PHP_METHOD(HttpMessage, __construct)
1021 {
1022 zend_bool greedy = 1;
1023 zval *zmessage = NULL;
1024 php_http_message_t *msg = NULL;
1025 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1026 zend_error_handling zeh;
1027
1028 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!b", &zmessage, &greedy), invalid_arg, return);
1029
1030 zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_message_class_entry(), &zeh);
1031 if (zmessage && Z_TYPE_P(zmessage) == IS_RESOURCE) {
1032 php_stream *s;
1033 php_http_message_parser_t p;
1034 zend_error_handling zeh;
1035
1036 zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh);
1037 php_stream_from_zval(s, zmessage);
1038 zend_restore_error_handling(&zeh);
1039
1040 if (s && php_http_message_parser_init(&p)) {
1041 unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0);
1042 php_http_buffer_t buf;
1043
1044 php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC);
1045 if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, &buf, s, flags, &msg)) {
1046 if (!EG(exception)) {
1047 php_http_throw(bad_message, "Could not parse message from stream", NULL);
1048 }
1049 }
1050 php_http_buffer_dtor(&buf);
1051 php_http_message_parser_dtor(&p);
1052 }
1053
1054 if (!msg && !EG(exception)) {
1055 php_http_throw(bad_message, "Empty message received from stream", NULL);
1056 }
1057 } else if (zmessage) {
1058 zend_string *zs_msg = zval_get_string(zmessage);
1059
1060 msg = php_http_message_parse(NULL, zs_msg->val, zs_msg->len, greedy);
1061
1062 if (!msg && !EG(exception)) {
1063 php_http_throw(bad_message, "Could not parse message: %.*s", MIN(25, zs_msg->len), zs_msg->val);
1064 }
1065 zend_string_release(zs_msg);
1066 }
1067
1068 if (msg) {
1069 php_http_message_dtor(obj->message);
1070 obj->message = msg;
1071 if (obj->message->parent) {
1072 obj->parent = php_http_message_object_new_ex(obj->zo.ce, obj->message->parent);
1073 }
1074 }
1075 zend_restore_error_handling(&zeh);
1076 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1077 }
1078
1079 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getBody, 0, 0, 0)
1080 ZEND_END_ARG_INFO();
1081 static PHP_METHOD(HttpMessage, getBody)
1082 {
1083 php_http_message_object_t *obj;
1084
1085 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1086
1087 obj = PHP_HTTP_OBJ(NULL, getThis());
1088 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1089
1090 if (!obj->body) {
1091 php_http_message_object_init_body_object(obj);
1092
1093 }
1094 if (obj->body) {
1095 RETVAL_OBJECT(&obj->body->zo, 1);
1096 }
1097 }
1098
1099 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setBody, 0, 0, 1)
1100 ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0)
1101 ZEND_END_ARG_INFO();
1102 static PHP_METHOD(HttpMessage, setBody)
1103 {
1104 zval *zbody;
1105
1106 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zbody, php_http_get_message_body_class_entry())) {
1107 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1108
1109 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1110 php_http_message_object_prophandler_set_body(obj, zbody);
1111 }
1112 RETVAL_ZVAL(getThis(), 1, 0);
1113 }
1114
1115 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addBody, 0, 0, 1)
1116 ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0)
1117 ZEND_END_ARG_INFO();
1118 static PHP_METHOD(HttpMessage, addBody)
1119 {
1120 zval *new_body;
1121
1122 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &new_body, php_http_get_message_body_class_entry())) {
1123 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1124 php_http_message_body_object_t *new_obj = PHP_HTTP_OBJ(NULL, new_body);
1125
1126 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1127 php_http_message_body_to_callback(new_obj->body, (php_http_pass_callback_t) php_http_message_body_append, obj->message->body, 0, 0);
1128 }
1129 RETVAL_ZVAL(getThis(), 1, 0);
1130 }
1131
1132 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeader, 0, 0, 1)
1133 ZEND_ARG_INFO(0, header)
1134 ZEND_ARG_INFO(0, into_class)
1135 ZEND_END_ARG_INFO();
1136 static PHP_METHOD(HttpMessage, getHeader)
1137 {
1138 char *header_str;
1139 size_t header_len;
1140 zend_class_entry *header_ce = NULL;
1141
1142 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|C!", &header_str, &header_len, &header_ce)) {
1143 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1144 zval *header;
1145
1146 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1147
1148 if ((header = php_http_message_header(obj->message, header_str, header_len))) {
1149 if (!header_ce) {
1150 RETURN_ZVAL(header, 1, 0);
1151 } else if (instanceof_function(header_ce, php_http_header_get_class_entry())) {
1152 php_http_object_method_t cb;
1153 zval argv[2];
1154
1155 ZVAL_STRINGL(&argv[0], header_str, header_len);
1156 ZVAL_COPY(&argv[1], header);
1157
1158 object_init_ex(return_value, header_ce);
1159 php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct"));
1160 php_http_object_method_call(&cb, return_value, NULL, 2, argv);
1161 php_http_object_method_dtor(&cb);
1162
1163 zval_ptr_dtor(&argv[0]);
1164 zval_ptr_dtor(&argv[1]);
1165
1166 return;
1167 } else {
1168 php_error_docref(NULL, E_WARNING, "Class '%s' is not as descendant of http\\Header", header_ce->name->val);
1169 }
1170 }
1171 }
1172 RETURN_FALSE;
1173 }
1174
1175 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeaders, 0, 0, 0)
1176 ZEND_END_ARG_INFO();
1177 static PHP_METHOD(HttpMessage, getHeaders)
1178 {
1179 if (SUCCESS == zend_parse_parameters_none()) {
1180 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1181
1182 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1183
1184 array_init(return_value);
1185 array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
1186 }
1187 }
1188
1189 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeader, 0, 0, 1)
1190 ZEND_ARG_INFO(0, header)
1191 ZEND_ARG_INFO(0, value)
1192 ZEND_END_ARG_INFO();
1193 static PHP_METHOD(HttpMessage, setHeader)
1194 {
1195 zval *zvalue = NULL;
1196 char *name_str;
1197 size_t name_len;
1198
1199 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &name_str, &name_len, &zvalue)) {
1200 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1201 char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
1202
1203 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1204
1205 if (!zvalue) {
1206 zend_symtable_str_del(&obj->message->hdrs, name, name_len);
1207 } else {
1208 Z_TRY_ADDREF_P(zvalue);
1209 zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue);
1210 }
1211 efree(name);
1212 }
1213 RETVAL_ZVAL(getThis(), 1, 0);
1214 }
1215
1216 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeaders, 0, 0, 1)
1217 ZEND_ARG_ARRAY_INFO(0, headers, 1)
1218 ZEND_END_ARG_INFO();
1219 static PHP_METHOD(HttpMessage, setHeaders)
1220 {
1221 zval *new_headers = NULL;
1222
1223 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a/!", &new_headers)) {
1224 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1225
1226 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1227
1228 zend_hash_clean(&obj->message->hdrs);
1229 if (new_headers) {
1230 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY);
1231 }
1232 }
1233 RETVAL_ZVAL(getThis(), 1, 0);
1234 }
1235
1236 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeader, 0, 0, 2)
1237 ZEND_ARG_INFO(0, header)
1238 ZEND_ARG_INFO(0, value)
1239 ZEND_END_ARG_INFO();
1240 static PHP_METHOD(HttpMessage, addHeader)
1241 {
1242 zval *zvalue;
1243 char *name_str;
1244 size_t name_len;
1245
1246 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &name_str, &name_len, &zvalue)) {
1247 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1248 char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
1249 zval *header;
1250
1251 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1252
1253 Z_TRY_ADDREF_P(zvalue);
1254 if ((header = php_http_message_header(obj->message, name, name_len))) {
1255 convert_to_array(header);
1256 zend_hash_next_index_insert(Z_ARRVAL_P(header), zvalue);
1257 } else {
1258 zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue);
1259 }
1260 efree(name);
1261 }
1262 RETVAL_ZVAL(getThis(), 1, 0);
1263 }
1264
1265 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeaders, 0, 0, 1)
1266 ZEND_ARG_ARRAY_INFO(0, headers, 0)
1267 ZEND_ARG_INFO(0, append)
1268 ZEND_END_ARG_INFO();
1269 static PHP_METHOD(HttpMessage, addHeaders)
1270 {
1271 zval *new_headers;
1272 zend_bool append = 0;
1273
1274 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &new_headers, &append)) {
1275 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1276
1277 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1278
1279 array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
1280 }
1281 RETVAL_ZVAL(getThis(), 1, 0);
1282 }
1283
1284 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getType, 0, 0, 0)
1285 ZEND_END_ARG_INFO();
1286 static PHP_METHOD(HttpMessage, getType)
1287 {
1288 if (SUCCESS == zend_parse_parameters_none()) {
1289 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1290
1291 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1292
1293 RETURN_LONG(obj->message->type);
1294 }
1295 }
1296
1297 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setType, 0, 0, 1)
1298 ZEND_ARG_INFO(0, type)
1299 ZEND_END_ARG_INFO();
1300 static PHP_METHOD(HttpMessage, setType)
1301 {
1302 zend_long type;
1303
1304 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &type)) {
1305 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1306
1307 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1308
1309 php_http_message_set_type(obj->message, type);
1310 }
1311 RETVAL_ZVAL(getThis(), 1, 0);
1312 }
1313
1314 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getInfo, 0, 0, 0)
1315 ZEND_END_ARG_INFO();
1316 static PHP_METHOD(HttpMessage, getInfo)
1317 {
1318 if (SUCCESS == zend_parse_parameters_none()) {
1319 char *str, *tmp = NULL;
1320 size_t len;
1321 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1322
1323 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1324
1325 switch (obj->message->type) {
1326 case PHP_HTTP_REQUEST:
1327 len = spprintf(&str, 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, tmp, ""));
1328 PTR_FREE(tmp);
1329 break;
1330 case PHP_HTTP_RESPONSE:
1331 len = spprintf(&str, 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, tmp, ""));
1332 PTR_FREE(tmp);
1333 break;
1334 default:
1335 RETURN_NULL();
1336 break;
1337 }
1338
1339 RETVAL_STR(php_http_cs2zs(str, len));
1340 }
1341 }
1342
1343 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setInfo, 0, 0, 1)
1344 ZEND_ARG_INFO(0, http_info)
1345 ZEND_END_ARG_INFO();
1346 static PHP_METHOD(HttpMessage, setInfo)
1347 {
1348 char *str;
1349 size_t len;
1350 php_http_message_object_t *obj;
1351 php_http_info_t inf;
1352
1353 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len), invalid_arg, return);
1354
1355 obj = PHP_HTTP_OBJ(NULL, getThis());
1356 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1357
1358 if (!php_http_info_parse(&inf, str)) {
1359 php_http_throw(bad_header, "Could not parse message info '%s'", str);
1360 return;
1361 }
1362
1363 php_http_message_set_info(obj->message, &inf);
1364 php_http_info_dtor(&inf);
1365
1366 RETVAL_ZVAL(getThis(), 1, 0);
1367 }
1368
1369 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHttpVersion, 0, 0, 0)
1370 ZEND_END_ARG_INFO();
1371 static PHP_METHOD(HttpMessage, getHttpVersion)
1372 {
1373 if (SUCCESS == zend_parse_parameters_none()) {
1374 char *str;
1375 size_t len;
1376 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1377
1378 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1379
1380 php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL);
1381 RETURN_STR(php_http_cs2zs(str, len));
1382 }
1383 }
1384
1385 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHttpVersion, 0, 0, 1)
1386 ZEND_ARG_INFO(0, http_version)
1387 ZEND_END_ARG_INFO();
1388 static PHP_METHOD(HttpMessage, setHttpVersion)
1389 {
1390 char *v_str;
1391 size_t v_len;
1392 php_http_version_t version;
1393 php_http_message_object_t *obj;
1394
1395 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &v_str, &v_len), invalid_arg, return);
1396
1397 obj = PHP_HTTP_OBJ(NULL, getThis());
1398 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1399
1400 php_http_expect(php_http_version_parse(&version, v_str), unexpected_val, return);
1401
1402 obj->message->http.version = version;
1403
1404 RETVAL_ZVAL(getThis(), 1, 0);
1405 }
1406
1407 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseCode, 0, 0, 0)
1408 ZEND_END_ARG_INFO();
1409 static PHP_METHOD(HttpMessage, getResponseCode)
1410 {
1411 if (SUCCESS == zend_parse_parameters_none()) {
1412 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1413
1414 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1415
1416 if (obj->message->type != PHP_HTTP_RESPONSE) {
1417 php_error_docref(NULL, E_WARNING, "http\\Message is not if type response");
1418 RETURN_FALSE;
1419 }
1420
1421 RETURN_LONG(obj->message->http.info.response.code);
1422 }
1423 }
1424
1425 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseCode, 0, 0, 1)
1426 ZEND_ARG_INFO(0, response_code)
1427 ZEND_ARG_INFO(0, strict)
1428 ZEND_END_ARG_INFO();
1429 static PHP_METHOD(HttpMessage, setResponseCode)
1430 {
1431 zend_long code;
1432 zend_bool strict = 1;
1433 php_http_message_object_t *obj;
1434
1435 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &code, &strict), invalid_arg, return);
1436
1437 obj = PHP_HTTP_OBJ(NULL, getThis());
1438 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1439
1440 if (obj->message->type != PHP_HTTP_RESPONSE) {
1441 php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
1442 return;
1443 }
1444
1445 if (strict && (code < 100 || code > 599)) {
1446 php_http_throw(invalid_arg, "Invalid response code (100-599): %ld", code);
1447 return;
1448 }
1449
1450 obj->message->http.info.response.code = code;
1451 PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code)));
1452
1453 RETVAL_ZVAL(getThis(), 1, 0);
1454 }
1455
1456 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseStatus, 0, 0, 0)
1457 ZEND_END_ARG_INFO();
1458 static PHP_METHOD(HttpMessage, getResponseStatus)
1459 {
1460 if (SUCCESS == zend_parse_parameters_none()) {
1461 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1462
1463 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1464
1465 if (obj->message->type != PHP_HTTP_RESPONSE) {
1466 php_error_docref(NULL, E_WARNING, "http\\Message is not of type response");
1467 }
1468
1469 if (obj->message->http.info.response.status) {
1470 RETURN_STRING(obj->message->http.info.response.status);
1471 } else {
1472 RETURN_EMPTY_STRING();
1473 }
1474 }
1475 }
1476
1477 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseStatus, 0, 0, 1)
1478 ZEND_ARG_INFO(0, response_status)
1479 ZEND_END_ARG_INFO();
1480 static PHP_METHOD(HttpMessage, setResponseStatus)
1481 {
1482 char *status;
1483 size_t status_len;
1484 php_http_message_object_t *obj;
1485
1486 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &status, &status_len), invalid_arg, return);
1487
1488 obj = PHP_HTTP_OBJ(NULL, getThis());
1489
1490 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1491
1492 if (obj->message->type != PHP_HTTP_RESPONSE) {
1493 php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
1494 }
1495
1496 PTR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
1497 RETVAL_ZVAL(getThis(), 1, 0);
1498 }
1499
1500 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestMethod, 0, 0, 0)
1501 ZEND_END_ARG_INFO();
1502 static PHP_METHOD(HttpMessage, getRequestMethod)
1503 {
1504 if (SUCCESS == zend_parse_parameters_none()) {
1505 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1506
1507 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1508
1509 if (obj->message->type != PHP_HTTP_REQUEST) {
1510 php_error_docref(NULL, E_WARNING, "http\\Message is not of type request");
1511 RETURN_FALSE;
1512 }
1513
1514 if (obj->message->http.info.request.method) {
1515 RETURN_STRING(obj->message->http.info.request.method);
1516 } else {
1517 RETURN_EMPTY_STRING();
1518 }
1519 }
1520 }
1521
1522 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestMethod, 0, 0, 1)
1523 ZEND_ARG_INFO(0, request_method)
1524 ZEND_END_ARG_INFO();
1525 static PHP_METHOD(HttpMessage, setRequestMethod)
1526 {
1527 char *method;
1528 size_t method_len;
1529 php_http_message_object_t *obj;
1530
1531 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len), invalid_arg, return);
1532
1533 obj = PHP_HTTP_OBJ(NULL, getThis());
1534
1535 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1536
1537 if (obj->message->type != PHP_HTTP_REQUEST) {
1538 php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
1539 return;
1540 }
1541
1542 if (method_len < 1) {
1543 php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string", NULL);
1544 return;
1545 }
1546
1547 PTR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
1548 RETVAL_ZVAL(getThis(), 1, 0);
1549 }
1550
1551 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestUrl, 0, 0, 0)
1552 ZEND_END_ARG_INFO();
1553 static PHP_METHOD(HttpMessage, getRequestUrl)
1554 {
1555 if (SUCCESS == zend_parse_parameters_none()) {
1556 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1557
1558 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1559
1560 if (obj->message->type != PHP_HTTP_REQUEST) {
1561 php_error_docref(NULL, E_WARNING, "http\\Message is not of type request");
1562 RETURN_FALSE;
1563 }
1564
1565 if (obj->message->http.info.request.url) {
1566 char *url_str;
1567 size_t url_len;
1568
1569 php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
1570 RETURN_STR(php_http_cs2zs(url_str, url_len));
1571 } else {
1572 RETURN_EMPTY_STRING();
1573 }
1574 }
1575 }
1576
1577 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1)
1578 ZEND_ARG_INFO(0, url)
1579 ZEND_END_ARG_INFO();
1580 static PHP_METHOD(HttpMessage, setRequestUrl)
1581 {
1582 zval *zurl;
1583 php_http_url_t *url;
1584 php_http_message_object_t *obj;
1585 zend_error_handling zeh;
1586
1587 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zurl), invalid_arg, return);
1588
1589 obj = PHP_HTTP_OBJ(NULL, getThis());
1590
1591 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1592
1593 if (obj->message->type != PHP_HTTP_REQUEST) {
1594 php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
1595 return;
1596 }
1597
1598 zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
1599 url = php_http_url_from_zval(zurl, ~0);
1600 zend_restore_error_handling(&zeh);
1601
1602 if (url && php_http_url_is_empty(url)) {
1603 php_http_url_free(&url);
1604 php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL);
1605 } else if (url) {
1606 PTR_SET(obj->message->http.info.request.url, url);
1607 }
1608
1609 RETVAL_ZVAL(getThis(), 1, 0);
1610 }
1611
1612 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getParentMessage, 0, 0, 0)
1613 ZEND_END_ARG_INFO();
1614 static PHP_METHOD(HttpMessage, getParentMessage)
1615 {
1616 php_http_message_object_t *obj;
1617
1618 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1619
1620 obj = PHP_HTTP_OBJ(NULL, getThis());
1621 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1622
1623 if (!obj->message->parent) {
1624 php_http_throw(unexpected_val, "http\\Message has not parent message", NULL);
1625 return;
1626 }
1627
1628 RETVAL_OBJECT(&obj->parent->zo, 1);
1629 }
1630
1631 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___toString, 0, 0, 0)
1632 ZEND_END_ARG_INFO();
1633 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toString, 0, 0, 0)
1634 ZEND_ARG_INFO(0, include_parent)
1635 ZEND_END_ARG_INFO();
1636 static PHP_METHOD(HttpMessage, toString)
1637 {
1638 zend_bool include_parent = 0;
1639
1640 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &include_parent)) {
1641 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1642 char *string;
1643 size_t length;
1644
1645 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1646
1647 if (include_parent) {
1648 php_http_message_serialize(obj->message, &string, &length);
1649 } else {
1650 php_http_message_to_string(obj->message, &string, &length);
1651 }
1652 if (string) {
1653 RETURN_STR(php_http_cs2zs(string, length));
1654 }
1655 }
1656 RETURN_EMPTY_STRING();
1657 }
1658
1659 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toStream, 0, 0, 1)
1660 ZEND_ARG_INFO(0, stream)
1661 ZEND_END_ARG_INFO();
1662 static PHP_METHOD(HttpMessage, toStream)
1663 {
1664 zval *zstream;
1665
1666 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream)) {
1667 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1668 php_stream *s;
1669
1670 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1671
1672 php_stream_from_zval(s, zstream);
1673 php_http_message_to_callback(obj->message, (php_http_pass_callback_t) _php_stream_write, s);
1674 }
1675 }
1676
1677 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toCallback, 0, 0, 1)
1678 ZEND_ARG_INFO(0, callback)
1679 ZEND_END_ARG_INFO();
1680 static PHP_METHOD(HttpMessage, toCallback)
1681 {
1682 php_http_pass_fcall_arg_t fcd;
1683
1684 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fcd.fci, &fcd.fcc)) {
1685 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1686
1687 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1688
1689 ZVAL_COPY(&fcd.fcz, getThis());
1690 php_http_message_to_callback(obj->message, php_http_pass_fcall_callback, &fcd);
1691 zend_fcall_info_args_clear(&fcd.fci, 1);
1692 zval_ptr_dtor(&fcd.fcz);
1693
1694 RETURN_ZVAL(getThis(), 1, 0);
1695 }
1696 }
1697
1698 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_serialize, 0, 0, 0)
1699 ZEND_END_ARG_INFO();
1700 static PHP_METHOD(HttpMessage, serialize)
1701 {
1702 if (SUCCESS == zend_parse_parameters_none()) {
1703 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1704 char *string;
1705 size_t length;
1706
1707 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1708
1709 php_http_message_serialize(obj->message, &string, &length);
1710 RETURN_STR(php_http_cs2zs(string, length));
1711 }
1712 RETURN_EMPTY_STRING();
1713 }
1714
1715 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_unserialize, 0, 0, 1)
1716 ZEND_ARG_INFO(0, serialized)
1717 ZEND_END_ARG_INFO();
1718 static PHP_METHOD(HttpMessage, unserialize)
1719 {
1720 size_t length;
1721 char *serialized;
1722
1723 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized, &length)) {
1724 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1725 php_http_message_t *msg;
1726
1727 if (obj->message) {
1728 /* do not free recursively */
1729 php_http_message_dtor(obj->message);
1730 efree(obj->message);
1731 }
1732 if ((msg = php_http_message_parse(NULL, serialized, length, 1))) {
1733 obj->message = msg;
1734 } else {
1735 obj->message = php_http_message_init(NULL, 0, NULL);
1736 php_error_docref(NULL, E_ERROR, "Could not unserialize http\\Message");
1737 }
1738 }
1739 }
1740
1741 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_detach, 0, 0, 0)
1742 ZEND_END_ARG_INFO();
1743 static PHP_METHOD(HttpMessage, detach)
1744 {
1745 php_http_message_object_t *obj, *new_obj;
1746 php_http_message_t *msg_cpy;
1747
1748 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1749
1750 obj = PHP_HTTP_OBJ(NULL, getThis());
1751 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1752
1753 msg_cpy = php_http_message_copy_ex(obj->message, NULL, 0);
1754 new_obj = php_http_message_object_new_ex(obj->zo.ce, msg_cpy);
1755
1756 RETVAL_OBJ(&new_obj->zo);
1757 }
1758
1759 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_prepend, 0, 0, 1)
1760 ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0)
1761 ZEND_ARG_INFO(0, top)
1762 ZEND_END_ARG_INFO();
1763 static PHP_METHOD(HttpMessage, prepend)
1764 {
1765 zval *prepend;
1766 zend_bool top = 1;
1767 php_http_message_t *msg[2];
1768 php_http_message_object_t *obj, *prepend_obj;
1769
1770 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return);
1771
1772 obj = PHP_HTTP_OBJ(NULL, getThis());
1773 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1774 prepend_obj = PHP_HTTP_OBJ(NULL, prepend);
1775 PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj);
1776
1777 /* safety check */
1778 for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
1779 for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
1780 if (msg[0] == msg[1]) {
1781 php_http_throw(unexpected_val, "Cannot prepend a message located within the same message chain", NULL);
1782 return;
1783 }
1784 }
1785 }
1786
1787 php_http_message_object_prepend(getThis(), prepend, top);
1788 RETURN_ZVAL(getThis(), 1, 0);
1789 }
1790
1791 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_reverse, 0, 0, 0)
1792 ZEND_END_ARG_INFO();
1793 static PHP_METHOD(HttpMessage, reverse)
1794 {
1795 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1796
1797 php_http_message_object_reverse(getThis(), return_value);
1798 }
1799
1800 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_isMultipart, 0, 0, 0)
1801 ZEND_ARG_INFO(1, boundary)
1802 ZEND_END_ARG_INFO();
1803 static PHP_METHOD(HttpMessage, isMultipart)
1804 {
1805 zval *zboundary = NULL;
1806
1807 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zboundary)) {
1808 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1809 char *boundary = NULL;
1810
1811 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1812
1813 if (php_http_message_is_multipart(obj->message, zboundary ? &boundary : NULL)) {
1814 RETVAL_TRUE;
1815 } else {
1816 RETVAL_FALSE;
1817 }
1818
1819 if (zboundary && boundary) {
1820 ZVAL_DEREF(zboundary);
1821 zval_dtor(zboundary);
1822 ZVAL_STR(zboundary, php_http_cs2zs(boundary, strlen(boundary)));
1823 }
1824 }
1825 }
1826
1827 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_splitMultipartBody, 0, 0, 0)
1828 ZEND_END_ARG_INFO();
1829 static PHP_METHOD(HttpMessage, splitMultipartBody)
1830 {
1831 php_http_message_object_t *obj;
1832 php_http_message_t *msg;
1833 char *boundary = NULL;
1834
1835 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
1836
1837 obj = PHP_HTTP_OBJ(NULL, getThis());
1838 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1839
1840 if (!php_http_message_is_multipart(obj->message, &boundary)) {
1841 php_http_throw(bad_method_call, "http\\Message is not a multipart message", NULL);
1842 return;
1843 }
1844
1845 php_http_expect(msg = php_http_message_body_split(obj->message->body, boundary), bad_message, return);
1846
1847 PTR_FREE(boundary);
1848
1849 RETURN_OBJ(&php_http_message_object_new_ex(obj->zo.ce, msg)->zo);
1850 }
1851
1852 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_count, 0, 0, 0)
1853 ZEND_END_ARG_INFO();
1854 static PHP_METHOD(HttpMessage, count)
1855 {
1856 zend_long count_mode = -1;
1857
1858 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
1859 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1860
1861 PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
1862
1863 RETURN_LONG(php_http_message_count(obj->message));
1864 }
1865 }
1866
1867 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_rewind, 0, 0, 0)
1868 ZEND_END_ARG_INFO();
1869 static PHP_METHOD(HttpMessage, rewind)
1870 {
1871 if (SUCCESS == zend_parse_parameters_none()) {
1872 zval *zobj = getThis();
1873 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1874
1875 if (!Z_ISUNDEF(obj->iterator)) {
1876 zval_ptr_dtor(&obj->iterator);
1877 }
1878 ZVAL_COPY(&obj->iterator, zobj);
1879 }
1880 }
1881
1882 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_valid, 0, 0, 0)
1883 ZEND_END_ARG_INFO();
1884 static PHP_METHOD(HttpMessage, valid)
1885 {
1886 if (SUCCESS == zend_parse_parameters_none()) {
1887 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1888
1889 RETURN_BOOL(!Z_ISUNDEF(obj->iterator));
1890 }
1891 }
1892
1893 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_next, 0, 0, 0)
1894 ZEND_END_ARG_INFO();
1895 static PHP_METHOD(HttpMessage, next)
1896 {
1897 if (SUCCESS == zend_parse_parameters_none()) {
1898 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1899
1900 if (!Z_ISUNDEF(obj->iterator)) {
1901 php_http_message_object_t *itr = PHP_HTTP_OBJ(NULL, &obj->iterator);
1902
1903 if (itr->parent) {
1904 zval tmp;
1905
1906 ZVAL_OBJECT(&tmp, &itr->parent->zo, 1);
1907 zval_ptr_dtor(&obj->iterator);
1908 obj->iterator = tmp;
1909 } else {
1910 zval_ptr_dtor(&obj->iterator);
1911 ZVAL_UNDEF(&obj->iterator);
1912 }
1913 }
1914 }
1915 }
1916
1917 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_key, 0, 0, 0)
1918 ZEND_END_ARG_INFO();
1919 static PHP_METHOD(HttpMessage, key)
1920 {
1921 if (SUCCESS == zend_parse_parameters_none()) {
1922 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1923
1924 RETURN_LONG(Z_ISUNDEF(obj->iterator) ? 0 : Z_OBJ_HANDLE(obj->iterator));
1925 }
1926 }
1927
1928 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_current, 0, 0, 0)
1929 ZEND_END_ARG_INFO();
1930 static PHP_METHOD(HttpMessage, current)
1931 {
1932 if (SUCCESS == zend_parse_parameters_none()) {
1933 php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1934
1935 if (!Z_ISUNDEF(obj->iterator)) {
1936 RETURN_ZVAL(&obj->iterator, 1, 0);
1937 }
1938 }
1939 }
1940
1941 static zend_function_entry php_http_message_methods[] = {
1942 PHP_ME(HttpMessage, __construct, ai_HttpMessage___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1943 PHP_ME(HttpMessage, getBody, ai_HttpMessage_getBody, ZEND_ACC_PUBLIC)
1944 PHP_ME(HttpMessage, setBody, ai_HttpMessage_setBody, ZEND_ACC_PUBLIC)
1945 PHP_ME(HttpMessage, addBody, ai_HttpMessage_addBody, ZEND_ACC_PUBLIC)
1946 PHP_ME(HttpMessage, getHeader, ai_HttpMessage_getHeader, ZEND_ACC_PUBLIC)
1947 PHP_ME(HttpMessage, setHeader, ai_HttpMessage_setHeader, ZEND_ACC_PUBLIC)
1948 PHP_ME(HttpMessage, addHeader, ai_HttpMessage_addHeader, ZEND_ACC_PUBLIC)
1949 PHP_ME(HttpMessage, getHeaders, ai_HttpMessage_getHeaders, ZEND_ACC_PUBLIC)
1950 PHP_ME(HttpMessage, setHeaders, ai_HttpMessage_setHeaders, ZEND_ACC_PUBLIC)
1951 PHP_ME(HttpMessage, addHeaders, ai_HttpMessage_addHeaders, ZEND_ACC_PUBLIC)
1952 PHP_ME(HttpMessage, getType, ai_HttpMessage_getType, ZEND_ACC_PUBLIC)
1953 PHP_ME(HttpMessage, setType, ai_HttpMessage_setType, ZEND_ACC_PUBLIC)
1954 PHP_ME(HttpMessage, getInfo, ai_HttpMessage_getInfo, ZEND_ACC_PUBLIC)
1955 PHP_ME(HttpMessage, setInfo, ai_HttpMessage_setInfo, ZEND_ACC_PUBLIC)
1956 PHP_ME(HttpMessage, getResponseCode, ai_HttpMessage_getResponseCode, ZEND_ACC_PUBLIC)
1957 PHP_ME(HttpMessage, setResponseCode, ai_HttpMessage_setResponseCode, ZEND_ACC_PUBLIC)
1958 PHP_ME(HttpMessage, getResponseStatus, ai_HttpMessage_getResponseStatus, ZEND_ACC_PUBLIC)
1959 PHP_ME(HttpMessage, setResponseStatus, ai_HttpMessage_setResponseStatus, ZEND_ACC_PUBLIC)
1960 PHP_ME(HttpMessage, getRequestMethod, ai_HttpMessage_getRequestMethod, ZEND_ACC_PUBLIC)
1961 PHP_ME(HttpMessage, setRequestMethod, ai_HttpMessage_setRequestMethod, ZEND_ACC_PUBLIC)
1962 PHP_ME(HttpMessage, getRequestUrl, ai_HttpMessage_getRequestUrl, ZEND_ACC_PUBLIC)
1963 PHP_ME(HttpMessage, setRequestUrl, ai_HttpMessage_setRequestUrl, ZEND_ACC_PUBLIC)
1964 PHP_ME(HttpMessage, getHttpVersion, ai_HttpMessage_getHttpVersion, ZEND_ACC_PUBLIC)
1965 PHP_ME(HttpMessage, setHttpVersion, ai_HttpMessage_setHttpVersion, ZEND_ACC_PUBLIC)
1966 PHP_ME(HttpMessage, getParentMessage, ai_HttpMessage_getParentMessage, ZEND_ACC_PUBLIC)
1967 PHP_ME(HttpMessage, toString, ai_HttpMessage_toString, ZEND_ACC_PUBLIC)
1968 PHP_ME(HttpMessage, toCallback, ai_HttpMessage_toCallback, ZEND_ACC_PUBLIC)
1969 PHP_ME(HttpMessage, toStream, ai_HttpMessage_toStream, ZEND_ACC_PUBLIC)
1970
1971 /* implements Countable */
1972 PHP_ME(HttpMessage, count, ai_HttpMessage_count, ZEND_ACC_PUBLIC)
1973
1974 /* implements Serializable */
1975 PHP_ME(HttpMessage, serialize, ai_HttpMessage_serialize, ZEND_ACC_PUBLIC)
1976 PHP_ME(HttpMessage, unserialize, ai_HttpMessage_unserialize, ZEND_ACC_PUBLIC)
1977
1978 /* implements Iterator */
1979 PHP_ME(HttpMessage, rewind, ai_HttpMessage_rewind, ZEND_ACC_PUBLIC)
1980 PHP_ME(HttpMessage, valid, ai_HttpMessage_valid, ZEND_ACC_PUBLIC)
1981 PHP_ME(HttpMessage, current, ai_HttpMessage_current, ZEND_ACC_PUBLIC)
1982 PHP_ME(HttpMessage, key, ai_HttpMessage_key, ZEND_ACC_PUBLIC)
1983 PHP_ME(HttpMessage, next, ai_HttpMessage_next, ZEND_ACC_PUBLIC)
1984
1985 ZEND_MALIAS(HttpMessage, __toString, toString, ai_HttpMessage___toString, ZEND_ACC_PUBLIC)
1986
1987 PHP_ME(HttpMessage, detach, ai_HttpMessage_detach, ZEND_ACC_PUBLIC)
1988 PHP_ME(HttpMessage, prepend, ai_HttpMessage_prepend, ZEND_ACC_PUBLIC)
1989 PHP_ME(HttpMessage, reverse, ai_HttpMessage_reverse, ZEND_ACC_PUBLIC)
1990
1991 PHP_ME(HttpMessage, isMultipart, ai_HttpMessage_isMultipart, ZEND_ACC_PUBLIC)
1992 PHP_ME(HttpMessage, splitMultipartBody, ai_HttpMessage_splitMultipartBody, ZEND_ACC_PUBLIC)
1993
1994 EMPTY_FUNCTION_ENTRY
1995 };
1996
1997 PHP_MINIT_FUNCTION(http_message)
1998 {
1999 zend_class_entry ce = {0};
2000
2001 INIT_NS_CLASS_ENTRY(ce, "http", "Message", php_http_message_methods);
2002 php_http_message_class_entry = zend_register_internal_class(&ce);
2003 php_http_message_class_entry->create_object = php_http_message_object_new;
2004 memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2005 php_http_message_object_handlers.offset = XtOffsetOf(php_http_message_object_t, zo);
2006 php_http_message_object_handlers.clone_obj = php_http_message_object_clone;
2007 php_http_message_object_handlers.free_obj = php_http_message_object_free;
2008 php_http_message_object_handlers.read_property = php_http_message_object_read_prop;
2009 php_http_message_object_handlers.write_property = php_http_message_object_write_prop;
2010 php_http_message_object_handlers.get_debug_info = php_http_message_object_get_debug_info;
2011 php_http_message_object_handlers.get_property_ptr_ptr = NULL;
2012
2013 zend_class_implements(php_http_message_class_entry, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
2014
2015 zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, php_http_message_object_prophandler_hash_dtor, 1);
2016 zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED);
2017 php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type);
2018 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("body"), ZEND_ACC_PROTECTED);
2019 php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body);
2020 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED);
2021 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);
2022 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED);
2023 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);
2024 zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED);
2025 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);
2026 zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED);
2027 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);
2028 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED);
2029 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);
2030 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED);
2031 php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers);
2032 zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED);
2033 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);
2034
2035 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE);
2036 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST);
2037 zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE);
2038
2039 return SUCCESS;
2040 }
2041
2042 PHP_MSHUTDOWN_FUNCTION(http_message)
2043 {
2044 zend_hash_destroy(&php_http_message_object_prophandlers);
2045
2046 return SUCCESS;
2047 }
2048
2049 /*
2050 * Local variables:
2051 * tab-width: 4
2052 * c-basic-offset: 4
2053 * End:
2054 * vim600: noet sw=4 ts=4 fdm=marker
2055 * vim<600: noet sw=4 ts=4
2056 */