4e34ee3f1d5b08dce441d1159853d56be955c41a
[m6w6/ext-http] / php_http_params.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.h"
14
15 PHP_HTTP_API void php_http_params_parse_default_func(void *arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
16 {
17 zval tmp, *entry;
18 HashTable *ht = (HashTable *) arg;
19
20 if (ht) {
21 INIT_PZVAL_ARRAY(&tmp, ht);
22
23 if (vallen) {
24 MAKE_STD_ZVAL(entry);
25 array_init(entry);
26 if (keylen) {
27 add_assoc_stringl_ex(entry, key, keylen + 1, estrndup(val, vallen), vallen, 0);
28 } else {
29 add_next_index_stringl(entry, val, vallen, 1);
30 }
31 add_next_index_zval(&tmp, entry);
32 } else {
33 add_next_index_stringl(&tmp, key, keylen, 1);
34 }
35 }
36 }
37
38 PHP_HTTP_API STATUS php_http_params_parse(const char *param, int flags, php_http_params_parse_func_t cb, void *cb_arg TSRMLS_DC)
39 {
40 #define ST_QUOTE 1
41 #define ST_VALUE 2
42 #define ST_KEY 3
43 #define ST_ASSIGN 4
44 #define ST_ADD 5
45
46 int st = ST_KEY, keylen = 0, vallen = 0;
47 char *s, *c, *key = NULL, *val = NULL;
48
49 if (!cb) {
50 cb = php_http_params_parse_default_func;
51 }
52
53 for(c = s = estrdup(param);;) {
54 continued:
55 #if 0
56 {
57 char *tk = NULL, *tv = NULL;
58
59 if (key) {
60 if (keylen) {
61 tk= estrndup(key, keylen);
62 } else {
63 tk = ecalloc(1, 7);
64 memcpy(tk, key, 3);
65 tk[3]='.'; tk[4]='.'; tk[5]='.';
66 }
67 }
68 if (val) {
69 if (vallen) {
70 tv = estrndup(val, vallen);
71 } else {
72 tv = ecalloc(1, 7);
73 memcpy(tv, val, 3);
74 tv[3]='.'; tv[4]='.'; tv[5]='.';
75 }
76 }
77 fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
78 (
79 st == ST_QUOTE ? "QUOTE" :
80 st == ST_VALUE ? "VALUE" :
81 st == ST_KEY ? "KEY" :
82 st == ST_ASSIGN ? "ASSIGN" :
83 st == ST_ADD ? "ADD":
84 "HUH?"
85 ), *c?*c:'0', tk, tv
86 );
87 STR_FREE(tk); STR_FREE(tv);
88 }
89 #endif
90 switch (st) {
91 case ST_QUOTE:
92 quote:
93 if (*c == '"') {
94 if (*(c-1) == '\\') {
95 memmove(c-1, c, strlen(c)+1);
96 goto quote;
97 } else {
98 goto add;
99 }
100 } else {
101 if (!val) {
102 val = c;
103 }
104 if (!*c) {
105 --val;
106 st = ST_ADD;
107 }
108 }
109 break;
110
111 case ST_VALUE:
112 switch (*c) {
113 case '"':
114 if (!val) {
115 st = ST_QUOTE;
116 }
117 break;
118
119 case ' ':
120 break;
121
122 case ';':
123 case '\0':
124 goto add;
125 break;
126 case ',':
127 if (flags & PHP_HTTP_PARAMS_ALLOW_COMMA) {
128 goto add;
129 }
130 /* fallthrough */
131 default:
132 if (!val) {
133 val = c;
134 }
135 break;
136 }
137 break;
138
139 case ST_KEY:
140 switch (*c) {
141 case ',':
142 if (flags & PHP_HTTP_PARAMS_ALLOW_COMMA) {
143 goto allow_comma;
144 }
145 /* fallthrough */
146 case '\r':
147 case '\n':
148 case '\t':
149 case '\013':
150 case '\014':
151 goto failure;
152 break;
153
154 case ' ':
155 if (key) {
156 keylen = c - key;
157 st = ST_ASSIGN;
158 }
159 break;
160
161 case ';':
162 case '\0':
163 allow_comma:
164 if (key) {
165 keylen = c-- - key;
166 st = ST_ADD;
167 }
168 break;
169
170 case ':':
171 if (!(flags & PHP_HTTP_PARAMS_COLON_SEPARATOR)) {
172 goto not_separator;
173 }
174 if (key) {
175 keylen = c - key;
176 st = ST_VALUE;
177 } else {
178 goto failure;
179 }
180 break;
181
182 case '=':
183 if (flags & PHP_HTTP_PARAMS_COLON_SEPARATOR) {
184 goto not_separator;
185 }
186 if (key) {
187 keylen = c - key;
188 st = ST_VALUE;
189 } else {
190 goto failure;
191 }
192 break;
193
194 default:
195 not_separator:
196 if (!key) {
197 key = c;
198 }
199 break;
200 }
201 break;
202
203 case ST_ASSIGN:
204 if (*c == '=') {
205 st = ST_VALUE;
206 } else if (!*c || *c == ';' || ((flags & PHP_HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) {
207 st = ST_ADD;
208 } else if (*c != ' ') {
209 goto failure;
210 }
211 break;
212
213 case ST_ADD:
214 add:
215 if (val) {
216 vallen = c - val;
217 if (st != ST_QUOTE) {
218 while (val[vallen-1] == ' ') --vallen;
219 }
220 } else {
221 val = "";
222 vallen = 0;
223 }
224
225 cb(cb_arg, key, keylen, val, vallen TSRMLS_CC);
226
227 st = ST_KEY;
228 key = val = NULL;
229 keylen = vallen = 0;
230 break;
231 }
232 if (*c) {
233 ++c;
234 } else if (st == ST_ADD) {
235 goto add;
236 } else {
237 break;
238 }
239 }
240
241 efree(s);
242 return SUCCESS;
243
244 failure:
245 if (flags & PHP_HTTP_PARAMS_RAISE_ERROR) {
246 php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
247 }
248 if (flags & PHP_HTTP_PARAMS_ALLOW_FAILURE) {
249 if (st == ST_KEY) {
250 if (key) {
251 keylen = c - key;
252 } else {
253 key = c;
254 }
255 } else {
256 --c;
257 }
258 st = ST_ADD;
259 goto continued;
260 }
261 efree(s);
262 return FAILURE;
263 }
264
265
266 /*
267 * Local variables:
268 * tab-width: 4
269 * c-basic-offset: 4
270 * End:
271 * vim600: noet sw=4 ts=4 fdm=marker
272 * vim<600: noet sw=4 ts=4
273 */
274