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