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

Generated by: LCOV version 1.11