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