negotiation test & fixes
[m6w6/ext-http] / php_http_negotiate.c
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-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC)
16 {
17 zval result, *first, *second;
18
19 first = *((zval **) (*((Bucket **) a))->pData);
20 second= *((zval **) (*((Bucket **) b))->pData);
21
22 if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
23 return 0;
24 }
25 return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
26 }
27
28 static int php_http_negotiate_reduce(void *p TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
29 {
30 char *tmp;
31 zval **q, *supported = php_http_ztyp(IS_STRING, *(zval **)p);
32 HashTable *params = va_arg(args, HashTable *);
33 HashTable *result = va_arg(args, HashTable *);
34
35 tmp = php_strtolower(estrndup(Z_STRVAL_P(supported), Z_STRLEN_P(supported)), Z_STRLEN_P(supported));
36 if (SUCCESS == zend_symtable_find(params, tmp, Z_STRLEN_P(supported) + 1, (void *) &q)) {
37 Z_ADDREF_PP(q);
38 zend_symtable_update(result, Z_STRVAL_P(supported), Z_STRLEN_P(supported) + 1, (void *) q, sizeof(zval *), NULL);
39 }
40 efree(tmp);
41 zval_ptr_dtor(&supported);
42 return ZEND_HASH_APPLY_KEEP;
43 }
44
45 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)
46 {
47 HashTable *result = NULL;
48
49 if (value_str && value_len) {
50 unsigned i = 0;
51 zval arr, **val, **arg, **zq;
52 HashPosition pos;
53 HashTable params;
54 php_http_array_hashkey_t key = php_http_array_hashkey_init(1);
55 php_http_params_opts_t opts;
56
57 zend_hash_init(&params, 10, NULL, ZVAL_PTR_DTOR, 0);
58 php_http_params_opts_default_get(&opts);
59 opts.input.str = estrndup(value_str, value_len);
60 opts.input.len = value_len;
61 php_http_params_parse(&params, &opts TSRMLS_CC);
62 efree(opts.input.str);
63
64 INIT_PZVAL(&arr);
65 array_init(&arr);
66
67 FOREACH_HASH_KEYVAL(pos, &params, key, val) {
68 double q;
69
70 if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("arguments"), (void *) &arg)
71 && IS_ARRAY == Z_TYPE_PP(arg)
72 && SUCCESS == zend_hash_find(Z_ARRVAL_PP(arg), ZEND_STRS("q"), (void *) &zq)) {
73 zval *tmp = php_http_ztyp(IS_DOUBLE, *zq);
74
75 q = Z_DVAL_P(tmp);
76 zval_ptr_dtor(&tmp);
77
78 if (!q) {
79 STR_FREE(key.str);
80 continue;
81 }
82 } else {
83 q = 1.0 - ++i / 100.0;
84 }
85
86 if (key.type == HASH_KEY_IS_STRING) {
87 const char *ptr;
88
89 php_strtolower(key.str, key.len - 1);
90 add_assoc_double_ex(&arr, key.str, key.len, q);
91
92 if (primary_sep_str && primary_sep_len && (ptr = php_http_locate_str(key.str, key.len - 1, primary_sep_str, primary_sep_len))) {
93 key.str[ptr - key.str] = '\0';
94 add_assoc_double_ex(&arr, key.str, ptr - key.str + 1, q - i / 1000.0);
95 }
96 } else {
97 add_index_double(&arr, key.num, q);
98 }
99
100 STR_FREE(key.str);
101 }
102
103 ALLOC_HASHTABLE(result);
104 zend_hash_init(result, zend_hash_num_elements(supported), NULL, ZVAL_PTR_DTOR, 0);
105 zend_hash_apply_with_arguments(supported TSRMLS_CC, php_http_negotiate_reduce, 2, Z_ARRVAL(arr), result);
106 zend_hash_destroy(&params);
107 zval_dtor(&arr);
108 zend_hash_sort(result, zend_qsort, php_http_negotiate_sort, 0 TSRMLS_CC);
109 }
110
111 return result;
112 }
113
114
115
116 /*
117 * Local variables:
118 * tab-width: 4
119 * c-basic-offset: 4
120 * End:
121 * vim600: noet sw=4 ts=4 fdm=marker
122 * vim<600: noet sw=4 ts=4
123 */
124
125