LCOV - code coverage report
Current view: top level - ext/http - php_http_negotiate.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 75 78 96.2 %
Date: 2015-02-17 20:30:22 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     +--------------------------------------------------------------------+
       3             :     | PECL :: http                                                       |
       4             :     +--------------------------------------------------------------------+
       5             :     | Redistribution and use in source and binary forms, with or without |
       6             :     | modification, are permitted provided that the conditions mentioned |
       7             :     | in the accompanying LICENSE file are met.                          |
       8             :     +--------------------------------------------------------------------+
       9             :     | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
      10             :     +--------------------------------------------------------------------+
      11             : */
      12             : 
      13             : #include "php_http_api.h"
      14             : 
      15           9 : static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC)
      16             : {
      17             :         zval result, *first, *second;
      18             : 
      19           9 :         first = *((zval **) (*((Bucket **) a))->pData);
      20           9 :         second= *((zval **) (*((Bucket **) b))->pData);
      21             : 
      22           9 :         if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
      23           0 :                 return 0;
      24             :         }
      25           9 :         return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
      26             : }
      27             : 
      28             : #define M_PRI 5
      29             : #define M_SEC 2
      30             : #define M_ANY 1
      31             : #define M_NOT 0
      32             : #define M_ALL -1
      33         146 : static inline unsigned php_http_negotiate_match(const char *param_str, size_t param_len, const char *supported_str, size_t supported_len, const char *sep_str, size_t sep_len)
      34             : {
      35         146 :         int match = M_NOT;
      36             : 
      37         146 :         if (param_len == supported_len && !strncasecmp(param_str, supported_str, param_len)) {
      38             :                 /* that was easy */
      39          28 :                 match = M_ALL;
      40         118 :         } else if (sep_str && sep_len) {
      41          86 :                 const char *param_sec = php_http_locate_str(param_str, param_len, sep_str, sep_len);
      42          86 :                 size_t param_pri_len = param_sec ? param_sec - param_str : param_len;
      43          86 :                 const char *supported_sec = php_http_locate_str(supported_str, supported_len, sep_str, sep_len);
      44          86 :                 size_t supported_pri_len = supported_sec ? supported_sec - supported_str : supported_len;
      45          86 :                 size_t cmp_len = MIN(param_pri_len, supported_pri_len);
      46             : 
      47          86 :                 if (((*param_str == '*') || (*supported_str == '*'))
      48          69 :                 ||      ((param_pri_len == supported_pri_len) && !strncasecmp(param_str, supported_str, param_pri_len))
      49          41 :                 ||      ((!param_sec || !supported_sec) && cmp_len && !strncasecmp(param_str, supported_str, cmp_len))
      50             :                 ) {
      51          45 :                         match += M_PRI;
      52             :                 }
      53             : 
      54          86 :                 if (param_sec && supported_sec && !strcasecmp(param_sec, supported_sec)) {
      55           0 :                         match += M_SEC;
      56             :                 }
      57             : 
      58          86 :                 if ((param_sec && *(param_sec + sep_len) == '*')
      59          86 :                 ||      (supported_sec && *(supported_sec + sep_len) == '*')
      60          86 :                 ||      ((*param_str == '*') || (*supported_str == '*'))
      61             :                 ) {
      62          17 :                         match += M_ANY;
      63             :                 }
      64             :         }
      65             : #if 0
      66             :         fprintf(stderr, "match: %s == %s => %u\n", supported_str, param_str, match);
      67             : #endif
      68         146 :         return match;
      69             : }
      70             : 
      71          48 : static int php_http_negotiate_reduce(void *p TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
      72             : {
      73          48 :         unsigned best_match = 0;
      74             :         HashPosition pos;
      75          48 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
      76          48 :         zval **q = NULL, **val, *supported = php_http_ztyp(IS_STRING, *(zval **)p);
      77          48 :         HashTable *params = va_arg(args, HashTable *);
      78          48 :         HashTable *result = va_arg(args, HashTable *);
      79          48 :         const char *sep_str = va_arg(args, const char *);
      80          48 :         size_t sep_len = va_arg(args, size_t);
      81             : 
      82         194 :         FOREACH_HASH_KEYVAL(pos, params, key, val) {
      83         146 :                 if (key.type == HASH_KEY_IS_STRING) {
      84         146 :                         unsigned match = php_http_negotiate_match(key.str, key.len-1, Z_STRVAL_P(supported), Z_STRLEN_P(supported), sep_str, sep_len);
      85             : 
      86         146 :                         if (match > best_match) {
      87          48 :                                 best_match = match;
      88          48 :                                 q = val;
      89             :                         }
      90             :                 }
      91             :         }
      92             : 
      93          48 :         if (q && Z_DVAL_PP(q) > 0) {
      94          24 :                 Z_ADDREF_PP(q);
      95          24 :                 zend_hash_update(result, Z_STRVAL_P(supported), Z_STRLEN_P(supported) + 1, (void *) q, sizeof(zval *), NULL);
      96             :         }
      97             : 
      98          48 :         zval_ptr_dtor(&supported);
      99          48 :         return ZEND_HASH_APPLY_KEEP;
     100             : }
     101             : 
     102          19 : HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len TSRMLS_DC)
     103             : {
     104          19 :         HashTable *result = NULL;
     105             : 
     106          19 :         if (value_str && value_len) {
     107          19 :                 unsigned i = 0;
     108             :                 zval arr, **val, **arg, **zq;
     109             :                 HashPosition pos;
     110             :                 HashTable params;
     111          19 :                 php_http_array_hashkey_t key = php_http_array_hashkey_init(1);
     112             :                 php_http_params_opts_t opts;
     113             : 
     114          19 :                 zend_hash_init(&params, 10, NULL, ZVAL_PTR_DTOR, 0);
     115          19 :                 php_http_params_opts_default_get(&opts);
     116          19 :                 opts.input.str = estrndup(value_str, value_len);
     117          19 :                 opts.input.len = value_len;
     118          19 :                 php_http_params_parse(&params, &opts TSRMLS_CC);
     119          19 :                 efree(opts.input.str);
     120             : 
     121          19 :                 INIT_PZVAL(&arr);
     122          19 :                 array_init(&arr);
     123             : 
     124          78 :                 FOREACH_HASH_KEYVAL(pos, &params, key, val) {
     125             :                         double q;
     126             : 
     127          59 :                         if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("arguments"), (void *) &arg)
     128          59 :                         &&      IS_ARRAY == Z_TYPE_PP(arg)
     129          96 :                         &&      SUCCESS == zend_hash_find(Z_ARRVAL_PP(arg), ZEND_STRS("q"), (void *) &zq)) {
     130          37 :                                 zval *tmp = php_http_ztyp(IS_DOUBLE, *zq);
     131             : 
     132          37 :                                 q = Z_DVAL_P(tmp);
     133          37 :                                 zval_ptr_dtor(&tmp);
     134             :                         } else {
     135          22 :                                 q = 1.0 - ++i / 100.0;
     136             :                         }
     137             : 
     138          59 :                         if (key.type == HASH_KEY_IS_STRING) {
     139          59 :                                 add_assoc_double_ex(&arr, key.str, key.len, q);
     140             :                         } else {
     141           0 :                                 add_index_double(&arr, key.num, q);
     142             :                         }
     143             : 
     144          59 :                         PTR_FREE(key.str);
     145             :                 }
     146             : 
     147             : #if 0
     148             :                 zend_print_zval_r(&arr, 1 TSRMLS_CC);
     149             : #endif
     150             : 
     151          19 :                 ALLOC_HASHTABLE(result);
     152          19 :                 zend_hash_init(result, zend_hash_num_elements(supported), NULL, ZVAL_PTR_DTOR, 0);
     153          19 :                 zend_hash_apply_with_arguments(supported TSRMLS_CC, php_http_negotiate_reduce, 4, Z_ARRVAL(arr), result, primary_sep_str, primary_sep_len);
     154          19 :                 zend_hash_destroy(&params);
     155          19 :                 zval_dtor(&arr);
     156          19 :                 zend_hash_sort(result, zend_qsort, php_http_negotiate_sort, 0 TSRMLS_CC);
     157             :         }
     158             :         
     159          19 :         return result;
     160             : }
     161             : 
     162             : 
     163             : 
     164             : /*
     165             :  * Local variables:
     166             :  * tab-width: 4
     167             :  * c-basic-offset: 4
     168             :  * End:
     169             :  * vim600: noet sw=4 ts=4 fdm=marker
     170             :  * vim<600: noet sw=4 ts=4
     171             :  */
     172             : 
     173             : 

Generated by: LCOV version 1.11