2 +--------------------------------------------------------------------+
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-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 static int php_http_negotiate_sort(const void *a
, const void *b TSRMLS_DC
)
17 zval result
, *first
, *second
;
19 first
= *((zval
**) (*((Bucket
**) a
))->pData
);
20 second
= *((zval
**) (*((Bucket
**) b
))->pData
);
22 if (numeric_compare_function(&result
, first
, second TSRMLS_CC
) != SUCCESS
) {
25 return (Z_LVAL(result
) > 0 ? -1 : (Z_LVAL(result
) < 0 ? 1 : 0));
33 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
)
37 if (param_len
== supported_len
&& !strncasecmp(param_str
, supported_str
, param_len
)) {
40 } else if (sep_str
&& sep_len
) {
41 const char *param_sec
= php_http_locate_str(param_str
, param_len
, sep_str
, sep_len
);
42 size_t param_pri_len
= param_sec
? param_sec
- param_str
: param_len
;
43 const char *supported_sec
= php_http_locate_str(supported_str
, supported_len
, sep_str
, sep_len
);
44 size_t supported_pri_len
= supported_sec
? supported_sec
- supported_str
: supported_len
;
45 size_t cmp_len
= MIN(param_pri_len
, supported_pri_len
);
47 if (((*param_str
== '*') || (*supported_str
== '*'))
48 || ((param_pri_len
== supported_pri_len
) && !strncasecmp(param_str
, supported_str
, param_pri_len
))
49 || ((!param_sec
|| !supported_sec
) && cmp_len
&& !strncasecmp(param_str
, supported_str
, cmp_len
))
54 if (param_sec
&& supported_sec
&& !strcasecmp(param_sec
, supported_sec
)) {
58 if ((param_sec
&& *(param_sec
+ sep_len
) == '*')
59 || (supported_sec
&& *(supported_sec
+ sep_len
) == '*')
60 || ((*param_str
== '*') || (*supported_str
== '*'))
66 fprintf(stderr
, "match: %s == %s => %u\n", supported_str
, param_str
, match
);
71 static int php_http_negotiate_reduce(void *p TSRMLS_DC
, int num_args
, va_list args
, zend_hash_key
*hash_key
)
73 unsigned best_match
= 0;
75 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
76 zval
**q
= NULL
, **val
, *supported
= php_http_ztyp(IS_STRING
, *(zval
**)p
);
77 HashTable
*params
= va_arg(args
, HashTable
*);
78 HashTable
*result
= va_arg(args
, HashTable
*);
79 const char *sep_str
= va_arg(args
, const char *);
80 size_t sep_len
= va_arg(args
, size_t);
82 FOREACH_HASH_KEYVAL(pos
, params
, key
, val
) {
83 if (key
.type
== HASH_KEY_IS_STRING
) {
84 unsigned match
= php_http_negotiate_match(key
.str
, key
.len
-1, Z_STRVAL_P(supported
), Z_STRLEN_P(supported
), sep_str
, sep_len
);
86 if (match
> best_match
) {
93 if (q
&& Z_DVAL_PP(q
) > 0) {
95 zend_hash_update(result
, Z_STRVAL_P(supported
), Z_STRLEN_P(supported
) + 1, (void *) q
, sizeof(zval
*), NULL
);
98 zval_ptr_dtor(&supported
);
99 return ZEND_HASH_APPLY_KEEP
;
102 PHP_HTTP_API 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
)
104 HashTable
*result
= NULL
;
106 if (value_str
&& value_len
) {
108 zval arr
, **val
, **arg
, **zq
;
111 php_http_array_hashkey_t key
= php_http_array_hashkey_init(1);
112 php_http_params_opts_t opts
;
114 zend_hash_init(¶ms
, 10, NULL
, ZVAL_PTR_DTOR
, 0);
115 php_http_params_opts_default_get(&opts
);
116 opts
.input
.str
= estrndup(value_str
, value_len
);
117 opts
.input
.len
= value_len
;
118 php_http_params_parse(¶ms
, &opts TSRMLS_CC
);
119 efree(opts
.input
.str
);
124 FOREACH_HASH_KEYVAL(pos
, ¶ms
, key
, val
) {
127 if (SUCCESS
== zend_hash_find(Z_ARRVAL_PP(val
), ZEND_STRS("arguments"), (void *) &arg
)
128 && IS_ARRAY
== Z_TYPE_PP(arg
)
129 && SUCCESS
== zend_hash_find(Z_ARRVAL_PP(arg
), ZEND_STRS("q"), (void *) &zq
)) {
130 zval
*tmp
= php_http_ztyp(IS_DOUBLE
, *zq
);
135 q
= 1.0 - ++i
/ 100.0;
138 if (key
.type
== HASH_KEY_IS_STRING
) {
139 add_assoc_double_ex(&arr
, key
.str
, key
.len
, q
);
141 add_index_double(&arr
, key
.num
, q
);
148 zend_print_zval_r(&arr
, 1 TSRMLS_CC
);
151 ALLOC_HASHTABLE(result
);
152 zend_hash_init(result
, zend_hash_num_elements(supported
), NULL
, ZVAL_PTR_DTOR
, 0);
153 zend_hash_apply_with_arguments(supported TSRMLS_CC
, php_http_negotiate_reduce
, 4, Z_ARRVAL(arr
), result
, primary_sep_str
, primary_sep_len
);
154 zend_hash_destroy(¶ms
);
156 zend_hash_sort(result
, zend_qsort
, php_http_negotiate_sort
, 0 TSRMLS_CC
);
169 * vim600: noet sw=4 ts=4 fdm=marker
170 * vim<600: noet sw=4 ts=4