LTP GCOV extension - code coverage report
Current view: directory - ext/http - http_api.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 322
Code covered: 65.8 % Executed lines: 212
Legend: not executed executed

       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-2007, Michael Wallner <mike@php.net>            |
      10                 :     +--------------------------------------------------------------------+
      11                 : */
      12                 : 
      13                 : /* $Id: http_api.c,v 1.165 2007/02/09 14:19:39 mike Exp $ */
      14                 : 
      15                 : #define HTTP_WANT_SAPI
      16                 : #include "php_http.h"
      17                 : 
      18                 : #include "php_output.h"
      19                 : #include "ext/standard/url.h"
      20                 : 
      21                 : #include "php_http_api.h"
      22                 : #include "php_http_send_api.h"
      23                 : 
      24                 : #ifdef ZEND_ENGINE_2
      25                 : #       include "php_http_exception_object.h"
      26                 : #endif
      27                 : 
      28                 : PHP_MINIT_FUNCTION(http_support)
      29             220 : {
      30             220 :         HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT);
      31             220 :         HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS);
      32             220 :         HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME);
      33             220 :         HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS);
      34             220 :         HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS);
      35                 :         
      36             220 :         HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA);
      37             220 :         HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE);
      38             220 :         HTTP_LONG_CONSTANT("HTTP_PARAMS_RAISE_ERROR", HTTP_PARAMS_RAISE_ERROR);
      39             220 :         HTTP_LONG_CONSTANT("HTTP_PARAMS_DEFAULT", HTTP_PARAMS_DEFAULT);
      40                 :         
      41             220 :         return SUCCESS;
      42                 : }
      43                 : 
      44                 : PHP_HTTP_API long _http_support(long feature)
      45              15 : {
      46              15 :         long support = HTTP_SUPPORT;
      47                 :         
      48                 : #ifdef HTTP_HAVE_CURL
      49              15 :         support |= HTTP_SUPPORT_REQUESTS;
      50                 : #       ifdef HTTP_HAVE_SSL
      51              15 :         support |= HTTP_SUPPORT_SSLREQUESTS;
      52                 : #       endif
      53                 : #endif
      54                 : #ifdef HTTP_HAVE_MAGIC
      55                 :         support |= HTTP_SUPPORT_MAGICMIME;
      56                 : #endif
      57                 : #ifdef HTTP_HAVE_ZLIB
      58              15 :         support |= HTTP_SUPPORT_ENCODINGS;
      59                 : #endif
      60                 : 
      61              15 :         if (feature) {
      62              15 :                 return (feature == (support & feature));
      63                 :         }
      64               0 :         return support;
      65                 : }
      66                 : 
      67                 : /* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
      68                 : char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
      69             810 : {
      70                 :         size_t i;
      71                 :         int wasalpha;
      72                 :         
      73             810 :         if (key && key_len) {
      74             810 :                 if ((wasalpha = HTTP_IS_CTYPE(alpha, key[0]))) {
      75             810 :                         key[0] = (char) (uctitle ? HTTP_TO_CTYPE(upper, key[0]) : HTTP_TO_CTYPE(lower, key[0]));
      76                 :                 }
      77            7492 :                 for (i = 1; i < key_len; i++) {
      78            6682 :                         if (HTTP_IS_CTYPE(alpha, key[i])) {
      79            6195 :                                 key[i] = (char) (((!wasalpha) && uctitle) ? HTTP_TO_CTYPE(upper, key[i]) : HTTP_TO_CTYPE(lower, key[i]));
      80            6195 :                                 wasalpha = 1;
      81                 :                         } else {
      82             487 :                                 if (xhyphen && (key[i] == '_')) {
      83               2 :                                         key[i] = '-';
      84                 :                                 }
      85             487 :                                 wasalpha = 0;
      86                 :                         }
      87                 :                 }
      88                 :         }
      89             810 :         return key;
      90                 : }
      91                 : /* }}} */
      92                 : 
      93                 : /* {{{ void http_error(long, long, char*) */
      94                 : void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...)
      95              19 : {
      96                 :         va_list args;
      97                 :         
      98              19 :         va_start(args, format);
      99                 : #ifdef ZEND_ENGINE_2
     100              35 :         if ((type == E_THROW) || (PG(error_handling) == EH_THROW)) {
     101                 :                 char *message;
     102              16 :                 zend_class_entry *ce = http_exception_get_for_code(code);
     103                 :                 
     104              16 :                 http_try {
     105              16 :                         vspprintf(&message, 0, format, args);
     106              16 :                         zend_throw_exception(ce, message, code TSRMLS_CC);
     107              16 :                         efree(message);
     108              16 :                 } http_catch(PG(exception_class) ? PG(exception_class) : HTTP_EX_DEF_CE);
     109                 :         } else
     110                 : #endif
     111               3 :         php_verror(NULL, "", type, format, args TSRMLS_CC);
     112              19 :         va_end(args);
     113              19 : }
     114                 : /* }}} */
     115                 : 
     116                 : #ifdef ZEND_ENGINE_2
     117                 : static inline void copy_bt_args(zval *from, zval *to TSRMLS_DC)
     118              10 : {
     119              10 :         zval **args, **trace_0, *old_trace_0, *trace = NULL;
     120                 :         
     121              10 :         if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), from, "trace", lenof("trace"), 0 TSRMLS_CC))) {
     122              10 :                 if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) {
     123              10 :                         old_trace_0 = *trace_0;
     124              10 :                         if (Z_TYPE_PP(trace_0) == IS_ARRAY && SUCCESS == zend_hash_find(Z_ARRVAL_PP(trace_0), "args", sizeof("args"), (void *) &args)) {
     125              10 :                                 if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), to, "trace", lenof("trace"), 0 TSRMLS_CC))) {
     126              10 :                                         if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) {
     127              10 :                                                 ZVAL_ADDREF(*args);
     128              10 :                                                 add_assoc_zval(*trace_0, "args", *args);
     129                 :                                         }
     130                 :                                 }
     131                 :                         }
     132                 :                 }
     133                 :         }
     134              10 : }
     135                 : 
     136                 : /* {{{ zval *http_exception_wrap(zval *, zval *, zend_class_entry *) */
     137                 : zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC)
     138               6 : {
     139               6 :         int inner = 1;
     140                 :         char *message;
     141                 :         zval *sub_exception, *tmp_exception;
     142                 :         
     143               6 :         if (!new_exception) {
     144               2 :                 MAKE_STD_ZVAL(new_exception);
     145               2 :                 object_init_ex(new_exception, ce);
     146                 :                 
     147               2 :                 zend_update_property(ce, new_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
     148               2 :                 copy_bt_args(old_exception, new_exception TSRMLS_CC);
     149                 :                 
     150               2 :                 sub_exception = old_exception;
     151                 :                 
     152               8 :                 while ((sub_exception = zend_read_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(sub_exception) == IS_OBJECT) {
     153               4 :                         ++inner;
     154                 :                 }
     155                 :                 
     156               2 :                 spprintf(&message, 0, "Exception caused by %d inner exception(s)", inner);
     157               2 :                 zend_update_property_string(ZEND_EXCEPTION_GET_DEFAULT(), new_exception, "message", lenof("message"), message TSRMLS_CC);
     158               2 :                 efree(message);
     159                 :         } else {
     160               4 :                 sub_exception = new_exception;
     161               4 :                 tmp_exception = new_exception;
     162                 :                 
     163               8 :                 while ((tmp_exception = zend_read_property(Z_OBJCE_P(tmp_exception), tmp_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(tmp_exception) == IS_OBJECT) {
     164               0 :                         sub_exception = tmp_exception;
     165                 :                 }
     166                 :                 
     167               4 :                 zend_update_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
     168               4 :                 copy_bt_args(old_exception, new_exception TSRMLS_CC);
     169               4 :                 copy_bt_args(old_exception, sub_exception TSRMLS_CC);
     170                 :         }
     171                 :         
     172               6 :         zval_ptr_dtor(&old_exception);
     173               6 :         return new_exception;
     174                 : }
     175                 : /* }}} */
     176                 : 
     177                 : /* {{{ STATUS http_object_new(zend_object_value *, const char *, uint, http_object_new_t, zend_class_entry *, void *, void **) */
     178                 : STATUS _http_object_new(zend_object_value *ov, const char *cname_str, uint cname_len, http_object_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC)
     179               3 : {
     180               3 :         zend_class_entry *ce = parent_ce;
     181                 :         
     182               3 :         if (cname_str && cname_len) {
     183               0 :                 if (!(ce = zend_fetch_class((char *) cname_str, cname_len, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC))) {
     184               0 :                         return FAILURE;
     185                 :                 }
     186               0 :                 if (!instanceof_function(ce, parent_ce TSRMLS_CC)) {
     187               0 :                         http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Class %s does not extend %s", cname_str, parent_ce->name);
     188               0 :                         return FAILURE;
     189                 :                 }
     190                 :         }
     191                 :         
     192               3 :         *ov = create(ce, intern_ptr, obj_ptr TSRMLS_CC);
     193               3 :         return SUCCESS;
     194                 : }
     195                 : /* }}} */
     196                 : #endif /* ZEND_ENGINE_2 */
     197                 : 
     198                 : /* {{{ void http_log(char *, char *, char *) */
     199                 : void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC)
     200               6 : {
     201                 :         time_t now;
     202                 :         struct tm nowtm;
     203               6 :         char datetime[20] = {0};
     204                 :         
     205               6 :         now = HTTP_G->request.time;
     206               6 :         strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
     207                 : 
     208                 : #define HTTP_LOG_WRITE(file, type, msg) \
     209                 :         if (file && *file) { \
     210                 :                 php_stream *log = php_stream_open_wrapper_ex(file, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT); \
     211                 :                  \
     212                 :                 if (log) { \
     213                 :                         php_stream_printf(log TSRMLS_CC, "%s\t[%s]\t%s\t<%s>%s", datetime, type, msg, SG(request_info).request_uri, PHP_EOL); \
     214                 :                         php_stream_close(log); \
     215                 :                 } \
     216                 :          \
     217                 :         }
     218                 :         
     219               6 :         HTTP_LOG_WRITE(file, ident, message);
     220               6 :         HTTP_LOG_WRITE(HTTP_G->log.composite, ident, message);
     221               6 : }
     222                 : /* }}} */
     223                 : 
     224                 : static void http_ob_blackhole(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
     225               0 : {
     226               0 :         *handled_output = ecalloc(1,1);
     227               0 :         *handled_output_len = 0;
     228               0 : }
     229                 : 
     230                 : /* {{{ STATUS http_exit(int, char*, char*) */
     231                 : STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC)
     232               6 : {
     233               6 :         if (    (send_header && (SUCCESS != http_send_status_header(status, header))) ||
     234                 :                         (status && (SUCCESS != http_send_status(status)))) {
     235               0 :                 http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, STR_PTR(header));
     236               0 :                 STR_FREE(header);
     237               0 :                 STR_FREE(body);
     238               0 :                 return FAILURE;
     239                 :         }
     240                 :         
     241               6 :         if (!OG(ob_lock)) {
     242               6 :                 php_end_ob_buffers(0 TSRMLS_CC);
     243                 :         }
     244               6 :         if ((SUCCESS == sapi_send_headers(TSRMLS_C)) && body) {
     245               4 :                 PHPWRITE(body, strlen(body));
     246                 :         }
     247                 :         
     248               6 :         switch (status) {
     249               1 :                 case 301:       http_log(HTTP_G->log.redirect, "301-REDIRECT", header);                    break;
     250               2 :                 case 302:       http_log(HTTP_G->log.redirect, "302-REDIRECT", header);                    break;
     251               0 :                 case 303:       http_log(HTTP_G->log.redirect, "303-REDIRECT", header);                    break;
     252               0 :                 case 305:       http_log(HTTP_G->log.redirect, "305-REDIRECT", header);                    break;
     253               0 :                 case 307:       http_log(HTTP_G->log.redirect, "307-REDIRECT", header);                    break;
     254               1 :                 case 304:       http_log(HTTP_G->log.cache, "304-CACHE", header);                          break;
     255               1 :                 case 404:       http_log(HTTP_G->log.not_found, "404-NOTFOUND", NULL);                     break;
     256               1 :                 case 405:       http_log(HTTP_G->log.allowed_methods, "405-ALLOWED", header);      break;
     257               0 :                 default:        http_log(NULL, header, body);                                                                   break;
     258                 :         }
     259                 :         
     260               6 :         STR_FREE(header);
     261               6 :         STR_FREE(body);
     262                 :         
     263               6 :         if (HTTP_G->force_exit) {
     264               6 :                 zend_bailout();
     265                 :         } else {
     266               0 :                 php_ob_set_internal_handler(http_ob_blackhole, 4096, "blackhole", 0 TSRMLS_CC);
     267                 :         }
     268                 :         
     269               0 :         return SUCCESS;
     270                 : }
     271                 : /* }}} */
     272                 : 
     273                 : /* {{{ STATUS http_check_method(char *) */
     274                 : STATUS _http_check_method_ex(const char *method, const char *methods)
     275               1 : {
     276                 :         const char *found;
     277                 : 
     278               1 :         if (    (found = strstr(methods, method)) &&
     279                 :                         (found == method || !HTTP_IS_CTYPE(alpha, found[-1])) &&
     280                 :                         (strlen(found) >= strlen(method) && !HTTP_IS_CTYPE(alpha, found[strlen(method)]))) {
     281               0 :                 return SUCCESS;
     282                 :         }
     283               1 :         return FAILURE;
     284                 : }
     285                 : /* }}} */
     286                 : 
     287                 : /* {{{ zval *http_get_server_var_ex(char *, size_t) */
     288                 : PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
     289             147 : {
     290                 :         zval **hsv, **var;
     291                 :         char *env;
     292                 :         
     293                 :         /* if available, this is a lot faster than accessing $_SERVER */
     294             147 :         if (sapi_module.getenv) {
     295             147 :                 if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
     296             107 :                         return NULL;
     297                 :                 }
     298              40 :                 if (HTTP_G->server_var) {
     299              12 :                         zval_ptr_dtor(&HTTP_G->server_var);
     300                 :                 }
     301              40 :                 MAKE_STD_ZVAL(HTTP_G->server_var);
     302              40 :                 ZVAL_STRING(HTTP_G->server_var, env, 1);
     303              40 :                 return HTTP_G->server_var;
     304                 :         }
     305                 :         
     306                 : #ifdef ZEND_ENGINE_2
     307               0 :         zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
     308                 : #endif
     309                 :         
     310               0 :         if ((SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
     311               0 :                 return NULL;
     312                 :         }
     313               0 :         if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), (char *) key, key_len + 1, (void *) &var))) {
     314               0 :                 return NULL;
     315                 :         }
     316               0 :         if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
     317               0 :                 return NULL;
     318                 :         }
     319               0 :         return *var;
     320                 : }
     321                 : /* }}} */
     322                 : 
     323                 : /* {{{ STATUS http_get_request_body(char **, size_t *) */
     324                 : PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC)
     325               0 : {
     326               0 :         *length = 0;
     327               0 :         *body = NULL;
     328                 :         
     329               0 :         if (SG(request_info).raw_post_data) {
     330               0 :                 *length = SG(request_info).raw_post_data_length;
     331               0 :                 *body = SG(request_info).raw_post_data;
     332                 :                 
     333               0 :                 if (dup) {
     334               0 :                         *body = estrndup(*body, *length);
     335                 :                 }
     336               0 :                 return SUCCESS;
     337               0 :         } else if (sapi_module.read_post && !HTTP_G->read_post_data) {
     338                 :                 char buf[4096];
     339                 :                 int len;
     340                 :                 
     341               0 :                 HTTP_G->read_post_data = 1;
     342                 :                 
     343               0 :                 while (0 < (len = sapi_module.read_post(buf, sizeof(buf) TSRMLS_CC))) {
     344               0 :                         *body = erealloc(*body, *length + len + 1);
     345               0 :                         memcpy(*body + *length, buf, len);
     346               0 :                         *length += len;
     347               0 :                         (*body)[*length] = '\0';
     348                 :                 }
     349                 :                 
     350                 :                 /* check for error */
     351               0 :                 if (len < 0) {
     352               0 :                         STR_FREE(*body);
     353               0 :                         *length = 0;
     354               0 :                         return FAILURE;
     355                 :                 }
     356                 :                 
     357               0 :                 SG(request_info).raw_post_data = *body;
     358               0 :                 SG(request_info).raw_post_data_length = *length;
     359                 :                 
     360               0 :                 if (dup) {
     361               0 :                         *body = estrndup(*body, *length);
     362                 :                 }
     363               0 :                 return SUCCESS;
     364                 :         }
     365                 :         
     366               0 :         return FAILURE;
     367                 : }
     368                 : /* }}} */
     369                 : 
     370                 : /* {{{ php_stream *http_get_request_body_stream(void) */
     371                 : PHP_HTTP_API php_stream *_http_get_request_body_stream(TSRMLS_D)
     372               0 : {
     373               0 :         php_stream *s = NULL;
     374                 :         
     375               0 :         if (SG(request_info).raw_post_data) {
     376               0 :                 s = php_stream_open_wrapper("php://input", "rb", 0, NULL);
     377               0 :         } else if (sapi_module.read_post && !HTTP_G->read_post_data) {
     378               0 :                 HTTP_G->read_post_data = 1;
     379                 :                 
     380               0 :                 if ((s = php_stream_temp_new())) {
     381                 :                         char buf[4096];
     382                 :                         int len;
     383                 :                         
     384               0 :                         while (0 < (len = sapi_module.read_post(buf, sizeof(buf) TSRMLS_CC))) {
     385               0 :                                 php_stream_write(s, buf, len);
     386                 :                         }
     387                 :                         
     388               0 :                         if (len < 0) {
     389               0 :                                 php_stream_close(s);
     390               0 :                                 s = NULL;
     391                 :                         } else {
     392               0 :                                 php_stream_rewind(s);
     393                 :                         }
     394                 :                 }
     395                 :         }
     396                 :         
     397               0 :         return s;
     398                 : }
     399                 : /* }}} */
     400                 : 
     401                 : /* {{{ void http_parse_params_default_callback(...) */
     402                 : PHP_HTTP_API void _http_parse_params_default_callback(void *arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
     403              11 : {
     404                 :         char *kdup;
     405                 :         zval tmp, *entry;
     406              11 :         HashTable *ht = (HashTable *) arg;
     407                 :         
     408              11 :         if (ht) {
     409              11 :                 INIT_ZARR(tmp, ht);
     410                 :                 
     411              11 :                 if (vallen) {
     412               5 :                         MAKE_STD_ZVAL(entry);
     413               5 :                         array_init(entry);
     414               5 :                         if (keylen) {
     415               5 :                                 kdup = estrndup(key, keylen);
     416               5 :                                 add_assoc_stringl_ex(entry, kdup, keylen + 1, (char *) val, vallen, 1);
     417               5 :                                 efree(kdup);
     418                 :                         } else {
     419               0 :                                 add_next_index_stringl(entry, (char *) val, vallen, 1);
     420                 :                         }
     421               5 :                         add_next_index_zval(&tmp, entry);
     422                 :                 } else {
     423               6 :                         add_next_index_stringl(&tmp, (char *) key, keylen, 1);
     424                 :                 }
     425                 :         }
     426              11 : }
     427                 : /* }}} */
     428                 : 
     429                 : /* {{{ STATUS http_parse_params(const char *, HashTable *) */
     430                 : PHP_HTTP_API STATUS _http_parse_params_ex(const char *param, int flags, http_parse_params_callback cb, void *cb_arg TSRMLS_DC)
     431              41 : {
     432                 : #define ST_QUOTE        1
     433                 : #define ST_VALUE        2
     434                 : #define ST_KEY          3
     435                 : #define ST_ASSIGN       4
     436                 : #define ST_ADD          5
     437                 :         
     438              41 :         int st = ST_KEY, keylen = 0, vallen = 0;
     439              41 :         char *s, *c, *key = NULL, *val = NULL;
     440                 :         
     441              41 :         for(c = s = estrdup(param);;) {
     442             910 :         continued:
     443                 : #if 0
     444                 :         {
     445                 :                 char *tk = NULL, *tv = NULL;
     446                 :                 
     447                 :                 if (key) {
     448                 :                         if (keylen) {
     449                 :                                 tk= estrndup(key, keylen);
     450                 :                         } else {
     451                 :                                 tk = ecalloc(1, 7);
     452                 :                                 memcpy(tk, key, 3);
     453                 :                                 tk[3]='.'; tk[4]='.'; tk[5]='.';
     454                 :                         }
     455                 :                 }
     456                 :                 if (val) {
     457                 :                         if (vallen) {
     458                 :                                 tv = estrndup(val, vallen);
     459                 :                         } else {
     460                 :                                 tv = ecalloc(1, 7);
     461                 :                                 memcpy(tv, val, 3);
     462                 :                                 tv[3]='.'; tv[4]='.'; tv[5]='.';
     463                 :                         }
     464                 :                 }
     465                 :                 fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
     466                 :                                 (
     467                 :                                                 st == ST_QUOTE ? "QUOTE" :
     468                 :                                                 st == ST_VALUE ? "VALUE" :
     469                 :                                                 st == ST_KEY ? "KEY" :
     470                 :                                                 st == ST_ASSIGN ? "ASSIGN" :
     471                 :                                                 st == ST_ADD ? "ADD":
     472                 :                                                 "HUH?"
     473                 :                                 ), *c?*c:'0', tk, tv
     474                 :                 );
     475                 :                 STR_FREE(tk); STR_FREE(tv);
     476                 :         }
     477                 : #endif
     478             910 :                 switch (st) {
     479                 :                         case ST_QUOTE:
     480              61 :                         quote:
     481              61 :                                 if (*c == '"') {
     482              14 :                                         if (*(c-1) == '\\') {
     483               2 :                                                 memmove(c-1, c, strlen(c)+1);
     484               2 :                                                 goto quote;
     485                 :                                         } else {
     486              12 :                                                 goto add;
     487                 :                                         }
     488                 :                                 } else {
     489              47 :                                         if (!val) {
     490              14 :                                                 val = c;
     491                 :                                         }
     492              47 :                                         if (!*c) {
     493               3 :                                                 --val;
     494               3 :                                                 st = ST_ADD;
     495                 :                                         }
     496                 :                                 }
     497              47 :                                 break;
     498                 :                                 
     499                 :                         case ST_VALUE:
     500             474 :                                 switch (*c) {
     501                 :                                         case '"':
     502              16 :                                                 if (!val) {
     503              15 :                                                         st = ST_QUOTE;
     504                 :                                                 }
     505              16 :                                                 break;
     506                 :                                         
     507                 :                                         case ' ':
     508              31 :                                                 break;
     509                 :                                         
     510                 :                                         case ';':
     511                 :                                         case '\0':
     512              31 :                                                 goto add;
     513                 :                                                 break;
     514                 :                                         case ',':
     515               3 :                                                 if (flags & HTTP_PARAMS_ALLOW_COMMA) {
     516               0 :                                                         goto add;
     517                 :                                                 }
     518                 :                                         default:
     519             396 :                                                 if (!val) {
     520              24 :                                                         val = c;
     521                 :                                                 }
     522                 :                                                 break;
     523                 :                                 }
     524             443 :                                 break;
     525                 :                                 
     526                 :                         case ST_KEY:
     527             358 :                                 switch (*c) {
     528                 :                                         case ',':
     529               2 :                                                 if (flags & HTTP_PARAMS_ALLOW_COMMA) {
     530               2 :                                                         goto allow_comma;
     531                 :                                                 }
     532                 :                                         case '\r':
     533                 :                                         case '\n':
     534                 :                                         case '\t':
     535                 :                                         case '\013':
     536                 :                                         case '\014':
     537               0 :                                                 goto failure;
     538                 :                                                 break;
     539                 :                                         
     540                 :                                         case '=':
     541              41 :                                                 if (key) {
     542              41 :                                                         keylen = c - key;
     543              41 :                                                         st = ST_VALUE;
     544                 :                                                 } else {
     545               0 :                                                         goto failure;
     546                 :                                                 }
     547              41 :                                                 break;
     548                 :                                         
     549                 :                                         case ' ':
     550              28 :                                                 if (key) {
     551               8 :                                                         keylen = c - key;
     552               8 :                                                         st = ST_ASSIGN;
     553                 :                                                 }
     554              28 :                                                 break;
     555                 :                                         
     556                 :                                         case ';':
     557                 :                                         case '\0':
     558              33 :                                         allow_comma:
     559              33 :                                                 if (key) {
     560               9 :                                                         keylen = c-- - key;
     561               9 :                                                         st = ST_ADD;
     562                 :                                                 }
     563              33 :                                                 break;
     564                 :                                         
     565                 :                                         default:
     566             256 :                                                 if (!key) {
     567              58 :                                                         key = c;
     568                 :                                                 }
     569                 :                                                 break;
     570                 :                                 }
     571             358 :                                 break;
     572                 :                                 
     573                 :                         case ST_ASSIGN:
     574               8 :                                 if (*c == '=') {
     575               5 :                                         st = ST_VALUE;
     576               6 :                                 } else if (!*c || *c == ';' || ((flags & HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) {
     577               3 :                                         st = ST_ADD;
     578               0 :                                 } else if (*c != ' ') {
     579               0 :                                         goto failure;
     580                 :                                 }
     581               8 :                                 break;
     582                 :                                 
     583                 :                         case ST_ADD:
     584              58 :                         add:
     585              58 :                                 if (val) {
     586              38 :                                         vallen = c - val;
     587              38 :                                         if (st != ST_QUOTE) {
     588              27 :                                                 while (val[vallen-1] == ' ') --vallen;
     589                 :                                         }
     590                 :                                 } else {
     591              20 :                                         val = "";
     592              20 :                                         vallen = 0;
     593                 :                                 }
     594                 :                                 
     595              58 :                                 cb(cb_arg, key, keylen, val, vallen TSRMLS_CC);
     596                 :                                 
     597              58 :                                 st = ST_KEY;
     598              58 :                                 key = val = NULL;
     599              58 :                                 keylen = vallen = 0;
     600                 :                                 break;
     601                 :                 }
     602             914 :                 if (*c) {
     603             869 :                         ++c;
     604              45 :                 } else if (st == ST_ADD) {
     605               4 :                         goto add;
     606                 :                 } else {
     607              41 :                         break;
     608                 :                 }
     609             869 :         }
     610                 :         
     611              41 :         efree(s);
     612              41 :         return SUCCESS;
     613                 :         
     614               0 : failure:
     615               0 :         if (flags & HTTP_PARAMS_RAISE_ERROR) {
     616               0 :                 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
     617                 :         }
     618               0 :         if (flags & HTTP_PARAMS_ALLOW_FAILURE) {
     619               0 :                 if (st == ST_KEY) {
     620               0 :                         if (key) {
     621               0 :                                 keylen = c - key;
     622                 :                         } else {
     623               0 :                                 key = c;
     624                 :                         }
     625                 :                 } else {
     626               0 :                         --c;
     627                 :                 }
     628               0 :                 st = ST_ADD;
     629               0 :                 goto continued;
     630                 :         }
     631               0 :         efree(s);
     632               0 :         return FAILURE;
     633                 : }
     634                 : /* }}} */
     635                 : 
     636                 : /* {{{ array_join */
     637                 : int apply_array_append_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
     638               0 : {
     639                 :         int flags;
     640               0 :         char *key = NULL;
     641                 :         HashTable *dst;
     642               0 :         zval **data = NULL, **value = (zval **) pDest;
     643                 :         
     644               0 :         dst = va_arg(args, HashTable *);
     645               0 :         flags = va_arg(args, int);
     646                 :         
     647               0 :         if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
     648               0 :                 if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
     649               0 :                         key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
     650               0 :                         zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data);
     651                 :                 } else {
     652               0 :                         zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data);
     653                 :                 }
     654                 :                 
     655               0 :                 ZVAL_ADDREF(*value);
     656               0 :                 if (data) {
     657               0 :                         if (Z_TYPE_PP(data) != IS_ARRAY) {
     658               0 :                                 convert_to_array(*data);
     659                 :                         }
     660               0 :                         add_next_index_zval(*data, *value);
     661               0 :                 } else if (key) {
     662               0 :                         zend_hash_add(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL);
     663                 :                 } else {
     664               0 :                         zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL);
     665                 :                 }
     666                 :                 
     667               0 :                 if (key) {
     668               0 :                         efree(key);
     669                 :                 }
     670                 :         }
     671                 :         
     672               0 :         return ZEND_HASH_APPLY_KEEP;
     673                 : }
     674                 : 
     675                 : int apply_array_merge_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
     676             266 : {
     677                 :         int flags;
     678             266 :         char *key = NULL;
     679                 :         HashTable *dst;
     680             266 :         zval **value = (zval **) pDest;
     681                 :         
     682             266 :         dst = va_arg(args, HashTable *);
     683             266 :         flags = va_arg(args, int);
     684                 :         
     685             266 :         if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
     686             266 :                 ZVAL_ADDREF(*value);
     687             270 :                 if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
     688               4 :                         key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
     689               4 :                         zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL);
     690               4 :                         efree(key);
     691                 :                 } else {
     692             262 :                         zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL);
     693                 :                 }
     694                 :         }
     695                 :         
     696             266 :         return ZEND_HASH_APPLY_KEEP;
     697                 : }
     698                 : /* }}} */
     699                 : 
     700                 : /*
     701                 :  * Local variables:
     702                 :  * tab-width: 4
     703                 :  * c-basic-offset: 4
     704                 :  * End:
     705                 :  * vim600: noet sw=4 ts=4 fdm=marker
     706                 :  * vim<600: noet sw=4 ts=4
     707                 :  */
     708                 : 

Generated by: LTP GCOV extension version 1.5