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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 static int php_http_negotiate_sort(const void *first
, const void *second
)
17 Bucket
*b1
= (Bucket
*) first
, *b2
= (Bucket
*) second
;
18 int result
= numeric_compare_function(&b1
->val
, &b2
->val
);
20 return (result
> 0 ? -1 : (result
< 0 ? 1 : 0));
28 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
)
30 unsigned match
= M_NOT
;
32 if (param_len
== supported_len
&& !strncasecmp(param_str
, supported_str
, param_len
)) {
35 } else if (sep_str
&& sep_len
) {
36 const char *param_sec
= php_http_locate_str(param_str
, param_len
, sep_str
, sep_len
);
37 size_t param_pri_len
= param_sec
? param_sec
- param_str
: param_len
;
38 const char *supported_sec
= php_http_locate_str(supported_str
, supported_len
, sep_str
, sep_len
);
39 size_t supported_pri_len
= supported_sec
? supported_sec
- supported_str
: supported_len
;
40 size_t cmp_len
= MIN(param_pri_len
, supported_pri_len
);
42 if (((*param_str
== '*') || (*supported_str
== '*'))
43 || ((param_pri_len
== supported_pri_len
) && !strncasecmp(param_str
, supported_str
, param_pri_len
))
44 || ((!param_sec
|| !supported_sec
) && cmp_len
&& !strncasecmp(param_str
, supported_str
, cmp_len
))
49 if (param_sec
&& supported_sec
&& !strcasecmp(param_sec
, supported_sec
)) {
53 if ((param_sec
&& *(param_sec
+ sep_len
) == '*')
54 || (supported_sec
&& *(supported_sec
+ sep_len
) == '*')
55 || ((*param_str
== '*') || (*supported_str
== '*'))
61 fprintf(stderr
, "match: %s == %s => %u\n", supported_str
, param_str
, match
);
65 static int php_http_negotiate_reduce(zval
*p
, int num_args
, va_list args
, zend_hash_key
*hash_key
)
67 unsigned best_match
= 0;
68 php_http_arrkey_t key
;
69 zval
*value
, *q
= NULL
;
70 zend_string
*supported
= zval_get_string(p
);
71 HashTable
*params
= va_arg(args
, HashTable
*);
72 HashTable
*result
= va_arg(args
, HashTable
*);
73 const char *sep_str
= va_arg(args
, const char *);
74 size_t sep_len
= va_arg(args
, size_t);
76 ZEND_HASH_FOREACH_KEY_VAL(params
, key
.h
, key
.key
, value
)
80 php_http_arrkey_stringify(&key
, NULL
);
81 match
= php_http_negotiate_match(key
.key
->val
, key
.key
->len
, supported
->val
, supported
->len
, sep_str
, sep_len
);
83 if (match
> best_match
) {
87 php_http_arrkey_dtor(&key
);
89 ZEND_HASH_FOREACH_END();
91 if (q
&& Z_DVAL_P(q
) > 0) {
93 zend_hash_update(result
, supported
, q
);
96 zend_string_release(supported
);
97 return ZEND_HASH_APPLY_KEEP
;
100 HashTable
*php_http_negotiate(const char *value_str
, size_t value_len
, HashTable
*supported
, const char *primary_sep_str
, size_t primary_sep_len
)
102 HashTable
*result
= NULL
;
104 if (value_str
&& value_len
) {
106 zval arr
, *val
, *arg
, *zq
;
108 php_http_arrkey_t key
;
109 php_http_params_opts_t opts
;
111 zend_hash_init(¶ms
, 10, NULL
, ZVAL_PTR_DTOR
, 0);
112 php_http_params_opts_default_get(&opts
);
113 opts
.input
.str
= estrndup(value_str
, value_len
);
114 opts
.input
.len
= value_len
;
115 php_http_params_parse(¶ms
, &opts
);
116 efree(opts
.input
.str
);
120 ZEND_HASH_FOREACH_KEY_VAL(¶ms
, key
.h
, key
.key
, val
)
124 if ((arg
= zend_hash_str_find(Z_ARRVAL_P(val
), ZEND_STRL("arguments")))
125 && (IS_ARRAY
== Z_TYPE_P(arg
))
126 && (zq
= zend_hash_str_find(Z_ARRVAL_P(arg
), ZEND_STRL("q")))) {
127 q
= zval_get_double(zq
);
129 q
= 1.0 - ++i
/ 100.0;
133 fprintf(stderr
, "Q: %s=%1.3f\n", key
.key
->val
, q
);
137 add_assoc_double_ex(&arr
, key
.key
->val
, key
.key
->len
, q
);
139 add_index_double(&arr
, key
.h
, q
);
143 ZEND_HASH_FOREACH_END();
146 zend_print_zval_r(&arr
, 1);
149 ALLOC_HASHTABLE(result
);
150 zend_hash_init(result
, zend_hash_num_elements(supported
), NULL
, ZVAL_PTR_DTOR
, 0);
151 zend_hash_apply_with_arguments(supported
, php_http_negotiate_reduce
, 4, Z_ARRVAL(arr
), result
, primary_sep_str
, primary_sep_len
);
152 zend_hash_destroy(¶ms
);
154 zend_hash_sort(result
, php_http_negotiate_sort
, 0);
167 * vim600: noet sw=4 ts=4 fdm=marker
168 * vim<600: noet sw=4 ts=4