LCOV - code coverage report
Current view: top level - ext/http - php_http_env.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 365 401 91.0 %
Date: 2015-02-17 20:30:22 Functions: 36 38 94.7 %
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             : #include "php_variables.h"
      15             : 
      16         374 : PHP_RINIT_FUNCTION(http_env)
      17             : {
      18             :         /* populate form data on non-POST requests */
      19         374 :         if (SG(request_info).request_method && strcasecmp(SG(request_info).request_method, "POST") && SG(request_info).content_type && *SG(request_info).content_type) {
      20           5 :                 uint ct_len = strlen(SG(request_info).content_type);
      21           5 :                 char *ct_str = estrndup(SG(request_info).content_type, ct_len);
      22             :                 php_http_params_opts_t opts;
      23             :                 HashTable params;
      24             : 
      25           5 :                 php_http_params_opts_default_get(&opts);
      26           5 :                 opts.input.str = ct_str;
      27           5 :                 opts.input.len = ct_len;
      28             : 
      29           5 :                 SG(request_info).content_type_dup = ct_str;
      30             : 
      31           5 :                 ZEND_INIT_SYMTABLE(&params);
      32           5 :                 if (php_http_params_parse(&params, &opts TSRMLS_CC)) {
      33             :                         char *key_str;
      34             :                         uint key_len;
      35             :                         ulong key_num;
      36             : 
      37           5 :                         if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(&params, &key_str, &key_len, &key_num, 0, NULL)) {
      38           5 :                                 sapi_post_entry *post_entry = NULL;
      39             : 
      40           5 :                                 if (SUCCESS == zend_hash_find(&SG(known_post_content_types), key_str, key_len, (void *) &post_entry)) {
      41           3 :                                         zval *files = PG(http_globals)[TRACK_VARS_FILES];
      42             : 
      43           3 :                                         if (post_entry) {
      44           3 :                                                 SG(request_info).post_entry = post_entry;
      45             : 
      46           3 :                                                 if (post_entry->post_reader) {
      47           2 :                                                         post_entry->post_reader(TSRMLS_C);
      48             :                                                 }
      49             :                                         }
      50             : 
      51           3 :                                         if (sapi_module.default_post_reader) {
      52           3 :                                                 sapi_module.default_post_reader(TSRMLS_C);
      53             :                                         }
      54             : 
      55           3 :                                         sapi_handle_post(PG(http_globals)[TRACK_VARS_POST] TSRMLS_CC);
      56             : 
      57             :                                         /*
      58             :                                          * the rfc1867 handler is an awkward buddy
      59             :                                          */
      60           3 :                                         if (files != PG(http_globals)[TRACK_VARS_FILES] && PG(http_globals)[TRACK_VARS_FILES]) {
      61           1 :                                                 Z_ADDREF_P(PG(http_globals)[TRACK_VARS_FILES]);
      62           1 :                                                 zend_hash_update(&EG(symbol_table), "_FILES", sizeof("_FILES"), &PG(http_globals)[TRACK_VARS_FILES], sizeof(zval *), NULL);
      63           1 :                                                 if (files) {
      64           1 :                                                         zval_ptr_dtor(&files);
      65             :                                                 }
      66             :                                         }
      67             :                                 }
      68             :                         }
      69           5 :                         zend_hash_destroy(&params);
      70             :                 }
      71             :         }
      72             : 
      73         374 :         PTR_SET(SG(request_info).content_type_dup, NULL);
      74             : 
      75         374 :         return SUCCESS;
      76             : }
      77             : 
      78         374 : PHP_RSHUTDOWN_FUNCTION(http_env)
      79             : {
      80         374 :         if (PHP_HTTP_G->env.request.headers) {
      81          30 :                 zend_hash_destroy(PHP_HTTP_G->env.request.headers);
      82          30 :                 FREE_HASHTABLE(PHP_HTTP_G->env.request.headers);
      83          30 :                 PHP_HTTP_G->env.request.headers = NULL;
      84             :         }
      85         374 :         if (PHP_HTTP_G->env.request.body) {
      86          13 :                 php_http_message_body_free(&PHP_HTTP_G->env.request.body);
      87             :         }
      88             : 
      89         374 :         if (PHP_HTTP_G->env.server_var) {
      90          10 :                 zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
      91          10 :                 PHP_HTTP_G->env.server_var = NULL;
      92             :         }
      93             : 
      94         374 :         return SUCCESS;
      95             : }
      96             : 
      97          91 : void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC)
      98             : {
      99          91 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
     100             :         zval **hsv, **header;
     101             :         HashPosition pos;
     102             : 
     103          91 :         if (!PHP_HTTP_G->env.request.headers) {
     104          30 :                 ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers);
     105          30 :                 zend_hash_init(PHP_HTTP_G->env.request.headers, 0, NULL, ZVAL_PTR_DTOR, 0);
     106             : 
     107          30 :                 zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
     108             : 
     109          30 :                 if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) {
     110        3004 :                         FOREACH_KEY(pos, *hsv, key) {
     111        2974 :                                 if (key.type == HASH_KEY_IS_STRING && key.len > 6 && *key.str == 'H' && !strncmp(key.str, "HTTP_", 5)) {
     112          19 :                                         key.len -= 5;
     113          19 :                                         key.str = php_http_pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1);
     114             : 
     115          19 :                                         zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
     116          19 :                                         Z_ADDREF_P(*header);
     117          19 :                                         zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
     118             : 
     119          19 :                                         efree(key.str);
     120        2955 :                                 } else if (key.type == HASH_KEY_IS_STRING && key.len > 9 && *key.str == 'C' && !strncmp(key.str, "CONTENT_", 8)) {
     121          12 :                                         key.str = php_http_pretty_key(estrndup(key.str, key.len - 1), key.len - 1, 1, 1);
     122             : 
     123          12 :                                         zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
     124          12 :                                         Z_ADDREF_P(*header);
     125          12 :                                         zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
     126             : 
     127          12 :                                         efree(key.str);
     128             :                                 }
     129             :                         }
     130             :                 }
     131             :         }
     132             : 
     133          91 :         if (headers) {
     134          13 :                 zend_hash_copy(headers, PHP_HTTP_G->env.request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
     135             :         }
     136          91 : }
     137             : 
     138          81 : char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request TSRMLS_DC)
     139             : {
     140             :         HashTable *request_headers;
     141          81 :         zval **zvalue = NULL;
     142          81 :         char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
     143             : 
     144          81 :         if (request) {
     145          16 :                 request_headers = &request->hdrs;
     146             :         } else {
     147          65 :                 php_http_env_get_request_headers(NULL TSRMLS_CC);
     148          65 :                 request_headers = PHP_HTTP_G->env.request.headers;
     149             :         }
     150             : 
     151          81 :         if (SUCCESS == zend_symtable_find(request_headers, key, name_len + 1, (void *) &zvalue)) {
     152          27 :                 zval *zcopy = php_http_ztyp(IS_STRING, *zvalue);
     153             : 
     154          27 :                 val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
     155          27 :                 if (len) {
     156          16 :                         *len = Z_STRLEN_P(zcopy);
     157             :                 }
     158          27 :                 zval_ptr_dtor(&zcopy);
     159             :         }
     160             : 
     161          81 :         efree(key);
     162             : 
     163          81 :         return val;
     164             : }
     165             : 
     166          17 : int php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request TSRMLS_DC)
     167             : {
     168             :         HashTable *request_headers;
     169          17 :         char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
     170             :         int got;
     171             : 
     172          17 :         if (request) {
     173           4 :                 request_headers = &request->hdrs;
     174             :         } else {
     175          13 :                 php_http_env_get_request_headers(NULL TSRMLS_CC);
     176          13 :                 request_headers = PHP_HTTP_G->env.request.headers;
     177             :         }
     178          17 :         got = zend_symtable_exists(request_headers, key, name_len + 1);
     179          17 :         efree(key);
     180             : 
     181          17 :         return got;
     182             : }
     183             : 
     184         102 : zval *php_http_env_get_superglobal(const char *key, size_t key_len TSRMLS_DC)
     185             : {
     186             :         zval **hsv;
     187             : 
     188         102 :         zend_is_auto_global(key, key_len TSRMLS_CC);
     189             : 
     190         102 :         if ((SUCCESS != zend_hash_find(&EG(symbol_table), key, key_len + 1, (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
     191           0 :                 return NULL;
     192             :         }
     193             : 
     194         102 :         return *hsv;
     195             : }
     196             : 
     197          93 : zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
     198             : {
     199             :         zval *hsv, **var;
     200             :         char *env;
     201             : 
     202             :         /* if available, this is a lot faster than accessing $_SERVER */
     203          93 :         if (sapi_module.getenv) {
     204          39 :                 if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
     205          22 :                         return NULL;
     206             :                 }
     207          17 :                 if (PHP_HTTP_G->env.server_var) {
     208           7 :                         zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
     209             :                 }
     210          17 :                 MAKE_STD_ZVAL(PHP_HTTP_G->env.server_var);
     211          17 :                 ZVAL_STRING(PHP_HTTP_G->env.server_var, env, 1);
     212          17 :                 return PHP_HTTP_G->env.server_var;
     213             :         }
     214             : 
     215          54 :         if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER") TSRMLS_CC))) {
     216           0 :                 return NULL;
     217             :         }
     218          54 :         if ((SUCCESS != zend_symtable_find(Z_ARRVAL_P(hsv), key, key_len + 1, (void *) &var))) {
     219          51 :                 return NULL;
     220             :         }
     221           3 :         if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
     222           0 :                 return NULL;
     223             :         }
     224           3 :         return *var;
     225             : }
     226             : 
     227          13 : php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D)
     228             : {
     229          13 :         if (!PHP_HTTP_G->env.request.body) {
     230          13 :                 php_stream *s = php_stream_temp_new();
     231             : #if PHP_VERSION_ID >= 50600
     232          13 :                 php_stream *input = php_stream_open_wrapper("php://input", "r", 0, NULL);
     233             : 
     234             :                 /* php://input does not support stat */
     235          13 :                 php_stream_copy_to_stream_ex(input, s, -1, NULL);
     236          13 :                 php_stream_close(input);
     237             : #else
     238             :                 if (SG(request_info).post_data || SG(request_info).raw_post_data) {
     239             :                         /* php://input does not support seek() in PHP <= 5.5 */
     240             :                         if (SG(request_info).raw_post_data) {
     241             :                                 php_stream_write(s, SG(request_info).raw_post_data, SG(request_info).raw_post_data_length);
     242             :                         } else {
     243             :                                 php_stream_write(s, SG(request_info).post_data, SG(request_info).post_data_length);
     244             :                         }
     245             :                 } else if (sapi_module.read_post && !SG(read_post_bytes)) {
     246             :                         char *buf = emalloc(4096);
     247             :                         int len;
     248             : 
     249             :                         while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
     250             :                                 SG(read_post_bytes) += len;
     251             :                                 php_stream_write(s, buf, len);
     252             : 
     253             :                                 if (len < 4096) {
     254             :                                         break;
     255             :                                 }
     256             :                         }
     257             :                         efree(buf);
     258             :                 }
     259             : #endif
     260          13 :                 php_stream_rewind(s);
     261          13 :                 PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s TSRMLS_CC);
     262             :         }
     263             : 
     264          13 :         return PHP_HTTP_G->env.request.body;
     265             : }
     266             : 
     267          16 : const char *php_http_env_get_request_method(php_http_message_t *request TSRMLS_DC)
     268             : {
     269             :         const char *m;
     270             : 
     271          16 :         if (PHP_HTTP_MESSAGE_TYPE(REQUEST, request)) {
     272           3 :                 m = request->http.info.request.method;
     273             :         } else {
     274          13 :                 m = SG(request_info).request_method;
     275             :         }
     276             : 
     277          16 :         return m ? m : "GET";
     278             : }
     279             : 
     280          18 : php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request TSRMLS_DC)
     281             : {
     282             :         zval *zentry;
     283             :         char *range, *rp, c;
     284          18 :         long begin = -1, end = -1, *ptr;
     285             : 
     286          18 :         if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request TSRMLS_CC))) {
     287          13 :                 return PHP_HTTP_RANGE_NO;
     288             :         }
     289           5 :         if (strncmp(range, "bytes=", lenof("bytes="))) {
     290           0 :                 PTR_FREE(range);
     291           0 :                 return PHP_HTTP_RANGE_NO;
     292             :         }
     293             : 
     294           5 :         rp  = range + lenof("bytes=");
     295           5 :         ptr = &begin;
     296             : 
     297             :         do {
     298          44 :                 switch (c = *(rp++)) {
     299             :                         case '0':
     300             :                                 /* allow 000... - shall we? */
     301           9 :                                 if (*ptr != -10) {
     302           6 :                                         *ptr *= 10;
     303             :                                 }
     304           9 :                                 break;
     305             : 
     306             :                         case '1': case '2': case '3':
     307             :                         case '4': case '5': case '6':
     308             :                         case '7': case '8': case '9':
     309             :                                 /*
     310             :                                  * If the value of the pointer is already set (non-negative)
     311             :                                  * then multiply its value by ten and add the current value,
     312             :                                  * else initialise the pointers value with the current value
     313             :                                  * --
     314             :                                  * This let us recognize empty fields when validating the
     315             :                                  * ranges, i.e. a "-10" for begin and "12345" for the end
     316             :                                  * was the following range request: "Range: bytes=0-12345";
     317             :                                  * While a "-1" for begin and "12345" for the end would
     318             :                                  * have been: "Range: bytes=-12345".
     319             :                                  */
     320          17 :                                 if (*ptr > 0) {
     321           4 :                                         *ptr *= 10;
     322           4 :                                         *ptr += c - '0';
     323             :                                 } else {
     324          13 :                                         *ptr = c - '0';
     325             :                                 }
     326          17 :                                 break;
     327             : 
     328             :                         case '-':
     329           9 :                                 ptr = &end;
     330           9 :                                 break;
     331             : 
     332             :                         case ' ':
     333           0 :                                 break;
     334             : 
     335             :                         case 0:
     336             :                         case ',':
     337             : 
     338           9 :                                 if (length) {
     339             :                                         /* validate ranges */
     340           9 :                                         switch (begin) {
     341             :                                                 /* "0-12345" */
     342             :                                                 case -10:
     343           2 :                                                         switch (end) {
     344             :                                                                 /* "0-" */
     345             :                                                                 case -1:
     346           0 :                                                                         PTR_FREE(range);
     347           0 :                                                                         return PHP_HTTP_RANGE_NO;
     348             : 
     349             :                                                                 /* "0-0" */
     350             :                                                                 case -10:
     351           1 :                                                                         end = 0;
     352           1 :                                                                         break;
     353             : 
     354             :                                                                 default:
     355           1 :                                                                         if (length <= (size_t) end) {
     356           0 :                                                                                 end = length - 1;
     357             :                                                                         }
     358           1 :                                                                         break;
     359             :                                                         }
     360           2 :                                                         begin = 0;
     361           2 :                                                         break;
     362             : 
     363             :                                                 /* "-12345" */
     364             :                                                 case -1:
     365             :                                                         /* "-", "-0" */
     366           1 :                                                         if (end == -1 || end == -10) {
     367           0 :                                                                 PTR_FREE(range);
     368           0 :                                                                 return PHP_HTTP_RANGE_ERR;
     369             :                                                         }
     370           1 :                                                         begin = length - end;
     371           1 :                                                         end = length - 1;
     372           1 :                                                         break;
     373             : 
     374             :                                                 /* "12345-(NNN)" */
     375             :                                                 default:
     376           6 :                                                         if (length <= (size_t) begin) {
     377           1 :                                                                 PTR_FREE(range);
     378           1 :                                                                 return PHP_HTTP_RANGE_ERR;
     379             :                                                         }
     380           5 :                                                         switch (end) {
     381             :                                                                 /* "12345-0" */
     382             :                                                                 case -10:
     383           0 :                                                                         PTR_FREE(range);
     384           0 :                                                                         return PHP_HTTP_RANGE_ERR;
     385             : 
     386             :                                                                 /* "12345-" */
     387             :                                                                 case -1:
     388           1 :                                                                         end = length - 1;
     389           1 :                                                                         break;
     390             : 
     391             :                                                                 /* "12345-67890" */
     392             :                                                                 default:
     393           4 :                                                                         if (length <= (size_t) end) {
     394           0 :                                                                                 end = length - 1;
     395           4 :                                                                         } else if (end <  begin) {
     396           0 :                                                                                 PTR_FREE(range);
     397           0 :                                                                                 return PHP_HTTP_RANGE_ERR;
     398             :                                                                         }
     399           4 :                                                                         break;
     400             :                                                         }
     401           5 :                                                         break;
     402             :                                         }
     403             :                                 }
     404             : 
     405           8 :                                 MAKE_STD_ZVAL(zentry);
     406           8 :                                 array_init(zentry);
     407           8 :                                 add_index_long(zentry, 0, begin);
     408           8 :                                 add_index_long(zentry, 1, end);
     409           8 :                                 zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL);
     410             : 
     411           8 :                                 begin = -1;
     412           8 :                                 end = -1;
     413           8 :                                 ptr = &begin;
     414             : 
     415           8 :                                 break;
     416             : 
     417             :                         default:
     418           0 :                                 PTR_FREE(range);
     419           0 :                                 return PHP_HTTP_RANGE_NO;
     420             :                 }
     421          43 :         } while (c != 0);
     422             : 
     423           4 :         PTR_FREE(range);
     424           4 :         return PHP_HTTP_RANGE_OK;
     425             : }
     426             : 
     427          27 : static void grab_headers(void *data, void *arg TSRMLS_DC)
     428             : {
     429          27 :         php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header);
     430          27 :         php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF);
     431          27 : }
     432             : 
     433          26 : STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC)
     434             : {
     435             :         STATUS status;
     436             :         php_http_buffer_t headers;
     437             : 
     438          26 :         php_http_buffer_init(&headers);
     439          26 :         zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers TSRMLS_CC);
     440          26 :         php_http_buffer_fix(&headers);
     441             : 
     442          26 :         status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL TSRMLS_CC);
     443          26 :         php_http_buffer_dtor(&headers);
     444             : 
     445          26 :         return status;
     446             : }
     447             : 
     448           1 : char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC)
     449             : {
     450           1 :         char *val = NULL;
     451             :         HashTable headers;
     452             : 
     453           1 :         zend_hash_init(&headers, 0, NULL, ZVAL_PTR_DTOR, 0);
     454           1 :         if (SUCCESS == php_http_env_get_response_headers(&headers TSRMLS_CC)) {
     455             :                 zval **zvalue;
     456           1 :                 char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
     457             : 
     458           1 :                 if (SUCCESS == zend_symtable_find(&headers, key, name_len + 1, (void *) &zvalue)) {
     459           1 :                         zval *zcopy = php_http_ztyp(IS_STRING, *zvalue);
     460             : 
     461           1 :                         val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
     462           1 :                         zval_ptr_dtor(&zcopy);
     463             :                 }
     464             : 
     465           1 :                 efree(key);
     466             :         }
     467           1 :         zend_hash_destroy(&headers);
     468             : 
     469           1 :         return val;
     470             : }
     471             : 
     472          19 : long php_http_env_get_response_code(TSRMLS_D)
     473             : {
     474          19 :         long code = SG(sapi_headers).http_response_code;
     475          19 :         return code ? code : 200;
     476             : }
     477             : 
     478          15 : STATUS php_http_env_set_response_code(long http_code TSRMLS_DC)
     479             : {
     480          15 :         return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) http_code TSRMLS_CC);
     481             : }
     482             : 
     483          10 : STATUS php_http_env_set_response_status_line(long code, php_http_version_t *v TSRMLS_DC)
     484             : {
     485          10 :         sapi_header_line h = {NULL, 0, 0};
     486             :         STATUS ret;
     487             : 
     488          10 :         h.line_len = spprintf(&h.line, 0, "HTTP/%u.%u %ld %s", v->major, v->minor, code, php_http_env_get_response_status_for_code(code));
     489          10 :         ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h TSRMLS_CC);
     490          10 :         efree(h.line);
     491             : 
     492          10 :         return ret;
     493             : }
     494             : 
     495          10 : STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC)
     496             : {
     497          10 :         return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C), v TSRMLS_CC);
     498             : }
     499             : 
     500           0 : STATUS php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC)
     501             : {
     502           0 :         sapi_header_line h = {estrndup(header_str, header_len), header_len, http_code};
     503           0 :         STATUS ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
     504           0 :         efree(h.line);
     505           0 :         return ret;
     506             : }
     507             : 
     508          42 : STATUS php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv TSRMLS_DC)
     509             : {
     510          42 :         STATUS ret = FAILURE;
     511          42 :         sapi_header_line h = {NULL, 0, http_code};
     512             : 
     513          42 :         h.line_len = vspprintf(&h.line, 0, fmt, argv);
     514             : 
     515          42 :         if (h.line) {
     516          42 :                 if (h.line_len) {
     517          42 :                         ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
     518             :                 }
     519          42 :                 efree(h.line);
     520             :         }
     521          42 :         return ret;
     522             : }
     523             : 
     524           0 : STATUS php_http_env_set_response_header_format(long http_code, zend_bool replace TSRMLS_DC, const char *fmt, ...)
     525             : {
     526             :         STATUS ret;
     527             :         va_list args;
     528             : 
     529           0 :         va_start(args, fmt);
     530           0 :         ret = php_http_env_set_response_header_va(http_code, replace, fmt, args TSRMLS_CC);
     531           0 :         va_end(args);
     532             : 
     533           0 :         return ret;
     534             : }
     535             : 
     536          13 : STATUS php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC)
     537             : {
     538          13 :         if (!value) {
     539           7 :                 sapi_header_line h = {(char *) name_str, name_len, http_code};
     540             : 
     541           7 :                 return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h TSRMLS_CC);
     542             :         }
     543             : 
     544           6 :         if(Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
     545             :                 HashPosition pos;
     546           1 :                 int first = replace;
     547             :                 zval **data_ptr;
     548             : 
     549           4 :                 FOREACH_HASH_VAL(pos, HASH_OF(value), data_ptr) {
     550           3 :                         if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, *data_ptr, first TSRMLS_CC)) {
     551           0 :                                 return FAILURE;
     552             :                         }
     553           3 :                         first = 0;
     554             :                 }
     555             : 
     556           1 :                 return SUCCESS;
     557             :         } else {
     558           5 :                 zval *data = php_http_ztyp(IS_STRING, value);
     559             : 
     560           5 :                 if (!Z_STRLEN_P(data)) {
     561           0 :                         zval_ptr_dtor(&data);
     562           0 :                         return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace TSRMLS_CC);
     563             :                 } else {
     564             :                         sapi_header_line h;
     565             :                         STATUS ret;
     566             : 
     567           5 :                         if (name_len > INT_MAX) {
     568           0 :                                 name_len = INT_MAX;
     569             :                         }
     570           5 :                         h.response_code = http_code;
     571           5 :                         h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, Z_STRLEN_P(data), Z_STRVAL_P(data));
     572             : 
     573           5 :                         ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
     574             : 
     575           5 :                         zval_ptr_dtor(&data);
     576           5 :                         PTR_FREE(h.line);
     577             : 
     578           5 :                         return ret;
     579             :                 }
     580             :         }
     581             : }
     582             : 
     583         650 : const char *php_http_env_get_response_status_for_code(unsigned code)
     584             : {
     585         650 :         switch (code) {
     586             : #define PHP_HTTP_RESPONSE_CODE(c, s) case c: return s;
     587             : #include "php_http_response_codes.h"
     588             : #undef PHP_HTTP_RESPONSE_CODE
     589             :         default:
     590         544 :                 return NULL;
     591             :         }
     592             : }
     593             : 
     594             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestHeader, 0, 0, 0)
     595             :         ZEND_ARG_INFO(0, header_name)
     596             : ZEND_END_ARG_INFO();
     597           4 : static PHP_METHOD(HttpEnv, getRequestHeader)
     598             : {
     599           4 :         char *header_name_str = NULL;
     600           4 :         int header_name_len = 0;
     601             : 
     602           4 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
     603           2 :                 return;
     604             :         }
     605           5 :         if (header_name_str && header_name_len) {
     606             :                 size_t header_length;
     607           3 :                 char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL TSRMLS_CC);
     608             : 
     609           3 :                 if (header_value) {
     610           2 :                         RETURN_STRINGL(header_value, header_length, 0);
     611             :                 }
     612             :         } else {
     613           1 :                 array_init(return_value);
     614           1 :                 php_http_env_get_request_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
     615             :         }
     616             : }
     617             : 
     618             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestBody, 0, 0, 0)
     619             :         ZEND_ARG_INFO(0, body_class_name)
     620             : ZEND_END_ARG_INFO();
     621           1 : static PHP_METHOD(HttpEnv, getRequestBody)
     622             : {
     623             :         zend_object_value ov;
     624             :         php_http_message_body_t *body;
     625           1 :         zend_class_entry *class_entry = php_http_message_body_class_entry;
     626             : 
     627           2 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &class_entry), invalid_arg, return);
     628             : 
     629           1 :         body = php_http_env_get_request_body(TSRMLS_C);
     630           1 :         if (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_message_body_class_entry, body, NULL TSRMLS_CC)) {
     631           1 :                 php_http_message_body_addref(body);
     632           1 :                 RETVAL_OBJVAL(ov, 0);
     633             :         }
     634             : }
     635             : 
     636             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForCode, 0, 0, 1)
     637             :         ZEND_ARG_INFO(0, code)
     638             : ZEND_END_ARG_INFO();
     639         602 : static PHP_METHOD(HttpEnv, getResponseStatusForCode)
     640             : {
     641             :         long code;
     642             :         const char *status;
     643             : 
     644         602 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
     645          58 :                 return;
     646             :         }
     647             : 
     648         602 :         if ((status = php_http_env_get_response_status_for_code(code))) {
     649          58 :                 RETURN_STRING(status, 1);
     650             :         }
     651             : }
     652             : 
     653             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForAllCodes, 0, 0, 0)
     654             : ZEND_END_ARG_INFO();
     655           1 : static PHP_METHOD(HttpEnv, getResponseStatusForAllCodes)
     656             : {
     657           1 :         if (SUCCESS != zend_parse_parameters_none()) {
     658           1 :                 return;
     659             :         }
     660             : 
     661           1 :         array_init(return_value);
     662             : #define PHP_HTTP_RESPONSE_CODE(code, status) add_index_string(return_value, code, status, 1);
     663             : #include "php_http_response_codes.h"
     664             : #undef PHP_HTTP_RESPONSE_CODE
     665             : }
     666             : 
     667             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseHeader, 0, 0, 0)
     668             :         ZEND_ARG_INFO(0, header_name)
     669             : ZEND_END_ARG_INFO();
     670           2 : static PHP_METHOD(HttpEnv, getResponseHeader)
     671             : {
     672           2 :         char *header_name_str = NULL;
     673           2 :         int header_name_len = 0;
     674             : 
     675           2 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
     676           1 :                 return;
     677             :         }
     678           2 :         if (header_name_str && header_name_len) {
     679           1 :                 char *header_value = php_http_env_get_response_header(header_name_str, header_name_len TSRMLS_CC);
     680             : 
     681           1 :                 if (header_value) {
     682           1 :                         RETURN_STRING(header_value, 0);
     683             :                 }
     684             :         } else {
     685           1 :                 array_init(return_value);
     686           1 :                 php_http_env_get_response_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
     687             :         }
     688             : }
     689             : 
     690             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseCode, 0, 0, 0)
     691             : ZEND_END_ARG_INFO();
     692           1 : static PHP_METHOD(HttpEnv, getResponseCode)
     693             : {
     694           1 :         if (SUCCESS != zend_parse_parameters_none()) {
     695           0 :                 return;
     696             :         }
     697           1 :         RETURN_LONG(php_http_env_get_response_code(TSRMLS_C));
     698             : }
     699             : 
     700             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseHeader, 0, 0, 1)
     701             :         ZEND_ARG_INFO(0, header_name)
     702             :         ZEND_ARG_INFO(0, header_value)
     703             :         ZEND_ARG_INFO(0, response_code)
     704             :         ZEND_ARG_INFO(0, replace_header)
     705             : ZEND_END_ARG_INFO();
     706           4 : static PHP_METHOD(HttpEnv, setResponseHeader)
     707             : {
     708             :         char *header_name_str;
     709             :         int header_name_len;
     710           4 :         zval *header_value = NULL;
     711           4 :         long code = 0;
     712           4 :         zend_bool replace_header = 1;
     713             : 
     714           4 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) {
     715           0 :                 return;
     716             :         }
     717           4 :         RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header TSRMLS_CC));
     718             : }
     719             : 
     720             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseCode, 0, 0, 1)
     721             :         ZEND_ARG_INFO(0, code)
     722             : ZEND_END_ARG_INFO();
     723           1 : static PHP_METHOD(HttpEnv, setResponseCode)
     724             : {
     725             :         long code;
     726             : 
     727           1 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
     728           0 :                 return;
     729             :         }
     730           1 :         RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code TSRMLS_CC));
     731             : }
     732             : 
     733             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateLanguage, 0, 0, 1)
     734             :         ZEND_ARG_INFO(0, supported)
     735             :         ZEND_ARG_INFO(1, result_array)
     736             : ZEND_END_ARG_INFO();
     737           3 : static PHP_METHOD(HttpEnv, negotiateLanguage)
     738             : {
     739             :         HashTable *supported;
     740           3 :         zval *rs_array = NULL;
     741             : 
     742           3 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
     743           3 :                 return;
     744             :         }
     745           3 :         if (rs_array) {
     746           3 :                 zval_dtor(rs_array);
     747           3 :                 array_init(rs_array);
     748             :         }
     749             : 
     750           3 :         PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array);
     751             : }
     752             : 
     753             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateCharset, 0, 0, 1)
     754             :         ZEND_ARG_INFO(0, supported)
     755             :         ZEND_ARG_INFO(1, result_array)
     756             : ZEND_END_ARG_INFO();
     757           3 : static PHP_METHOD(HttpEnv, negotiateCharset)
     758             : {
     759             :         HashTable *supported;
     760           3 :         zval *rs_array = NULL;
     761             : 
     762           3 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
     763           3 :                 return;
     764             :         }
     765           3 :         if (rs_array) {
     766           3 :                 zval_dtor(rs_array);
     767           3 :                 array_init(rs_array);
     768             :         }
     769           3 :         PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array);
     770             : }
     771             : 
     772             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateEncoding, 0, 0, 1)
     773             :         ZEND_ARG_INFO(0, supported)
     774             :         ZEND_ARG_INFO(1, result_array)
     775             : ZEND_END_ARG_INFO();
     776           2 : static PHP_METHOD(HttpEnv, negotiateEncoding)
     777             : {
     778             :         HashTable *supported;
     779           2 :         zval *rs_array = NULL;
     780             : 
     781           2 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
     782           2 :                 return;
     783             :         }
     784           2 :         if (rs_array) {
     785           2 :                 zval_dtor(rs_array);
     786           2 :                 array_init(rs_array);
     787             :         }
     788           2 :         PHP_HTTP_DO_NEGOTIATE(encoding, supported, rs_array);
     789             : }
     790             : 
     791             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateContentType, 0, 0, 1)
     792             :         ZEND_ARG_INFO(0, supported)
     793             :         ZEND_ARG_INFO(1, result_array)
     794             : ZEND_END_ARG_INFO();
     795           3 : static PHP_METHOD(HttpEnv, negotiateContentType)
     796             : {
     797             :         HashTable *supported;
     798           3 :         zval *rs_array = NULL;
     799             : 
     800           3 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
     801           3 :                 return;
     802             :         }
     803           3 :         if (rs_array) {
     804           3 :                 zval_dtor(rs_array);
     805           3 :                 array_init(rs_array);
     806             :         }
     807           3 :         PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
     808             : }
     809             : 
     810             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiate, 0, 0, 2)
     811             :         ZEND_ARG_INFO(0, params)
     812             :         ZEND_ARG_INFO(0, supported)
     813             :         ZEND_ARG_INFO(0, primary_type_separator)
     814             :         ZEND_ARG_INFO(1, result_array)
     815             : ZEND_END_ARG_INFO();
     816           1 : static PHP_METHOD(HttpEnv, negotiate)
     817             : {
     818             :         HashTable *supported, *rs;
     819           1 :         zval *rs_array = NULL;
     820           1 :         char *value_str, *sep_str = NULL;
     821           1 :         int value_len, sep_len = 0;
     822             : 
     823           1 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sH|s!z", &value_str, &value_len, &supported, &sep_str, &sep_len, &rs_array)) {
     824           1 :                 return;
     825             :         }
     826             : 
     827             : 
     828           1 :         if (rs_array) {
     829           1 :                 zval_dtor(rs_array);
     830           1 :                 array_init(rs_array);
     831             :         }
     832             : 
     833           1 :         if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len TSRMLS_CC))) {
     834           1 :                 PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
     835             :         } else {
     836           0 :                 PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
     837             :         }
     838             : }
     839             : 
     840             : static zend_function_entry php_http_env_methods[] = {
     841             :         PHP_ME(HttpEnv, getRequestHeader,              ai_HttpEnv_getRequestHeader,              ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     842             :         PHP_ME(HttpEnv, getRequestBody,                ai_HttpEnv_getRequestBody,                ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     843             : 
     844             :         PHP_ME(HttpEnv, getResponseStatusForCode,      ai_HttpEnv_getResponseStatusForCode,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     845             :         PHP_ME(HttpEnv, getResponseStatusForAllCodes,  ai_HttpEnv_getResponseStatusForAllCodes,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     846             : 
     847             :         PHP_ME(HttpEnv, getResponseHeader,             ai_HttpEnv_getResponseHeader,             ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     848             :         PHP_ME(HttpEnv, getResponseCode,               ai_HttpEnv_getResponseCode,               ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     849             :         PHP_ME(HttpEnv, setResponseHeader,             ai_HttpEnv_setResponseHeader,             ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     850             :         PHP_ME(HttpEnv, setResponseCode,               ai_HttpEnv_setResponseCode,               ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     851             : 
     852             :         PHP_ME(HttpEnv, negotiateLanguage,             ai_HttpEnv_negotiateLanguage,             ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     853             :         PHP_ME(HttpEnv, negotiateContentType,          ai_HttpEnv_negotiateContentType,          ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     854             :         PHP_ME(HttpEnv, negotiateEncoding,             ai_HttpEnv_negotiateEncoding,             ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     855             :         PHP_ME(HttpEnv, negotiateCharset,              ai_HttpEnv_negotiateCharset,              ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     856             :         PHP_ME(HttpEnv, negotiate,                     ai_HttpEnv_negotiate,                     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     857             : 
     858             :         EMPTY_FUNCTION_ENTRY
     859             : };
     860             : 
     861             : #ifdef PHP_HTTP_HAVE_JSON
     862             : #include "ext/json/php_json.h"
     863             : 
     864           2 : static SAPI_POST_HANDLER_FUNC(php_http_json_post_handler)
     865             : {
     866           2 :         zval *zarg = arg;
     867           2 :         char *json_str = NULL;
     868           2 :         size_t json_len = 0;
     869             : 
     870             : #if PHP_VERSION_ID >= 50600
     871           2 :         if (SG(request_info).request_body) {
     872             :                 /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
     873           2 :                 php_stream_rewind(SG(request_info).request_body);
     874           2 :                 json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0);
     875             :         }
     876             : #else
     877             :         json_str = SG(request_info).raw_post_data;
     878             :         json_len = SG(request_info).raw_post_data_length;
     879             : #endif
     880             : 
     881           2 :         if (json_len) {
     882             :                 zval zjson;
     883             : 
     884           2 :                 INIT_ZVAL(zjson);
     885           2 :                 php_json_decode(&zjson, json_str, json_len, 1, PG(max_input_nesting_level) TSRMLS_CC);
     886           2 :                 if (Z_TYPE(zjson) != IS_NULL) {
     887           2 :                         zval_dtor(zarg);
     888           2 :                         ZVAL_COPY_VALUE(zarg, (&zjson));
     889             :                 }
     890             :         }
     891             : #if PHP_VERSION_ID >= 50600
     892           2 :         PTR_FREE(json_str);
     893             : #endif
     894           2 : }
     895             : 
     896         374 : static void php_http_env_register_json_handler(TSRMLS_D)
     897             : {
     898         374 :         sapi_post_entry entry = {NULL, 0, NULL, NULL};
     899             : 
     900         374 :         entry.post_reader = sapi_read_standard_form_data;
     901         374 :         entry.post_handler = php_http_json_post_handler;
     902             : 
     903         374 :         entry.content_type = "text/json";
     904         374 :         entry.content_type_len = lenof("text/json");
     905         374 :         sapi_register_post_entry(&entry TSRMLS_CC);
     906             : 
     907         374 :         entry.content_type = "application/json";
     908         374 :         entry.content_type_len = lenof("application/json");
     909         374 :         sapi_register_post_entry(&entry TSRMLS_CC);
     910         374 : }
     911             : #endif
     912             : 
     913             : zend_class_entry *php_http_env_class_entry;
     914             : 
     915         374 : PHP_MINIT_FUNCTION(http_env)
     916             : {
     917         374 :         zend_class_entry ce = {0};
     918             : 
     919         374 :         INIT_NS_CLASS_ENTRY(ce, "http", "Env", php_http_env_methods);
     920         374 :         php_http_env_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
     921             : 
     922             : #ifdef PHP_HTTP_HAVE_JSON
     923         374 :         php_http_env_register_json_handler(TSRMLS_C);
     924             : #endif
     925             : 
     926         374 :         return SUCCESS;
     927             : }
     928             : 
     929             : 
     930             : /*
     931             :  * Local variables:
     932             :  * tab-width: 4
     933             :  * c-basic-offset: 4
     934             :  * End:
     935             :  * vim600: noet sw=4 ts=4 fdm=marker
     936             :  * vim<600: noet sw=4 ts=4
     937             :  */

Generated by: LCOV version 1.11