LCOV - code coverage report
Current view: top level - ext/http - php_http_header.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 160 173 92.5 %
Date: 2015-02-17 20:30:22 Functions: 12 12 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          32 : STATUS php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data TSRMLS_DC)
      16             : {
      17             :         php_http_header_parser_t ctx;
      18             :         php_http_buffer_t buf;
      19             :         php_http_header_parser_state_t rs;
      20             :         
      21          32 :         if (!php_http_buffer_from_string_ex(&buf, header, length)) {
      22           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not allocate buffer");
      23           0 :                 return FAILURE;
      24             :         }
      25             :         
      26          32 :         if (!php_http_header_parser_init(&ctx TSRMLS_CC)) {
      27           0 :                 php_http_buffer_dtor(&buf);
      28           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize header parser");
      29           0 :                 return FAILURE;
      30             :         }
      31             :         
      32          32 :         rs = php_http_header_parser_parse(&ctx, &buf, PHP_HTTP_HEADER_PARSER_CLEANUP, headers, callback_func, callback_data);
      33          32 :         php_http_header_parser_dtor(&ctx);
      34          32 :         php_http_buffer_dtor(&buf);
      35             : 
      36          32 :         return rs == PHP_HTTP_HEADER_PARSER_STATE_FAILURE ? FAILURE : SUCCESS;
      37             : }
      38             : 
      39         134 : void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC)
      40             : {
      41             :         HashPosition pos1, pos2;
      42         134 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
      43             :         zval **header, **single_header;
      44             : 
      45         423 :         FOREACH_HASH_KEYVAL(pos1, headers, key, header) {
      46         289 :                 if (key.type == HASH_KEY_IS_STRING) {
      47         290 :                         if (key.len == sizeof("Set-Cookie") && !strcasecmp(key.str, "Set-Cookie") && Z_TYPE_PP(header) == IS_ARRAY) {
      48           3 :                                 FOREACH_VAL(pos2, *header, single_header) {
      49           2 :                                         if (Z_TYPE_PP(single_header) == IS_ARRAY) {
      50           1 :                                                 php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, *single_header TSRMLS_CC);
      51             : 
      52           1 :                                                 if (cookie) {
      53             :                                                         char *buf;
      54             :                                                         size_t len;
      55             : 
      56           1 :                                                         php_http_cookie_list_to_string(cookie, &buf, &len);
      57           1 :                                                         cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", buf);
      58           1 :                                                         php_http_cookie_list_free(&cookie);
      59           1 :                                                         efree(buf);
      60             :                                                 }
      61             :                                         } else {
      62           1 :                                                 zval *strval = php_http_header_value_to_string(*single_header TSRMLS_CC);
      63             : 
      64           1 :                                                 cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", Z_STRVAL_P(strval));
      65           1 :                                                 zval_ptr_dtor(&strval);
      66             :                                         }
      67             :                                 }
      68             :                         } else {
      69         288 :                                 zval *strval = php_http_header_value_to_string(*header TSRMLS_CC);
      70             : 
      71         288 :                                 cb(cb_arg, crlf ? "%s: %s" PHP_HTTP_CRLF : "%s: %s", key.str, Z_STRVAL_P(strval));
      72         288 :                                 zval_ptr_dtor(&strval);
      73             :                         }
      74             :                 }
      75             :         }
      76         134 : }
      77             : 
      78         114 : void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers TSRMLS_DC)
      79             : {
      80         114 :         php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str TSRMLS_CC);
      81         114 : }
      82             : 
      83         304 : zval *php_http_header_value_to_string(zval *header TSRMLS_DC)
      84             : {
      85             :         zval *ret;
      86             : 
      87         304 :         if (Z_TYPE_P(header) == IS_BOOL) {
      88           1 :                 MAKE_STD_ZVAL(ret);
      89           1 :                 ZVAL_STRING(ret, Z_BVAL_P(header) ? "true" : "false", 1);
      90         303 :         } else if (Z_TYPE_P(header) == IS_ARRAY) {
      91             :                 zval **val;
      92             :                 HashPosition pos;
      93             :                 php_http_buffer_t str;
      94             : 
      95           5 :                 php_http_buffer_init(&str);
      96           5 :                 MAKE_STD_ZVAL(ret);
      97          20 :                 FOREACH_VAL(pos,header, val) {
      98          15 :                         zval *strval = php_http_header_value_to_string(*val TSRMLS_CC);
      99             : 
     100          15 :                         php_http_buffer_appendf(&str, str.used ? ", %s":"%s", Z_STRVAL_P(strval));
     101          15 :                         zval_ptr_dtor(&strval);
     102             :                 }
     103           5 :                 php_http_buffer_fix(&str);
     104           5 :                 ZVAL_STRINGL(ret, str.data, str.used, 0);
     105             :         } else  {
     106         298 :                 ret = php_http_zsep(1, IS_STRING, header);
     107             :         }
     108             : 
     109         304 :         return ret;
     110             : }
     111             : 
     112             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader___construct, 0, 0, 0)
     113             :         ZEND_ARG_INFO(0, name)
     114             :         ZEND_ARG_INFO(0, value)
     115             : ZEND_END_ARG_INFO();
     116          11 : PHP_METHOD(HttpHeader, __construct)
     117             : {
     118          11 :         char *name_str = NULL, *value_str = NULL;
     119          11 :         int name_len = 0, value_len = 0;
     120             : 
     121          22 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return);
     122             : 
     123          11 :         if (name_str && name_len) {
     124          10 :                 char *pretty_str = estrndup(name_str, name_len);
     125          10 :                 zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), php_http_pretty_key(pretty_str, name_len, 1, 1), name_len TSRMLS_CC);
     126          10 :                 efree(pretty_str);
     127             :         }
     128          11 :         if (value_str && value_len) {
     129          10 :                 zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("value"), value_str, value_len TSRMLS_CC);
     130             :         }
     131             : }
     132             : 
     133             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_serialize, 0, 0, 0)
     134             : ZEND_END_ARG_INFO();
     135           8 : PHP_METHOD(HttpHeader, serialize)
     136             : {
     137           8 :         if (SUCCESS == zend_parse_parameters_none()) {
     138             :                 php_http_buffer_t buf;
     139             :                 zval *zname, *zvalue;
     140             : 
     141           8 :                 php_http_buffer_init(&buf);
     142           8 :                 zname = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("name"), 0 TSRMLS_CC));
     143           8 :                 php_http_buffer_append(&buf, Z_STRVAL_P(zname), Z_STRLEN_P(zname));
     144           8 :                 zval_ptr_dtor(&zname);
     145           8 :                 zvalue = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0 TSRMLS_CC));
     146           8 :                 if (Z_STRLEN_P(zvalue)) {
     147           6 :                         php_http_buffer_appends(&buf, ": ");
     148           6 :                         php_http_buffer_append(&buf, Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue));
     149             :                 } else {
     150           2 :                         php_http_buffer_appends(&buf, ":");
     151             :                 }
     152           8 :                 zval_ptr_dtor(&zvalue);
     153             : 
     154           8 :                 RETURN_PHP_HTTP_BUFFER_VAL(&buf);
     155             :         }
     156           0 :         RETURN_EMPTY_STRING();
     157             : }
     158             : 
     159             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_unserialize, 0, 0, 1)
     160             :         ZEND_ARG_INFO(0, serialized)
     161             : ZEND_END_ARG_INFO();
     162           3 : PHP_METHOD(HttpHeader, unserialize)
     163             : {
     164             :         char *serialized_str;
     165             :         int serialized_len;
     166             : 
     167           3 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized_str, &serialized_len)) {
     168             :                 HashTable ht;
     169             : 
     170           3 :                 zend_hash_init(&ht, 1, NULL, ZVAL_PTR_DTOR, 0);
     171           3 :                 if (SUCCESS == php_http_header_parse(serialized_str, serialized_len, &ht, NULL, NULL TSRMLS_CC)) {
     172           3 :                         if (zend_hash_num_elements(&ht)) {
     173             :                                 zval **val, *cpy;
     174             :                                 char *str;
     175             :                                 uint len;
     176             :                                 ulong idx;
     177             : 
     178           2 :                                 zend_hash_internal_pointer_reset(&ht);
     179           2 :                                 switch (zend_hash_get_current_key_ex(&ht, &str, &len, &idx, 0, NULL)) {
     180             :                                         case HASH_KEY_IS_STRING:
     181           1 :                                                 zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), str, len - 1 TSRMLS_CC);
     182           1 :                                                 break;
     183             :                                         case HASH_KEY_IS_LONG:
     184           1 :                                                 zend_update_property_long(php_http_header_class_entry, getThis(), ZEND_STRL("name"), idx TSRMLS_CC);
     185           1 :                                                 break;
     186             :                                         default:
     187           0 :                                                 break;
     188             :                                 }
     189           2 :                                 zend_hash_get_current_data(&ht, (void *) &val);
     190           2 :                                 cpy = php_http_zsep(1, IS_STRING, *val);
     191           2 :                                 zend_update_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), cpy TSRMLS_CC);
     192           2 :                                 zval_ptr_dtor(&cpy);
     193             :                         }
     194             :                 }
     195           3 :                 zend_hash_destroy(&ht);
     196             :         }
     197             : 
     198           3 : }
     199             : 
     200             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_match, 0, 0, 1)
     201             :         ZEND_ARG_INFO(0, value)
     202             :         ZEND_ARG_INFO(0, flags)
     203             : ZEND_END_ARG_INFO();
     204           8 : PHP_METHOD(HttpHeader, match)
     205             : {
     206             :         char *val_str;
     207             :         int val_len;
     208           8 :         long flags = PHP_HTTP_MATCH_LOOSE;
     209             :         zval *zvalue;
     210             : 
     211           8 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &val_str, &val_len, &flags)) {
     212           8 :                 return;
     213             :         }
     214             : 
     215           8 :         zvalue = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0 TSRMLS_CC));
     216           8 :         RETVAL_BOOL(php_http_match(Z_STRVAL_P(zvalue), val_str, flags));
     217           8 :         zval_ptr_dtor(&zvalue);
     218             : }
     219             : 
     220             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_negotiate, 0, 0, 1)
     221             :         ZEND_ARG_INFO(0, supported)
     222             :         ZEND_ARG_INFO(1, result)
     223             : ZEND_END_ARG_INFO();
     224           4 : PHP_METHOD(HttpHeader, negotiate)
     225             : {
     226             :         HashTable *supported, *rs;
     227           4 :         zval *zname, *zvalue, *rs_array = NULL;
     228           4 :         char *sep_str = NULL;
     229           4 :         size_t sep_len = 0;
     230             : 
     231           4 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
     232           4 :                 return;
     233             :         }
     234           4 :         if (rs_array) {
     235           3 :                 zval_dtor(rs_array);
     236           3 :                 array_init(rs_array);
     237             :         }
     238             : 
     239           4 :         zname = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("name"), 0 TSRMLS_CC));
     240           4 :         if (!strcasecmp(Z_STRVAL_P(zname), "Accept")) {
     241           4 :                 sep_str = "/";
     242           4 :                 sep_len = 1;
     243           0 :         } else if (!strcasecmp(Z_STRVAL_P(zname), "Accept-Language")) {
     244           0 :                 sep_str = "-";
     245           0 :                 sep_len = 1;
     246             :         }
     247           4 :         zval_ptr_dtor(&zname);
     248             : 
     249           4 :         zvalue = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0 TSRMLS_CC));
     250           4 :         if ((rs = php_http_negotiate(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue), supported, sep_str, sep_len TSRMLS_CC))) {
     251           4 :                 PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
     252             :         } else {
     253           0 :                 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
     254             :         }
     255           4 :         zval_ptr_dtor(&zvalue);
     256             : }
     257             : 
     258             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_getParams, 0, 0, 0)
     259             :         ZEND_ARG_INFO(0, param_sep)
     260             :         ZEND_ARG_INFO(0, arg_sep)
     261             :         ZEND_ARG_INFO(0, val_sep)
     262             :         ZEND_ARG_INFO(0, flags)
     263             : ZEND_END_ARG_INFO();
     264           2 : PHP_METHOD(HttpHeader, getParams)
     265             : {
     266           2 :         zval zctor, *zparams_obj, **zargs = NULL;
     267             :         
     268           2 :         INIT_PZVAL(&zctor);
     269           2 :         ZVAL_STRINGL(&zctor, "__construct", lenof("__construct"), 0);
     270             :         
     271           2 :         MAKE_STD_ZVAL(zparams_obj);
     272           2 :         object_init_ex(zparams_obj, php_http_params_class_entry);
     273             :         
     274           2 :         zargs = (zval **) ecalloc(ZEND_NUM_ARGS()+1, sizeof(zval *));
     275           2 :         zargs[0] = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("value"), 0 TSRMLS_CC);
     276           2 :         if (ZEND_NUM_ARGS()) {
     277           1 :                 zend_get_parameters_array(ZEND_NUM_ARGS(), ZEND_NUM_ARGS(), &zargs[1]);
     278             :         }
     279             :         
     280           2 :         if (SUCCESS == call_user_function(NULL, &zparams_obj, &zctor, return_value, ZEND_NUM_ARGS()+1, zargs TSRMLS_CC)) {
     281           2 :                 RETVAL_ZVAL(zparams_obj, 0, 1);
     282             :         }
     283             :         
     284           2 :         if (zargs) {
     285           2 :                 efree(zargs);
     286             :         }
     287           2 : }
     288             : 
     289             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_parse, 0, 0, 1)
     290             :         ZEND_ARG_INFO(0, string)
     291             :         ZEND_ARG_INFO(0, header_class)
     292             : ZEND_END_ARG_INFO();
     293           3 : PHP_METHOD(HttpHeader, parse)
     294             : {
     295             :         char *header_str;
     296             :         int header_len;
     297           3 :         zend_class_entry *ce = NULL;
     298             : 
     299           3 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C", &header_str, &header_len, &ce)) {
     300           3 :                 array_init(return_value);
     301             : 
     302           3 :                 if (SUCCESS != php_http_header_parse(header_str, header_len, Z_ARRVAL_P(return_value), NULL, NULL TSRMLS_CC)) {
     303           1 :                         zval_dtor(return_value);
     304           4 :                         RETURN_FALSE;
     305             :                 } else {
     306           2 :                         if (ce && instanceof_function(ce, php_http_header_class_entry TSRMLS_CC)) {
     307             :                                 HashPosition pos;
     308           1 :                                 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
     309             :                                 zval **val;
     310             : 
     311           3 :                                 FOREACH_KEYVAL(pos, return_value, key, val) {
     312             :                                         zval *zho, *zkey, *zvalue;
     313             : 
     314           2 :                                         Z_ADDREF_PP(val);
     315           2 :                                         zvalue = *val;
     316             : 
     317           2 :                                         MAKE_STD_ZVAL(zkey);
     318           2 :                                         if (key.type == HASH_KEY_IS_LONG) {
     319           0 :                                                 ZVAL_LONG(zkey, key.num);
     320             :                                         } else {
     321           2 :                                                 ZVAL_STRINGL(zkey, key.str, key.len - 1, 1);
     322             :                                         }
     323             : 
     324           2 :                                         MAKE_STD_ZVAL(zho);
     325           2 :                                         object_init_ex(zho, ce);
     326           2 :                                         zend_call_method_with_2_params(&zho, ce, NULL, "__construct", NULL, zkey, zvalue);
     327             : 
     328           2 :                                         if (key.type == HASH_KEY_IS_LONG) {
     329           0 :                                                 zend_hash_index_update(Z_ARRVAL_P(return_value), key.num, (void *) &zho, sizeof(zval *), NULL);
     330             :                                         } else {
     331           2 :                                                 zend_hash_update(Z_ARRVAL_P(return_value), key.str, key.len, (void *) &zho, sizeof(zval *), NULL);
     332             :                                         }
     333             : 
     334           2 :                                         zval_ptr_dtor(&zvalue);
     335           2 :                                         zval_ptr_dtor(&zkey);
     336             :                                 }
     337             :                         }
     338             :                 }
     339             :         }
     340             : }
     341             : 
     342             : static zend_function_entry php_http_header_methods[] = {
     343             :         PHP_ME(HttpHeader, __construct,   ai_HttpHeader___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
     344             :         PHP_ME(HttpHeader, serialize,     ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
     345             :         ZEND_MALIAS(HttpHeader, __toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
     346             :         ZEND_MALIAS(HttpHeader, toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
     347             :         PHP_ME(HttpHeader, unserialize,   ai_HttpHeader_unserialize, ZEND_ACC_PUBLIC)
     348             :         PHP_ME(HttpHeader, match,         ai_HttpHeader_match, ZEND_ACC_PUBLIC)
     349             :         PHP_ME(HttpHeader, negotiate,     ai_HttpHeader_negotiate, ZEND_ACC_PUBLIC)
     350             :         PHP_ME(HttpHeader, getParams,     ai_HttpHeader_getParams, ZEND_ACC_PUBLIC)
     351             :         PHP_ME(HttpHeader, parse,         ai_HttpHeader_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     352             :         EMPTY_FUNCTION_ENTRY
     353             : };
     354             : 
     355             : zend_class_entry *php_http_header_class_entry;
     356             : 
     357         374 : PHP_MINIT_FUNCTION(http_header)
     358             : {
     359         374 :         zend_class_entry ce = {0};
     360             : 
     361         374 :         INIT_NS_CLASS_ENTRY(ce, "http", "Header", php_http_header_methods);
     362         374 :         php_http_header_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
     363         374 :         zend_class_implements(php_http_header_class_entry TSRMLS_CC, 1, zend_ce_serializable);
     364         374 :         zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_LOOSE"), PHP_HTTP_MATCH_LOOSE TSRMLS_CC);
     365         374 :         zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_CASE"), PHP_HTTP_MATCH_CASE TSRMLS_CC);
     366         374 :         zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_WORD"), PHP_HTTP_MATCH_WORD TSRMLS_CC);
     367         374 :         zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_FULL"), PHP_HTTP_MATCH_FULL TSRMLS_CC);
     368         374 :         zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_STRICT"), PHP_HTTP_MATCH_STRICT TSRMLS_CC);
     369         374 :         zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
     370         374 :         zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("value"), ZEND_ACC_PUBLIC TSRMLS_CC);
     371             : 
     372         374 :         return SUCCESS;
     373             : }
     374             : 
     375             : /*
     376             :  * Local variables:
     377             :  * tab-width: 4
     378             :  * c-basic-offset: 4
     379             :  * End:
     380             :  * vim600: noet sw=4 ts=4 fdm=marker
     381             :  * vim<600: noet sw=4 ts=4
     382             :  */
     383             : 

Generated by: LCOV version 1.11