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