#include "php_http_api.h"
+#ifndef PHP_HTTP_DEBUG_NEG
+# define PHP_HTTP_DEBUG_NEG 0
+#endif
+
static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC)
{
zval result, *first, *second;
#define M_PRI 5
#define M_SEC 2
-#define M_ANY 1
+#define M_ANY -1
#define M_NOT 0
-#define M_ALL -1
+#define M_ALL ~0
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)
{
int match = M_NOT;
match += M_PRI;
}
- if (param_sec && supported_sec && !strcasecmp(param_sec, supported_sec)) {
+ if (param_sec && supported_sec
+ && ((*(param_sec + sep_len) == '*' || *(supported_sec + sep_len) == '*')
+ || !strcasecmp(param_sec, supported_sec)
+ )
+ ) {
match += M_SEC;
}
match += M_ANY;
}
}
-#if 0
+#if PHP_HTTP_DEBUG_NEG
fprintf(stderr, "match: %s == %s => %u\n", supported_str, param_str, match);
#endif
return match;
static int php_http_negotiate_reduce(void *p TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
{
unsigned best_match = 0;
+ double q = 0;
HashPosition pos;
php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
- zval **q = NULL, **val, *supported = php_http_ztyp(IS_STRING, *(zval **)p);
+ zval **val, *supported = php_http_ztyp(IS_STRING, *(zval **)p);
HashTable *params = va_arg(args, HashTable *);
HashTable *result = va_arg(args, HashTable *);
const char *sep_str = va_arg(args, const char *);
FOREACH_HASH_KEYVAL(pos, params, key, val) {
if (key.type == HASH_KEY_IS_STRING) {
unsigned match = php_http_negotiate_match(key.str, key.len-1, Z_STRVAL_P(supported), Z_STRLEN_P(supported), sep_str, sep_len);
-
+#if PHP_HTTP_DEBUG_NEG
+ fprintf(stderr, "match(%u) > best_match(%u) = %u (q=%f)\n", match, best_match, match>best_match, Z_DVAL_PP(val));
+#endif
if (match > best_match) {
best_match = match;
- q = val;
+ q = Z_DVAL_PP(val) - 0.1 / match;
}
}
}
- if (q && Z_DVAL_PP(q) > 0) {
- Z_ADDREF_PP(q);
- zend_hash_update(result, Z_STRVAL_P(supported), Z_STRLEN_P(supported) + 1, (void *) q, sizeof(zval *), NULL);
+ if (q > 0) {
+ zval *tmp;
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_DOUBLE(tmp, q);
+ zend_hash_update(result, Z_STRVAL_P(supported), Z_STRLEN_P(supported) + 1, (void *) &tmp, sizeof(zval *), NULL);
}
zval_ptr_dtor(&supported);
q = Z_DVAL_P(tmp);
zval_ptr_dtor(&tmp);
} else {
- q = 1.0 - ++i / 100.0;
+ q = 1.0 - (((double) ++i) / 100.0);
}
if (key.type == HASH_KEY_IS_STRING) {
PTR_FREE(key.str);
}
-#if 0
+#if PHP_HTTP_DEBUG_NEG
zend_print_zval_r(&arr, 1 TSRMLS_CC);
#endif
echo "Test\n";
+function r($v) { return round($v, 2); }
+
$a = new http\Header("Accept", "text/html, text/plain;q=0.5, */*;q=0");
var_dump("text/html" === $a->negotiate(array("text/plain","text/html")));
var_dump("text/html" === $a->negotiate(array("text/plain","text/html"), $rs));
-var_dump(array("text/html"=>0.99, "text/plain"=>0.5) === $rs);
+var_dump(array("text/html"=>0.99, "text/plain"=>0.5) === array_map("r", $rs));
var_dump("text/plain" === $a->negotiate(array("foo/bar", "text/plain"), $rs));
-var_dump(array("text/plain"=>0.5) === $rs);
+var_dump(array("text/plain"=>0.5) === array_map("r", $rs));
var_dump("foo/bar" === $a->negotiate(array("foo/bar"), $rs));
var_dump(array() === $rs);