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.172 2009/02/12 13:11:04 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 9357 : {
31 9357 : HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT);
32 9357 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS);
33 9357 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME);
34 9357 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS);
35 9357 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS);
36 9357 : HTTP_LONG_CONSTANT("HTTP_SUPPORT_EVENTS", HTTP_SUPPORT_EVENTS);
37 :
38 9357 : HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA);
39 9357 : HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE);
40 9357 : HTTP_LONG_CONSTANT("HTTP_PARAMS_RAISE_ERROR", HTTP_PARAMS_RAISE_ERROR);
41 9357 : HTTP_LONG_CONSTANT("HTTP_PARAMS_DEFAULT", HTTP_PARAMS_DEFAULT);
42 :
43 9357 : 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 952 : {
75 : size_t i;
76 : int wasalpha;
77 :
78 952 : if (key && key_len) {
79 952 : if ((wasalpha = HTTP_IS_CTYPE(alpha, key[0]))) {
80 952 : key[0] = (char) (uctitle ? HTTP_TO_CTYPE(upper, key[0]) : HTTP_TO_CTYPE(lower, key[0]));
81 : }
82 9193 : for (i = 1; i < key_len; i++) {
83 8241 : if (HTTP_IS_CTYPE(alpha, key[i])) {
84 7609 : key[i] = (char) (((!wasalpha) && uctitle) ? HTTP_TO_CTYPE(upper, key[i]) : HTTP_TO_CTYPE(lower, key[i]));
85 7609 : wasalpha = 1;
86 : } else {
87 632 : if (xhyphen && (key[i] == '_')) {
88 5 : key[i] = '-';
89 : }
90 632 : wasalpha = 0;
91 : }
92 : }
93 : }
94 952 : 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 28 : if (key) {
554 8 : keylen = c - key;
555 8 : st = ST_ASSIGN;
556 : }
557 28 : break;
558 :
559 : case ';':
560 : case '\0':
561 33 : allow_comma:
562 33 : if (key) {
563 9 : keylen = c-- - key;
564 9 : st = ST_ADD;
565 : }
566 33 : break;
567 :
568 : case ':':
569 0 : if (!(flags & HTTP_PARAMS_COLON_SEPARATOR)) {
570 0 : goto not_separator;
571 : }
572 0 : if (key) {
573 0 : keylen = c - key;
574 0 : st = ST_VALUE;
575 : } else {
576 0 : goto failure;
577 : }
578 0 : break;
579 :
580 : case '=':
581 41 : if (flags & HTTP_PARAMS_COLON_SEPARATOR) {
582 0 : goto not_separator;
583 : }
584 41 : if (key) {
585 41 : keylen = c - key;
586 41 : st = ST_VALUE;
587 : } else {
588 0 : goto failure;
589 : }
590 41 : break;
591 :
592 : default:
593 256 : not_separator:
594 256 : if (!key) {
595 58 : key = c;
596 : }
597 : break;
598 : }
599 358 : break;
600 :
601 : case ST_ASSIGN:
602 8 : if (*c == '=') {
603 5 : st = ST_VALUE;
604 6 : } else if (!*c || *c == ';' || ((flags & HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) {
605 3 : st = ST_ADD;
606 0 : } else if (*c != ' ') {
607 0 : goto failure;
608 : }
609 8 : break;
610 :
611 : case ST_ADD:
612 58 : add:
613 58 : if (val) {
614 38 : vallen = c - val;
615 38 : if (st != ST_QUOTE) {
616 27 : while (val[vallen-1] == ' ') --vallen;
617 : }
618 : } else {
619 20 : val = "";
620 20 : vallen = 0;
621 : }
622 :
623 58 : cb(cb_arg, key, keylen, val, vallen TSRMLS_CC);
624 :
625 58 : st = ST_KEY;
626 58 : key = val = NULL;
627 58 : keylen = vallen = 0;
628 : break;
629 : }
630 914 : if (*c) {
631 869 : ++c;
632 45 : } else if (st == ST_ADD) {
633 4 : goto add;
634 : } else {
635 41 : break;
636 : }
637 869 : }
638 :
639 41 : efree(s);
640 41 : return SUCCESS;
641 :
642 0 : failure:
643 0 : if (flags & HTTP_PARAMS_RAISE_ERROR) {
644 0 : http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
645 : }
646 0 : if (flags & HTTP_PARAMS_ALLOW_FAILURE) {
647 0 : if (st == ST_KEY) {
648 0 : if (key) {
649 0 : keylen = c - key;
650 : } else {
651 0 : key = c;
652 : }
653 : } else {
654 0 : --c;
655 : }
656 0 : st = ST_ADD;
657 0 : goto continued;
658 : }
659 0 : efree(s);
660 0 : return FAILURE;
661 : }
662 : /* }}} */
663 :
664 : /* {{{ array_join */
665 : int apply_array_append_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
666 0 : {
667 : int flags;
668 0 : char *key = NULL;
669 : HashTable *dst;
670 0 : zval **data = NULL, **value = (zval **) pDest;
671 :
672 0 : dst = va_arg(args, HashTable *);
673 0 : flags = va_arg(args, int);
674 :
675 0 : if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
676 0 : if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
677 0 : key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
678 0 : zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data);
679 : } else {
680 0 : zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data);
681 : }
682 :
683 0 : ZVAL_ADDREF(*value);
684 0 : if (data) {
685 0 : add_next_index_zval(http_zset(IS_ARRAY, *data), *value);
686 0 : } else if (key) {
687 0 : zend_hash_add(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL);
688 : } else {
689 0 : zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL);
690 : }
691 :
692 0 : if (key) {
693 0 : efree(key);
694 : }
695 : }
696 :
697 0 : return ZEND_HASH_APPLY_KEEP;
698 : }
699 :
700 : int apply_array_merge_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
701 266 : {
702 : int flags;
703 266 : char *key = NULL;
704 : HashTable *dst;
705 266 : zval **value = (zval **) pDest;
706 :
707 266 : dst = va_arg(args, HashTable *);
708 266 : flags = va_arg(args, int);
709 :
710 266 : if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
711 266 : ZVAL_ADDREF(*value);
712 273 : if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
713 7 : key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
714 7 : zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL);
715 7 : efree(key);
716 : } else {
717 259 : zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL);
718 : }
719 : }
720 :
721 266 : return ZEND_HASH_APPLY_KEEP;
722 : }
723 : /* }}} */
724 :
725 : /*
726 : * Local variables:
727 : * tab-width: 4
728 : * c-basic-offset: 4
729 : * End:
730 : * vim600: noet sw=4 ts=4 fdm=marker
731 : * vim<600: noet sw=4 ts=4
732 : */
733 :
|