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