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-2007, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : /* $Id: http_api.c,v 1.170 2008/03/12 07:46:32 mike Exp $ */
14 :
15 : #define HTTP_WANT_SAPI
16 : #include "php_http.h"
17 :
18 : #include "php_output.h"
19 : #include "ext/standard/url.h"
20 : #include "ext/standard/php_lcg.h"
21 :
22 : #include "php_http_api.h"
23 : #include "php_http_send_api.h"
24 :
25 : #ifdef ZEND_ENGINE_2
26 : # include "php_http_exception_object.h"
27 : #endif
28 :
29 : PHP_MINIT_FUNCTION(http_support)
30 9669 : {
31 9669 : HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT);
32 9669 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS);
33 9669 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME);
34 9669 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS);
35 9669 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS);
36 9669 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_EVENTS", HTTP_SUPPORT_EVENTS);
37 :
38 9669 : HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA);
39 9669 : HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE);
40 9669 : HTTP_LONG_CONSTANT("HTTP_PARAMS_RAISE_ERROR", HTTP_PARAMS_RAISE_ERROR);
41 9669 : HTTP_LONG_CONSTANT("HTTP_PARAMS_DEFAULT", HTTP_PARAMS_DEFAULT);
42 :
43 9669 : return SUCCESS;
44 : }
45 :
46 : PHP_HTTP_API long _http_support(long feature)
47 12 : {
48 12 : long support = HTTP_SUPPORT;
49 :
50 : #ifdef HTTP_HAVE_CURL
51 12 : support |= HTTP_SUPPORT_REQUESTS;
52 : # ifdef HTTP_HAVE_SSL
53 12 : support |= HTTP_SUPPORT_SSLREQUESTS;
54 : # endif
55 : # ifdef HTTP_HAVE_EVENT
56 : support |= HTTP_SUPPORT_EVENTS;
57 : # endif
58 : #endif
59 : #ifdef HTTP_HAVE_MAGIC
60 12 : support |= HTTP_SUPPORT_MAGICMIME;
61 : #endif
62 : #ifdef HTTP_HAVE_ZLIB
63 12 : support |= HTTP_SUPPORT_ENCODINGS;
64 : #endif
65 :
66 12 : if (feature) {
67 12 : return (feature == (support & feature));
68 : }
69 0 : return support;
70 : }
71 :
72 : /* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
73 : char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
74 915 : {
75 : size_t i;
76 : int wasalpha;
77 :
78 915 : if (key && key_len) {
79 915 : if ((wasalpha = HTTP_IS_CTYPE(alpha, key[0]))) {
80 915 : key[0] = (char) (uctitle ? HTTP_TO_CTYPE(upper, key[0]) : HTTP_TO_CTYPE(lower, key[0]));
81 : }
82 8664 : for (i = 1; i < key_len; i++) {
83 7749 : if (HTTP_IS_CTYPE(alpha, key[i])) {
84 7172 : key[i] = (char) (((!wasalpha) && uctitle) ? HTTP_TO_CTYPE(upper, key[i]) : HTTP_TO_CTYPE(lower, key[i]));
85 7172 : wasalpha = 1;
86 : } else {
87 577 : if (xhyphen && (key[i] == '_')) {
88 5 : key[i] = '-';
89 : }
90 577 : wasalpha = 0;
91 : }
92 : }
93 : }
94 915 : return key;
95 : }
96 : /* }}} */
97 :
98 : /* {{{ http_boundary(char *, size_t) */
99 : size_t _http_boundary(char *buf, size_t buf_len TSRMLS_DC)
100 0 : {
101 0 : return snprintf(buf, buf_len, "%lu%0.9f", (ulong) HTTP_G->request.time, (float) php_combined_lcg(TSRMLS_C));
102 : }
103 : /* }}} */
104 :
105 : /* {{{ void http_error(long, long, char*) */
106 : void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...)
107 18 : {
108 : va_list args;
109 :
110 18 : va_start(args, format);
111 : #ifdef ZEND_ENGINE_2
112 34 : if ((type == E_THROW) || (GLOBAL_ERROR_HANDLING == EH_THROW)) {
113 : char *message;
114 16 : zend_class_entry *ce = http_exception_get_for_code(code);
115 :
116 16 : http_try {
117 16 : vspprintf(&message, 0, format, args);
118 16 : zend_throw_exception(ce, message, code TSRMLS_CC);
119 16 : efree(message);
120 16 : } http_catch(GLOBAL_EXCEPTION_CLASS ? GLOBAL_EXCEPTION_CLASS : HTTP_EX_DEF_CE);
121 : } else
122 : #endif
123 2 : php_verror(NULL, "", type, format, args TSRMLS_CC);
124 18 : va_end(args);
125 18 : }
126 : /* }}} */
127 :
128 : #ifdef ZEND_ENGINE_2
129 : static inline void copy_bt_args(zval *from, zval *to TSRMLS_DC)
130 12 : {
131 12 : zval **args, **trace_0, *old_trace_0, *trace = NULL;
132 :
133 12 : if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), from, "trace", lenof("trace"), 0 TSRMLS_CC))) {
134 12 : if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) {
135 12 : old_trace_0 = *trace_0;
136 12 : if (Z_TYPE_PP(trace_0) == IS_ARRAY && SUCCESS == zend_hash_find(Z_ARRVAL_PP(trace_0), "args", sizeof("args"), (void *) &args)) {
137 12 : if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), to, "trace", lenof("trace"), 0 TSRMLS_CC))) {
138 12 : if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) {
139 12 : ZVAL_ADDREF(*args);
140 12 : add_assoc_zval(*trace_0, "args", *args);
141 : }
142 : }
143 : }
144 : }
145 : }
146 12 : }
147 :
148 : /* {{{ zval *http_exception_wrap(zval *, zval *, zend_class_entry *) */
149 : zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC)
150 7 : {
151 7 : int inner = 1;
152 : char *message;
153 : zval *sub_exception, *tmp_exception;
154 :
155 7 : if (!new_exception) {
156 2 : MAKE_STD_ZVAL(new_exception);
157 2 : object_init_ex(new_exception, ce);
158 :
159 2 : zend_update_property(ce, new_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
160 2 : copy_bt_args(old_exception, new_exception TSRMLS_CC);
161 :
162 2 : sub_exception = old_exception;
163 :
164 8 : while ((sub_exception = zend_read_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(sub_exception) == IS_OBJECT) {
165 4 : ++inner;
166 : }
167 :
168 2 : spprintf(&message, 0, "Exception caused by %d inner exception(s)", inner);
169 2 : zend_update_property_string(ZEND_EXCEPTION_GET_DEFAULT(), new_exception, "message", lenof("message"), message TSRMLS_CC);
170 2 : efree(message);
171 : } else {
172 5 : sub_exception = new_exception;
173 5 : tmp_exception = new_exception;
174 :
175 10 : while ((tmp_exception = zend_read_property(Z_OBJCE_P(tmp_exception), tmp_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(tmp_exception) == IS_OBJECT) {
176 0 : sub_exception = tmp_exception;
177 : }
178 :
179 5 : zend_update_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
180 5 : copy_bt_args(old_exception, new_exception TSRMLS_CC);
181 5 : copy_bt_args(old_exception, sub_exception TSRMLS_CC);
182 : }
183 :
184 7 : zval_ptr_dtor(&old_exception);
185 7 : return new_exception;
186 : }
187 : /* }}} */
188 :
189 : /* {{{ STATUS http_object_new(zend_object_value *, const char *, uint, http_object_new_t, zend_class_entry *, void *, void **) */
190 : STATUS _http_object_new(zend_object_value *ov, const char *cname_str, uint cname_len, http_object_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC)
191 3 : {
192 3 : zend_class_entry *ce = parent_ce;
193 :
194 3 : if (cname_str && cname_len) {
195 0 : if (!(ce = zend_fetch_class(HTTP_ZAPI_CONST_CAST(char *) cname_str, cname_len, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC))) {
196 0 : return FAILURE;
197 : }
198 0 : if (!instanceof_function(ce, parent_ce TSRMLS_CC)) {
199 0 : http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Class %s does not extend %s", cname_str, parent_ce->name);
200 0 : return FAILURE;
201 : }
202 : }
203 :
204 3 : *ov = create(ce, intern_ptr, obj_ptr TSRMLS_CC);
205 3 : return SUCCESS;
206 : }
207 : /* }}} */
208 : #endif /* ZEND_ENGINE_2 */
209 :
210 : /* {{{ void http_log(char *, char *, char *) */
211 : void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC)
212 0 : {
213 : time_t now;
214 : struct tm nowtm;
215 0 : char datetime[20] = {0};
216 :
217 0 : now = HTTP_G->request.time;
218 0 : strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
219 :
220 : #define HTTP_LOG_WRITE(file, type, msg) \
221 : if (file && *file) { \
222 : php_stream *log = php_stream_open_wrapper_ex(file, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT); \
223 : \
224 : if (log) { \
225 : php_stream_printf(log TSRMLS_CC, "%s\t[%s]\t%s\t<%s>%s", datetime, type, msg, SG(request_info).request_uri, PHP_EOL); \
226 : php_stream_close(log); \
227 : } \
228 : \
229 : }
230 :
231 0 : HTTP_LOG_WRITE(file, ident, message);
232 0 : HTTP_LOG_WRITE(HTTP_G->log.composite, ident, message);
233 0 : }
234 : /* }}} */
235 :
236 : static void http_ob_blackhole(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
237 0 : {
238 0 : *handled_output = ecalloc(1,1);
239 0 : *handled_output_len = 0;
240 0 : }
241 :
242 : /* {{{ STATUS http_exit(int, char*, char*) */
243 : STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC)
244 0 : {
245 0 : if ( (send_header && (SUCCESS != http_send_status_header(status, header))) ||
246 : (status && (SUCCESS != http_send_status(status)))) {
247 0 : http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, STR_PTR(header));
248 0 : STR_FREE(header);
249 0 : STR_FREE(body);
250 0 : return FAILURE;
251 : }
252 :
253 0 : if (!OG(ob_lock)) {
254 0 : php_end_ob_buffers(0 TSRMLS_CC);
255 : }
256 0 : if ((SUCCESS == sapi_send_headers(TSRMLS_C)) && body) {
257 0 : PHPWRITE(body, strlen(body));
258 : }
259 :
260 0 : switch (status) {
261 0 : case 301: http_log(HTTP_G->log.redirect, "301-REDIRECT", header); break;
262 0 : case 302: http_log(HTTP_G->log.redirect, "302-REDIRECT", header); break;
263 0 : case 303: http_log(HTTP_G->log.redirect, "303-REDIRECT", header); break;
264 0 : case 305: http_log(HTTP_G->log.redirect, "305-REDIRECT", header); break;
265 0 : case 307: http_log(HTTP_G->log.redirect, "307-REDIRECT", header); break;
266 0 : case 304: http_log(HTTP_G->log.cache, "304-CACHE", header); break;
267 0 : case 404: http_log(HTTP_G->log.not_found, "404-NOTFOUND", NULL); break;
268 0 : case 405: http_log(HTTP_G->log.allowed_methods, "405-ALLOWED", header); break;
269 0 : default: http_log(NULL, header, body); break;
270 : }
271 :
272 0 : STR_FREE(header);
273 0 : STR_FREE(body);
274 :
275 0 : if (HTTP_G->force_exit) {
276 0 : zend_bailout();
277 : } else {
278 0 : php_ob_set_internal_handler(http_ob_blackhole, 4096, "blackhole", 0 TSRMLS_CC);
279 : }
280 :
281 0 : return SUCCESS;
282 : }
283 : /* }}} */
284 :
285 : /* {{{ STATUS http_check_method(char *) */
286 : STATUS _http_check_method_ex(const char *method, const char *methods)
287 0 : {
288 : const char *found;
289 :
290 0 : if ( (found = strstr(methods, method)) &&
291 : (found == method || !HTTP_IS_CTYPE(alpha, found[-1])) &&
292 : (strlen(found) >= strlen(method) && !HTTP_IS_CTYPE(alpha, found[strlen(method)]))) {
293 0 : return SUCCESS;
294 : }
295 0 : return FAILURE;
296 : }
297 : /* }}} */
298 :
299 : /* {{{ zval *http_get_server_var_ex(char *, size_t) */
300 : PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
301 18 : {
302 : zval **hsv, **var;
303 : char *env;
304 :
305 : /* if available, this is a lot faster than accessing $_SERVER */
306 18 : if (sapi_module.getenv) {
307 0 : if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
308 0 : return NULL;
309 : }
310 0 : if (HTTP_G->server_var) {
311 0 : zval_ptr_dtor(&HTTP_G->server_var);
312 : }
313 0 : MAKE_STD_ZVAL(HTTP_G->server_var);
314 0 : ZVAL_STRING(HTTP_G->server_var, env, 1);
315 0 : return HTTP_G->server_var;
316 : }
317 :
318 : #ifdef ZEND_ENGINE_2
319 18 : zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
320 : #endif
321 :
322 18 : if ((SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
323 0 : return NULL;
324 : }
325 18 : if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), HTTP_ZAPI_CONST_CAST(char *) key, key_len + 1, (void *) &var))) {
326 7 : return NULL;
327 : }
328 11 : if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
329 0 : return NULL;
330 : }
331 11 : return *var;
332 : }
333 : /* }}} */
334 :
335 : /* {{{ STATUS http_get_request_body(char **, size_t *) */
336 : PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC)
337 3 : {
338 3 : *length = 0;
339 3 : *body = NULL;
340 :
341 3 : if (SG(request_info).raw_post_data) {
342 3 : *length = SG(request_info).raw_post_data_length;
343 3 : *body = SG(request_info).raw_post_data;
344 :
345 3 : if (dup) {
346 3 : *body = estrndup(*body, *length);
347 : }
348 3 : return SUCCESS;
349 0 : } else if (sapi_module.read_post && !HTTP_G->read_post_data) {
350 : char buf[4096];
351 : int len;
352 :
353 0 : HTTP_G->read_post_data = 1;
354 :
355 0 : while (0 < (len = sapi_module.read_post(buf, sizeof(buf) TSRMLS_CC))) {
356 0 : *body = erealloc(*body, *length + len + 1);
357 0 : memcpy(*body + *length, buf, len);
358 0 : *length += len;
359 0 : (*body)[*length] = '\0';
360 : }
361 :
362 : /* check for error */
363 0 : if (len < 0) {
364 0 : STR_FREE(*body);
365 0 : *length = 0;
366 0 : return FAILURE;
367 : }
368 :
369 0 : SG(request_info).raw_post_data = *body;
370 0 : SG(request_info).raw_post_data_length = *length;
371 :
372 0 : if (dup) {
373 0 : *body = estrndup(*body, *length);
374 : }
375 0 : return SUCCESS;
376 : }
377 :
378 0 : return FAILURE;
379 : }
380 : /* }}} */
381 :
382 : /* {{{ php_stream *http_get_request_body_stream(void) */
383 : PHP_HTTP_API php_stream *_http_get_request_body_stream(TSRMLS_D)
384 1 : {
385 1 : php_stream *s = NULL;
386 :
387 1 : if (SG(request_info).raw_post_data) {
388 1 : s = php_stream_open_wrapper("php://input", "rb", 0, NULL);
389 0 : } else if (sapi_module.read_post && !HTTP_G->read_post_data) {
390 0 : HTTP_G->read_post_data = 1;
391 :
392 0 : if ((s = php_stream_temp_new())) {
393 : char buf[4096];
394 : int len;
395 :
396 0 : while (0 < (len = sapi_module.read_post(buf, sizeof(buf) TSRMLS_CC))) {
397 0 : php_stream_write(s, buf, len);
398 : }
399 :
400 0 : if (len < 0) {
401 0 : php_stream_close(s);
402 0 : s = NULL;
403 : } else {
404 0 : php_stream_rewind(s);
405 : }
406 : }
407 : }
408 :
409 1 : return s;
410 : }
411 : /* }}} */
412 :
413 : /* {{{ void http_parse_params_default_callback(...) */
414 : PHP_HTTP_API void _http_parse_params_default_callback(void *arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
415 11 : {
416 : char *kdup;
417 : zval tmp, *entry;
418 11 : HashTable *ht = (HashTable *) arg;
419 :
420 11 : if (ht) {
421 11 : INIT_ZARR(tmp, ht);
422 :
423 11 : if (vallen) {
424 5 : MAKE_STD_ZVAL(entry);
425 5 : array_init(entry);
426 5 : if (keylen) {
427 5 : kdup = estrndup(key, keylen);
428 5 : add_assoc_stringl_ex(entry, kdup, keylen + 1, (char *) val, vallen, 1);
429 5 : efree(kdup);
430 : } else {
431 0 : add_next_index_stringl(entry, (char *) val, vallen, 1);
432 : }
433 5 : add_next_index_zval(&tmp, entry);
434 : } else {
435 6 : add_next_index_stringl(&tmp, (char *) key, keylen, 1);
436 : }
437 : }
438 11 : }
439 : /* }}} */
440 :
441 : /* {{{ STATUS http_parse_params(const char *, HashTable *) */
442 : PHP_HTTP_API STATUS _http_parse_params_ex(const char *param, int flags, http_parse_params_callback cb, void *cb_arg TSRMLS_DC)
443 41 : {
444 : #define ST_QUOTE 1
445 : #define ST_VALUE 2
446 : #define ST_KEY 3
447 : #define ST_ASSIGN 4
448 : #define ST_ADD 5
449 :
450 41 : int st = ST_KEY, keylen = 0, vallen = 0;
451 41 : char *s, *c, *key = NULL, *val = NULL;
452 :
453 41 : for(c = s = estrdup(param);;) {
454 910 : continued:
455 : #if 0
456 : {
457 : char *tk = NULL, *tv = NULL;
458 :
459 : if (key) {
460 : if (keylen) {
461 : tk= estrndup(key, keylen);
462 : } else {
463 : tk = ecalloc(1, 7);
464 : memcpy(tk, key, 3);
465 : tk[3]='.'; tk[4]='.'; tk[5]='.';
466 : }
467 : }
468 : if (val) {
469 : if (vallen) {
470 : tv = estrndup(val, vallen);
471 : } else {
472 : tv = ecalloc(1, 7);
473 : memcpy(tv, val, 3);
474 : tv[3]='.'; tv[4]='.'; tv[5]='.';
475 : }
476 : }
477 : fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
478 : (
479 : st == ST_QUOTE ? "QUOTE" :
480 : st == ST_VALUE ? "VALUE" :
481 : st == ST_KEY ? "KEY" :
482 : st == ST_ASSIGN ? "ASSIGN" :
483 : st == ST_ADD ? "ADD":
484 : "HUH?"
485 : ), *c?*c:'0', tk, tv
486 : );
487 : STR_FREE(tk); STR_FREE(tv);
488 : }
489 : #endif
490 910 : switch (st) {
491 : case ST_QUOTE:
492 61 : quote:
493 61 : if (*c == '"') {
494 14 : if (*(c-1) == '\\') {
495 2 : memmove(c-1, c, strlen(c)+1);
496 2 : goto quote;
497 : } else {
498 12 : goto add;
499 : }
500 : } else {
501 47 : if (!val) {
502 14 : val = c;
503 : }
504 47 : if (!*c) {
505 3 : --val;
506 3 : st = ST_ADD;
507 : }
508 : }
509 47 : break;
510 :
511 : case ST_VALUE:
512 474 : switch (*c) {
513 : case '"':
514 16 : if (!val) {
515 15 : st = ST_QUOTE;
516 : }
517 16 : break;
518 :
519 : case ' ':
520 31 : break;
521 :
522 : case ';':
523 : case '\0':
524 31 : goto add;
525 : break;
526 : case ',':
527 3 : if (flags & HTTP_PARAMS_ALLOW_COMMA) {
528 0 : goto add;
529 : }
530 : default:
531 396 : if (!val) {
532 24 : val = c;
533 : }
534 : break;
535 : }
536 443 : break;
537 :
538 : case ST_KEY:
539 358 : switch (*c) {
540 : case ',':
541 2 : if (flags & HTTP_PARAMS_ALLOW_COMMA) {
542 2 : goto allow_comma;
543 : }
544 : case '\r':
545 : case '\n':
546 : case '\t':
547 : case '\013':
548 : case '\014':
549 0 : goto failure;
550 : break;
551 :
552 : case '=':
553 41 : if (key) {
554 41 : keylen = c - key;
555 41 : st = ST_VALUE;
556 : } else {
557 0 : goto failure;
558 : }
559 41 : break;
560 :
561 : case ' ':
562 28 : if (key) {
563 8 : keylen = c - key;
564 8 : st = ST_ASSIGN;
565 : }
566 28 : break;
567 :
568 : case ';':
569 : case '\0':
570 33 : allow_comma:
571 33 : if (key) {
572 9 : keylen = c-- - key;
573 9 : st = ST_ADD;
574 : }
575 33 : break;
576 :
577 : default:
578 256 : if (!key) {
579 58 : key = c;
580 : }
581 : break;
582 : }
583 358 : break;
584 :
585 : case ST_ASSIGN:
586 8 : if (*c == '=') {
587 5 : st = ST_VALUE;
588 6 : } else if (!*c || *c == ';' || ((flags & HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) {
589 3 : st = ST_ADD;
590 0 : } else if (*c != ' ') {
591 0 : goto failure;
592 : }
593 8 : break;
594 :
595 : case ST_ADD:
596 58 : add:
597 58 : if (val) {
598 38 : vallen = c - val;
599 38 : if (st != ST_QUOTE) {
600 27 : while (val[vallen-1] == ' ') --vallen;
601 : }
602 : } else {
603 20 : val = "";
604 20 : vallen = 0;
605 : }
606 :
607 58 : cb(cb_arg, key, keylen, val, vallen TSRMLS_CC);
608 :
609 58 : st = ST_KEY;
610 58 : key = val = NULL;
611 58 : keylen = vallen = 0;
612 : break;
613 : }
614 914 : if (*c) {
615 869 : ++c;
616 45 : } else if (st == ST_ADD) {
617 4 : goto add;
618 : } else {
619 41 : break;
620 : }
621 869 : }
622 :
623 41 : efree(s);
624 41 : return SUCCESS;
625 :
626 0 : failure:
627 0 : if (flags & HTTP_PARAMS_RAISE_ERROR) {
628 0 : http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
629 : }
630 0 : if (flags & HTTP_PARAMS_ALLOW_FAILURE) {
631 0 : if (st == ST_KEY) {
632 0 : if (key) {
633 0 : keylen = c - key;
634 : } else {
635 0 : key = c;
636 : }
637 : } else {
638 0 : --c;
639 : }
640 0 : st = ST_ADD;
641 0 : goto continued;
642 : }
643 0 : efree(s);
644 0 : return FAILURE;
645 : }
646 : /* }}} */
647 :
648 : /* {{{ array_join */
649 : int apply_array_append_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
650 0 : {
651 : int flags;
652 0 : char *key = NULL;
653 : HashTable *dst;
654 0 : zval **data = NULL, **value = (zval **) pDest;
655 :
656 0 : dst = va_arg(args, HashTable *);
657 0 : flags = va_arg(args, int);
658 :
659 0 : if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
660 0 : if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
661 0 : key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
662 0 : zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data);
663 : } else {
664 0 : zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data);
665 : }
666 :
667 0 : ZVAL_ADDREF(*value);
668 0 : if (data) {
669 0 : if (Z_TYPE_PP(data) != IS_ARRAY) {
670 0 : convert_to_array(*data);
671 : }
672 0 : add_next_index_zval(*data, *value);
673 0 : } else if (key) {
674 0 : zend_hash_add(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL);
675 : } else {
676 0 : zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL);
677 : }
678 :
679 0 : if (key) {
680 0 : efree(key);
681 : }
682 : }
683 :
684 0 : return ZEND_HASH_APPLY_KEEP;
685 : }
686 :
687 : int apply_array_merge_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
688 263 : {
689 : int flags;
690 263 : char *key = NULL;
691 : HashTable *dst;
692 263 : zval **value = (zval **) pDest;
693 :
694 263 : dst = va_arg(args, HashTable *);
695 263 : flags = va_arg(args, int);
696 :
697 263 : if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
698 263 : ZVAL_ADDREF(*value);
699 267 : if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
700 4 : key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
701 4 : zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL);
702 4 : efree(key);
703 : } else {
704 259 : zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL);
705 : }
706 : }
707 :
708 263 : return ZEND_HASH_APPLY_KEEP;
709 : }
710 : /* }}} */
711 :
712 : /*
713 : * Local variables:
714 : * tab-width: 4
715 : * c-basic-offset: 4
716 : * End:
717 : * vim600: noet sw=4 ts=4 fdm=marker
718 : * vim<600: noet sw=4 ts=4
719 : */
720 :
|