LCOV - code coverage report
Current view: top level - ext/http - php_http_message.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 917 1000 91.7 %
Date: 2015-02-17 20:30:22 Functions: 93 93 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11