1 /* Generated by re2c 1.0.3 */
2 #line 1 "ext/standard/url_scanner_ex.re"
3 /*
4 +----------------------------------------------------------------------+
5 | PHP Version 7 |
6 +----------------------------------------------------------------------+
7 | Copyright (c) 1997-2018 The PHP Group |
8 +----------------------------------------------------------------------+
9 | This source file is subject to version 3.01 of the PHP license, |
10 | that is bundled with this package in the file LICENSE, and is |
11 | available through the world-wide-web at the following url: |
12 | http://www.php.net/license/3_01.txt |
13 | If you did not receive a copy of the PHP license and are unable to |
14 | obtain it through the world-wide-web, please send a note to |
15 | license@php.net so we can mail you a copy immediately. |
16 +----------------------------------------------------------------------+
17 | Author: Sascha Schumann <sascha@schumann.cx> |
18 | Yasuo Ohgaki <yohgaki@ohgaki.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include "php.h"
23
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_LIMITS_H
28 #include <limits.h>
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "SAPI.h"
36 #include "php_ini.h"
37 #include "php_globals.h"
38 #include "php_string.h"
39 #define STATE_TAG SOME_OTHER_STATE_TAG
40 #include "basic_functions.h"
41 #include "url.h"
42 #include "html.h"
43 #undef STATE_TAG
44
45 #define url_scanner url_scanner_ex
46
47 #include "zend_smart_str.h"
48
tag_dtor(zval * zv)49 static void tag_dtor(zval *zv)
50 {
51 free(Z_PTR_P(zv));
52 }
53
php_ini_on_update_tags(zend_ini_entry * entry,zend_string * new_value,void * mh_arg1,void * mh_arg2,void * mh_arg3,int stage,int type)54 static int php_ini_on_update_tags(zend_ini_entry *entry, zend_string *new_value, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage, int type)
55 {
56 url_adapt_state_ex_t *ctx;
57 char *key;
58 char *tmp;
59 char *lasts = NULL;
60
61 if (type) {
62 ctx = &BG(url_adapt_session_ex);
63 } else {
64 ctx = &BG(url_adapt_output_ex);
65 }
66
67 tmp = estrndup(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
68
69 if (ctx->tags)
70 zend_hash_destroy(ctx->tags);
71 else {
72 ctx->tags = malloc(sizeof(HashTable));
73 if (!ctx->tags) {
74 efree(tmp);
75 return FAILURE;
76 }
77 }
78
79 zend_hash_init(ctx->tags, 0, NULL, tag_dtor, 1);
80
81 for (key = php_strtok_r(tmp, ",", &lasts);
82 key;
83 key = php_strtok_r(NULL, ",", &lasts)) {
84 char *val;
85
86 val = strchr(key, '=');
87 if (val) {
88 char *q;
89 size_t keylen;
90 zend_string *str;
91
92 *val++ = '\0';
93 for (q = key; *q; q++) {
94 *q = tolower(*q);
95 }
96 keylen = q - key;
97 str = zend_string_init(key, keylen, 1);
98 GC_MAKE_PERSISTENT_LOCAL(str);
99 zend_hash_add_mem(ctx->tags, str, val, strlen(val)+1);
100 zend_string_release_ex(str, 1);
101 }
102 }
103
104 efree(tmp);
105
106 return SUCCESS;
107 }
108
PHP_INI_MH(OnUpdateSessionTags)109 static PHP_INI_MH(OnUpdateSessionTags)
110 {
111 return php_ini_on_update_tags(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage, 1);
112 }
113
PHP_INI_MH(OnUpdateOutputTags)114 static PHP_INI_MH(OnUpdateOutputTags)
115 {
116 return php_ini_on_update_tags(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage, 0);
117 }
118
php_ini_on_update_hosts(zend_ini_entry * entry,zend_string * new_value,void * mh_arg1,void * mh_arg2,void * mh_arg3,int stage,int type)119 static int php_ini_on_update_hosts(zend_ini_entry *entry, zend_string *new_value, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage, int type)
120 {
121 HashTable *hosts;
122 char *key;
123 char *tmp;
124 char *lasts = NULL;
125
126 if (type) {
127 hosts = &BG(url_adapt_session_hosts_ht);
128 } else {
129 hosts = &BG(url_adapt_output_hosts_ht);
130 }
131 zend_hash_clean(hosts);
132
133 /* Use user supplied host whitelist */
134 tmp = estrndup(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
135 for (key = php_strtok_r(tmp, ",", &lasts);
136 key;
137 key = php_strtok_r(NULL, ",", &lasts)) {
138 size_t keylen;
139 zend_string *tmp_key;
140 char *q;
141
142 for (q = key; *q; q++) {
143 *q = tolower(*q);
144 }
145 keylen = q - key;
146 if (keylen > 0) {
147 tmp_key = zend_string_init(key, keylen, 0);
148 zend_hash_add_empty_element(hosts, tmp_key);
149 zend_string_release_ex(tmp_key, 0);
150 }
151 }
152 efree(tmp);
153
154 return SUCCESS;
155 }
156
PHP_INI_MH(OnUpdateSessionHosts)157 static PHP_INI_MH(OnUpdateSessionHosts)
158 {
159 return php_ini_on_update_hosts(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage, 1);
160 }
161
PHP_INI_MH(OnUpdateOutputHosts)162 static PHP_INI_MH(OnUpdateOutputHosts)
163 {
164 return php_ini_on_update_hosts(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage, 0);
165 }
166
167 /* FIXME: OnUpdate*Hosts cannot set default to $_SERVER['HTTP_HOST'] at startup */
168 PHP_INI_BEGIN()
169 STD_PHP_INI_ENTRY("session.trans_sid_tags", "a=href,area=href,frame=src,form=", PHP_INI_ALL, OnUpdateSessionTags, url_adapt_session_ex, php_basic_globals, basic_globals)
170 STD_PHP_INI_ENTRY("session.trans_sid_hosts", "", PHP_INI_ALL, OnUpdateSessionHosts, url_adapt_session_hosts_ht, php_basic_globals, basic_globals)
171 STD_PHP_INI_ENTRY("url_rewriter.tags", "form=", PHP_INI_ALL, OnUpdateOutputTags, url_adapt_session_ex, php_basic_globals, basic_globals)
172 STD_PHP_INI_ENTRY("url_rewriter.hosts", "", PHP_INI_ALL, OnUpdateOutputHosts, url_adapt_session_hosts_ht, php_basic_globals, basic_globals)
PHP_INI_END()173 PHP_INI_END()
174
175 #line 179 "ext/standard/url_scanner_ex.re"
176
177
178 #define YYFILL(n) goto done
179 #define YYCTYPE unsigned char
180 #define YYCURSOR p
181 #define YYLIMIT q
182 #define YYMARKER r
183
184 static inline void append_modified_url(smart_str *url, smart_str *dest, smart_str *url_app, const char *separator)
185 {
186 php_url *url_parts;
187
188 smart_str_0(url); /* FIXME: Bug #70480 php_url_parse_ex() crashes by processing chars exceed len */
189 url_parts = php_url_parse_ex(ZSTR_VAL(url->s), ZSTR_LEN(url->s));
190
191 /* Ignore malformed URLs */
192 if (!url_parts) {
193 smart_str_append_smart_str(dest, url);
194 return;
195 }
196
197 /* Don't modify URLs of the format "#mark" */
198 if (url_parts->fragment && '#' == ZSTR_VAL(url->s)[0]) {
199 smart_str_append_smart_str(dest, url);
200 php_url_free(url_parts);
201 return;
202 }
203
204 /* Check protocol. Only http/https is allowed. */
205 if (url_parts->scheme
206 && !zend_string_equals_literal_ci(url_parts->scheme, "http")
207 && !zend_string_equals_literal_ci(url_parts->scheme, "https")) {
208 smart_str_append_smart_str(dest, url);
209 php_url_free(url_parts);
210 return;
211 }
212
213 /* Check host whitelist. If it's not listed, do nothing. */
214 if (url_parts->host) {
215 zend_string *tmp = zend_string_tolower(url_parts->host);
216 if (!zend_hash_exists(&BG(url_adapt_session_hosts_ht), tmp)) {
217 zend_string_release_ex(tmp, 0);
218 smart_str_append_smart_str(dest, url);
219 php_url_free(url_parts);
220 return;
221 }
222 zend_string_release_ex(tmp, 0);
223 }
224
225 /*
226 * When URL does not have path and query string add "/?".
227 * i.e. If URL is only "?foo=bar", should not add "/?".
228 */
229 if (!url_parts->path && !url_parts->query && !url_parts->fragment) {
230 /* URL is http://php.net or like */
231 smart_str_append_smart_str(dest, url);
232 smart_str_appendc(dest, '/');
233 smart_str_appendc(dest, '?');
234 smart_str_append_smart_str(dest, url_app);
235 php_url_free(url_parts);
236 return;
237 }
238
239 if (url_parts->scheme) {
240 smart_str_appends(dest, ZSTR_VAL(url_parts->scheme));
241 smart_str_appends(dest, "://");
242 } else if (*(ZSTR_VAL(url->s)) == '/' && *(ZSTR_VAL(url->s)+1) == '/') {
243 smart_str_appends(dest, "//");
244 }
245 if (url_parts->user) {
246 smart_str_appends(dest, ZSTR_VAL(url_parts->user));
247 if (url_parts->pass) {
248 smart_str_appends(dest, ZSTR_VAL(url_parts->pass));
249 smart_str_appendc(dest, ':');
250 }
251 smart_str_appendc(dest, '@');
252 }
253 if (url_parts->host) {
254 smart_str_appends(dest, ZSTR_VAL(url_parts->host));
255 }
256 if (url_parts->port) {
257 smart_str_appendc(dest, ':');
258 smart_str_append_unsigned(dest, (long)url_parts->port);
259 }
260 if (url_parts->path) {
261 smart_str_appends(dest, ZSTR_VAL(url_parts->path));
262 }
263 smart_str_appendc(dest, '?');
264 if (url_parts->query) {
265 smart_str_appends(dest, ZSTR_VAL(url_parts->query));
266 smart_str_appends(dest, separator);
267 smart_str_append_smart_str(dest, url_app);
268 } else {
269 smart_str_append_smart_str(dest, url_app);
270 }
271 if (url_parts->fragment) {
272 smart_str_appendc(dest, '#');
273 smart_str_appends(dest, ZSTR_VAL(url_parts->fragment));
274 }
275 php_url_free(url_parts);
276 }
277
278 enum {
279 TAG_NORMAL = 0,
280 TAG_FORM
281 };
282
283 enum {
284 ATTR_NORMAL = 0,
285 ATTR_ACTION
286 };
287
288 #undef YYFILL
289 #undef YYCTYPE
290 #undef YYCURSOR
291 #undef YYLIMIT
292 #undef YYMARKER
293
tag_arg(url_adapt_state_ex_t * ctx,char quotes,char type)294 static inline void tag_arg(url_adapt_state_ex_t *ctx, char quotes, char type)
295 {
296 char f = 0;
297
298 /* arg.s is string WITHOUT NUL.
299 To avoid partial match, NUL is added here */
300 ZSTR_VAL(ctx->arg.s)[ZSTR_LEN(ctx->arg.s)] = '\0';
301 if (!strcasecmp(ZSTR_VAL(ctx->arg.s), ctx->lookup_data)) {
302 f = 1;
303 }
304
305 if (quotes) {
306 smart_str_appendc(&ctx->result, type);
307 }
308 if (f) {
309 append_modified_url(&ctx->val, &ctx->result, &ctx->url_app, PG(arg_separator).output);
310 } else {
311 smart_str_append_smart_str(&ctx->result, &ctx->val);
312 }
313 if (quotes) {
314 smart_str_appendc(&ctx->result, type);
315 }
316 }
317
318 enum {
319 STATE_PLAIN = 0,
320 STATE_TAG,
321 STATE_NEXT_ARG,
322 STATE_ARG,
323 STATE_BEFORE_VAL,
324 STATE_VAL
325 };
326
327 #define YYFILL(n) goto stop
328 #define YYCTYPE unsigned char
329 #define YYCURSOR xp
330 #define YYLIMIT end
331 #define YYMARKER q
332 #define STATE ctx->state
333
334 #define STD_PARA url_adapt_state_ex_t *ctx, char *start, char *YYCURSOR
335 #define STD_ARGS ctx, start, xp
336
337 #if SCANNER_DEBUG
338 #define scdebug(x) printf x
339 #else
340 #define scdebug(x)
341 #endif
342
passthru(STD_PARA)343 static inline void passthru(STD_PARA)
344 {
345 scdebug(("appending %d chars, starting with %c\n", YYCURSOR-start, *start));
346 smart_str_appendl(&ctx->result, start, YYCURSOR - start);
347 }
348
349
check_http_host(char * target)350 static int check_http_host(char *target)
351 {
352 zval *host, *tmp;
353 zend_string *host_tmp;
354 char *colon;
355
356 if ((tmp = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_SERVER"))) &&
357 Z_TYPE_P(tmp) == IS_ARRAY &&
358 (host = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("HTTP_HOST"))) &&
359 Z_TYPE_P(host) == IS_STRING) {
360 host_tmp = zend_string_init(Z_STRVAL_P(host), Z_STRLEN_P(host), 0);
361 /* HTTP_HOST could be 'localhost:8888' etc. */
362 colon = strchr(ZSTR_VAL(host_tmp), ':');
363 if (colon) {
364 ZSTR_LEN(host_tmp) = colon - ZSTR_VAL(host_tmp);
365 ZSTR_VAL(host_tmp)[ZSTR_LEN(host_tmp)] = '\0';
366 }
367 if (!strcasecmp(ZSTR_VAL(host_tmp), target)) {
368 zend_string_release_ex(host_tmp, 0);
369 return SUCCESS;
370 }
371 zend_string_release_ex(host_tmp, 0);
372 }
373 return FAILURE;
374 }
375
check_host_whitelist(url_adapt_state_ex_t * ctx)376 static int check_host_whitelist(url_adapt_state_ex_t *ctx)
377 {
378 php_url *url_parts = NULL;
379 HashTable *allowed_hosts = ctx->type ? &BG(url_adapt_session_hosts_ht) : &BG(url_adapt_output_hosts_ht);
380
381 ZEND_ASSERT(ctx->tag_type == TAG_FORM);
382
383 if (ctx->attr_val.s && ZSTR_LEN(ctx->attr_val.s)) {
384 url_parts = php_url_parse_ex(ZSTR_VAL(ctx->attr_val.s), ZSTR_LEN(ctx->attr_val.s));
385 } else {
386 return SUCCESS; /* empty URL is valid */
387 }
388
389 if (!url_parts) {
390 return FAILURE;
391 }
392 if (url_parts->scheme) {
393 /* Only http/https should be handled.
394 A bit hacky check this here, but saves a URL parse. */
395 if (!zend_string_equals_literal_ci(url_parts->scheme, "http") &&
396 !zend_string_equals_literal_ci(url_parts->scheme, "https")) {
397 php_url_free(url_parts);
398 return FAILURE;
399 }
400 }
401 if (!url_parts->host) {
402 php_url_free(url_parts);
403 return SUCCESS;
404 }
405 if (!zend_hash_num_elements(allowed_hosts) &&
406 check_http_host(ZSTR_VAL(url_parts->host)) == SUCCESS) {
407 php_url_free(url_parts);
408 return SUCCESS;
409 }
410 if (!zend_hash_find(allowed_hosts, url_parts->host)) {
411 php_url_free(url_parts);
412 return FAILURE;
413 }
414 php_url_free(url_parts);
415 return SUCCESS;
416 }
417
418 /*
419 * This function appends a hidden input field after a <form>.
420 */
handle_form(STD_PARA)421 static void handle_form(STD_PARA)
422 {
423 int doit = 0;
424
425 if (ZSTR_LEN(ctx->form_app.s) > 0) {
426 switch (ZSTR_LEN(ctx->tag.s)) {
427 case sizeof("form") - 1:
428 if (!strncasecmp(ZSTR_VAL(ctx->tag.s), "form", ZSTR_LEN(ctx->tag.s))
429 && check_host_whitelist(ctx) == SUCCESS) {
430 doit = 1;
431 }
432 break;
433 }
434 }
435
436 if (doit) {
437 smart_str_append_smart_str(&ctx->result, &ctx->form_app);
438 }
439 }
440
441 /*
442 * HANDLE_TAG copies the HTML Tag and checks whether we
443 * have that tag in our table. If we might modify it,
444 * we continue to scan the tag, otherwise we simply copy the complete
445 * HTML stuff to the result buffer.
446 */
447
handle_tag(STD_PARA)448 static inline void handle_tag(STD_PARA)
449 {
450 int ok = 0;
451 unsigned int i;
452
453 if (ctx->tag.s) {
454 ZSTR_LEN(ctx->tag.s) = 0;
455 }
456 smart_str_appendl(&ctx->tag, start, YYCURSOR - start);
457 for (i = 0; i < ZSTR_LEN(ctx->tag.s); i++)
458 ZSTR_VAL(ctx->tag.s)[i] = tolower((int)(unsigned char)ZSTR_VAL(ctx->tag.s)[i]);
459 /* intentionally using str_find here, in case the hash value is set, but the string val is changed later */
460 if ((ctx->lookup_data = zend_hash_str_find_ptr(ctx->tags, ZSTR_VAL(ctx->tag.s), ZSTR_LEN(ctx->tag.s))) != NULL) {
461 ok = 1;
462 if (ZSTR_LEN(ctx->tag.s) == sizeof("form")-1
463 && !strncasecmp(ZSTR_VAL(ctx->tag.s), "form", ZSTR_LEN(ctx->tag.s))) {
464 ctx->tag_type = TAG_FORM;
465 } else {
466 ctx->tag_type = TAG_NORMAL;
467 }
468 }
469 STATE = ok ? STATE_NEXT_ARG : STATE_PLAIN;
470 }
471
handle_arg(STD_PARA)472 static inline void handle_arg(STD_PARA)
473 {
474 if (ctx->arg.s) {
475 ZSTR_LEN(ctx->arg.s) = 0;
476 }
477 smart_str_appendl(&ctx->arg, start, YYCURSOR - start);
478 if (ctx->tag_type == TAG_FORM &&
479 strncasecmp(ZSTR_VAL(ctx->arg.s), "action", ZSTR_LEN(ctx->arg.s)) == 0) {
480 ctx->attr_type = ATTR_ACTION;
481 } else {
482 ctx->attr_type = ATTR_NORMAL;
483 }
484 }
485
handle_val(STD_PARA,char quotes,char type)486 static inline void handle_val(STD_PARA, char quotes, char type)
487 {
488 smart_str_setl(&ctx->val, start + quotes, YYCURSOR - start - quotes * 2);
489 if (ctx->tag_type == TAG_FORM && ctx->attr_type == ATTR_ACTION) {
490 smart_str_setl(&ctx->attr_val, start + quotes, YYCURSOR - start - quotes * 2);
491 }
492 tag_arg(ctx, quotes, type);
493 }
494
xx_mainloop(url_adapt_state_ex_t * ctx,const char * newdata,size_t newlen)495 static inline void xx_mainloop(url_adapt_state_ex_t *ctx, const char *newdata, size_t newlen)
496 {
497 char *end, *q;
498 char *xp;
499 char *start;
500 size_t rest;
501
502 smart_str_appendl(&ctx->buf, newdata, newlen);
503
504 YYCURSOR = ZSTR_VAL(ctx->buf.s);
505 YYLIMIT = ZSTR_VAL(ctx->buf.s) + ZSTR_LEN(ctx->buf.s);
506
507 switch (STATE) {
508 case STATE_PLAIN: goto state_plain;
509 case STATE_TAG: goto state_tag;
510 case STATE_NEXT_ARG: goto state_next_arg;
511 case STATE_ARG: goto state_arg;
512 case STATE_BEFORE_VAL: goto state_before_val;
513 case STATE_VAL: goto state_val;
514 }
515
516
517 state_plain_begin:
518 STATE = STATE_PLAIN;
519
520 state_plain:
521 start = YYCURSOR;
522
523 #line 524 "ext/standard/url_scanner_ex.c"
524 {
525 YYCTYPE yych;
526 static const unsigned char yybm[] = {
527 128, 128, 128, 128, 128, 128, 128, 128,
528 128, 128, 128, 128, 128, 128, 128, 128,
529 128, 128, 128, 128, 128, 128, 128, 128,
530 128, 128, 128, 128, 128, 128, 128, 128,
531 128, 128, 128, 128, 128, 128, 128, 128,
532 128, 128, 128, 128, 128, 128, 128, 128,
533 128, 128, 128, 128, 128, 128, 128, 128,
534 128, 128, 128, 128, 0, 128, 128, 128,
535 128, 128, 128, 128, 128, 128, 128, 128,
536 128, 128, 128, 128, 128, 128, 128, 128,
537 128, 128, 128, 128, 128, 128, 128, 128,
538 128, 128, 128, 128, 128, 128, 128, 128,
539 128, 128, 128, 128, 128, 128, 128, 128,
540 128, 128, 128, 128, 128, 128, 128, 128,
541 128, 128, 128, 128, 128, 128, 128, 128,
542 128, 128, 128, 128, 128, 128, 128, 128,
543 128, 128, 128, 128, 128, 128, 128, 128,
544 128, 128, 128, 128, 128, 128, 128, 128,
545 128, 128, 128, 128, 128, 128, 128, 128,
546 128, 128, 128, 128, 128, 128, 128, 128,
547 128, 128, 128, 128, 128, 128, 128, 128,
548 128, 128, 128, 128, 128, 128, 128, 128,
549 128, 128, 128, 128, 128, 128, 128, 128,
550 128, 128, 128, 128, 128, 128, 128, 128,
551 128, 128, 128, 128, 128, 128, 128, 128,
552 128, 128, 128, 128, 128, 128, 128, 128,
553 128, 128, 128, 128, 128, 128, 128, 128,
554 128, 128, 128, 128, 128, 128, 128, 128,
555 128, 128, 128, 128, 128, 128, 128, 128,
556 128, 128, 128, 128, 128, 128, 128, 128,
557 128, 128, 128, 128, 128, 128, 128, 128,
558 128, 128, 128, 128, 128, 128, 128, 128,
559 };
560 if (YYLIMIT <= YYCURSOR) YYFILL(1);
561 yych = *YYCURSOR;
562 if (yybm[0+yych] & 128) {
563 goto yy2;
564 }
565 goto yy5;
566 yy2:
567 ++YYCURSOR;
568 if (YYLIMIT <= YYCURSOR) YYFILL(1);
569 yych = *YYCURSOR;
570 if (yybm[0+yych] & 128) {
571 goto yy2;
572 }
573 #line 527 "ext/standard/url_scanner_ex.re"
574 { passthru(STD_ARGS); goto state_plain; }
575 #line 576 "ext/standard/url_scanner_ex.c"
576 yy5:
577 ++YYCURSOR;
578 #line 526 "ext/standard/url_scanner_ex.re"
579 { passthru(STD_ARGS); STATE = STATE_TAG; goto state_tag; }
580 #line 581 "ext/standard/url_scanner_ex.c"
581 }
582 #line 528 "ext/standard/url_scanner_ex.re"
583
584
585 state_tag:
586 start = YYCURSOR;
587
588 #line 589 "ext/standard/url_scanner_ex.c"
589 {
590 YYCTYPE yych;
591 static const unsigned char yybm[] = {
592 0, 0, 0, 0, 0, 0, 0, 0,
593 0, 0, 0, 0, 0, 0, 0, 0,
594 0, 0, 0, 0, 0, 0, 0, 0,
595 0, 0, 0, 0, 0, 0, 0, 0,
596 0, 0, 0, 0, 0, 0, 0, 0,
597 0, 0, 0, 0, 0, 0, 0, 0,
598 0, 0, 0, 0, 0, 0, 0, 0,
599 0, 0, 128, 0, 0, 0, 0, 0,
600 0, 128, 128, 128, 128, 128, 128, 128,
601 128, 128, 128, 128, 128, 128, 128, 128,
602 128, 128, 128, 128, 128, 128, 128, 128,
603 128, 128, 128, 0, 0, 0, 0, 0,
604 0, 128, 128, 128, 128, 128, 128, 128,
605 128, 128, 128, 128, 128, 128, 128, 128,
606 128, 128, 128, 128, 128, 128, 128, 128,
607 128, 128, 128, 0, 0, 0, 0, 0,
608 0, 0, 0, 0, 0, 0, 0, 0,
609 0, 0, 0, 0, 0, 0, 0, 0,
610 0, 0, 0, 0, 0, 0, 0, 0,
611 0, 0, 0, 0, 0, 0, 0, 0,
612 0, 0, 0, 0, 0, 0, 0, 0,
613 0, 0, 0, 0, 0, 0, 0, 0,
614 0, 0, 0, 0, 0, 0, 0, 0,
615 0, 0, 0, 0, 0, 0, 0, 0,
616 0, 0, 0, 0, 0, 0, 0, 0,
617 0, 0, 0, 0, 0, 0, 0, 0,
618 0, 0, 0, 0, 0, 0, 0, 0,
619 0, 0, 0, 0, 0, 0, 0, 0,
620 0, 0, 0, 0, 0, 0, 0, 0,
621 0, 0, 0, 0, 0, 0, 0, 0,
622 0, 0, 0, 0, 0, 0, 0, 0,
623 0, 0, 0, 0, 0, 0, 0, 0,
624 };
625 if (YYLIMIT <= YYCURSOR) YYFILL(1);
626 yych = *YYCURSOR;
627 if (yybm[0+yych] & 128) {
628 goto yy11;
629 }
630 ++YYCURSOR;
631 #line 534 "ext/standard/url_scanner_ex.re"
632 { passthru(STD_ARGS); goto state_plain_begin; }
633 #line 634 "ext/standard/url_scanner_ex.c"
634 yy11:
635 ++YYCURSOR;
636 if (YYLIMIT <= YYCURSOR) YYFILL(1);
637 yych = *YYCURSOR;
638 if (yybm[0+yych] & 128) {
639 goto yy11;
640 }
641 #line 533 "ext/standard/url_scanner_ex.re"
642 { handle_tag(STD_ARGS); /* Sets STATE */; passthru(STD_ARGS); if (STATE == STATE_PLAIN) goto state_plain; else goto state_next_arg; }
643 #line 644 "ext/standard/url_scanner_ex.c"
644 }
645 #line 535 "ext/standard/url_scanner_ex.re"
646
647
648 state_next_arg_begin:
649 STATE = STATE_NEXT_ARG;
650
651 state_next_arg:
652 start = YYCURSOR;
653
654 #line 655 "ext/standard/url_scanner_ex.c"
655 {
656 YYCTYPE yych;
657 static const unsigned char yybm[] = {
658 0, 0, 0, 0, 0, 0, 0, 0,
659 0, 128, 128, 128, 0, 128, 0, 0,
660 0, 0, 0, 0, 0, 0, 0, 0,
661 0, 0, 0, 0, 0, 0, 0, 0,
662 128, 0, 0, 0, 0, 0, 0, 0,
663 0, 0, 0, 0, 0, 0, 0, 0,
664 0, 0, 0, 0, 0, 0, 0, 0,
665 0, 0, 0, 0, 0, 0, 0, 0,
666 0, 0, 0, 0, 0, 0, 0, 0,
667 0, 0, 0, 0, 0, 0, 0, 0,
668 0, 0, 0, 0, 0, 0, 0, 0,
669 0, 0, 0, 0, 0, 0, 0, 0,
670 0, 0, 0, 0, 0, 0, 0, 0,
671 0, 0, 0, 0, 0, 0, 0, 0,
672 0, 0, 0, 0, 0, 0, 0, 0,
673 0, 0, 0, 0, 0, 0, 0, 0,
674 0, 0, 0, 0, 0, 0, 0, 0,
675 0, 0, 0, 0, 0, 0, 0, 0,
676 0, 0, 0, 0, 0, 0, 0, 0,
677 0, 0, 0, 0, 0, 0, 0, 0,
678 0, 0, 0, 0, 0, 0, 0, 0,
679 0, 0, 0, 0, 0, 0, 0, 0,
680 0, 0, 0, 0, 0, 0, 0, 0,
681 0, 0, 0, 0, 0, 0, 0, 0,
682 0, 0, 0, 0, 0, 0, 0, 0,
683 0, 0, 0, 0, 0, 0, 0, 0,
684 0, 0, 0, 0, 0, 0, 0, 0,
685 0, 0, 0, 0, 0, 0, 0, 0,
686 0, 0, 0, 0, 0, 0, 0, 0,
687 0, 0, 0, 0, 0, 0, 0, 0,
688 0, 0, 0, 0, 0, 0, 0, 0,
689 0, 0, 0, 0, 0, 0, 0, 0,
690 };
691 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
692 yych = *YYCURSOR;
693 if (yybm[0+yych] & 128) {
694 goto yy18;
695 }
696 if (yych <= '>') {
697 if (yych == '/') goto yy21;
698 if (yych >= '>') goto yy22;
699 } else {
700 if (yych <= 'Z') {
701 if (yych >= 'A') goto yy24;
702 } else {
703 if (yych <= '`') goto yy16;
704 if (yych <= 'z') goto yy24;
705 }
706 }
707 yy16:
708 ++YYCURSOR;
709 yy17:
710 #line 546 "ext/standard/url_scanner_ex.re"
711 { passthru(STD_ARGS); goto state_plain_begin; }
712 #line 713 "ext/standard/url_scanner_ex.c"
713 yy18:
714 ++YYCURSOR;
715 if (YYLIMIT <= YYCURSOR) YYFILL(1);
716 yych = *YYCURSOR;
717 if (yybm[0+yych] & 128) {
718 goto yy18;
719 }
720 #line 544 "ext/standard/url_scanner_ex.re"
721 { passthru(STD_ARGS); goto state_next_arg; }
722 #line 723 "ext/standard/url_scanner_ex.c"
723 yy21:
724 yych = *++YYCURSOR;
725 if (yych != '>') goto yy17;
726 yy22:
727 ++YYCURSOR;
728 #line 543 "ext/standard/url_scanner_ex.re"
729 { passthru(STD_ARGS); handle_form(STD_ARGS); goto state_plain_begin; }
730 #line 731 "ext/standard/url_scanner_ex.c"
731 yy24:
732 ++YYCURSOR;
733 #line 545 "ext/standard/url_scanner_ex.re"
734 { --YYCURSOR; STATE = STATE_ARG; goto state_arg; }
735 #line 736 "ext/standard/url_scanner_ex.c"
736 }
737 #line 547 "ext/standard/url_scanner_ex.re"
738
739
740 state_arg:
741 start = YYCURSOR;
742
743 #line 744 "ext/standard/url_scanner_ex.c"
744 {
745 YYCTYPE yych;
746 static const unsigned char yybm[] = {
747 0, 0, 0, 0, 0, 0, 0, 0,
748 0, 0, 0, 0, 0, 0, 0, 0,
749 0, 0, 0, 0, 0, 0, 0, 0,
750 0, 0, 0, 0, 0, 0, 0, 0,
751 0, 0, 0, 0, 0, 0, 0, 0,
752 0, 0, 0, 0, 0, 128, 0, 0,
753 0, 0, 0, 0, 0, 0, 0, 0,
754 0, 0, 0, 0, 0, 0, 0, 0,
755 0, 128, 128, 128, 128, 128, 128, 128,
756 128, 128, 128, 128, 128, 128, 128, 128,
757 128, 128, 128, 128, 128, 128, 128, 128,
758 128, 128, 128, 0, 0, 0, 0, 0,
759 0, 128, 128, 128, 128, 128, 128, 128,
760 128, 128, 128, 128, 128, 128, 128, 128,
761 128, 128, 128, 128, 128, 128, 128, 128,
762 128, 128, 128, 0, 0, 0, 0, 0,
763 0, 0, 0, 0, 0, 0, 0, 0,
764 0, 0, 0, 0, 0, 0, 0, 0,
765 0, 0, 0, 0, 0, 0, 0, 0,
766 0, 0, 0, 0, 0, 0, 0, 0,
767 0, 0, 0, 0, 0, 0, 0, 0,
768 0, 0, 0, 0, 0, 0, 0, 0,
769 0, 0, 0, 0, 0, 0, 0, 0,
770 0, 0, 0, 0, 0, 0, 0, 0,
771 0, 0, 0, 0, 0, 0, 0, 0,
772 0, 0, 0, 0, 0, 0, 0, 0,
773 0, 0, 0, 0, 0, 0, 0, 0,
774 0, 0, 0, 0, 0, 0, 0, 0,
775 0, 0, 0, 0, 0, 0, 0, 0,
776 0, 0, 0, 0, 0, 0, 0, 0,
777 0, 0, 0, 0, 0, 0, 0, 0,
778 0, 0, 0, 0, 0, 0, 0, 0,
779 };
780 if (YYLIMIT <= YYCURSOR) YYFILL(1);
781 yych = *YYCURSOR;
782 if (yych <= '@') goto yy28;
783 if (yych <= 'Z') goto yy30;
784 if (yych <= '`') goto yy28;
785 if (yych <= 'z') goto yy30;
786 yy28:
787 ++YYCURSOR;
788 #line 553 "ext/standard/url_scanner_ex.re"
789 { passthru(STD_ARGS); STATE = STATE_NEXT_ARG; goto state_next_arg; }
790 #line 791 "ext/standard/url_scanner_ex.c"
791 yy30:
792 ++YYCURSOR;
793 if (YYLIMIT <= YYCURSOR) YYFILL(1);
794 yych = *YYCURSOR;
795 if (yybm[0+yych] & 128) {
796 goto yy30;
797 }
798 #line 552 "ext/standard/url_scanner_ex.re"
799 { passthru(STD_ARGS); handle_arg(STD_ARGS); STATE = STATE_BEFORE_VAL; goto state_before_val; }
800 #line 801 "ext/standard/url_scanner_ex.c"
801 }
802 #line 554 "ext/standard/url_scanner_ex.re"
803
804
805 state_before_val:
806 start = YYCURSOR;
807
808 #line 809 "ext/standard/url_scanner_ex.c"
809 {
810 YYCTYPE yych;
811 static const unsigned char yybm[] = {
812 0, 0, 0, 0, 0, 0, 0, 0,
813 0, 0, 0, 0, 0, 0, 0, 0,
814 0, 0, 0, 0, 0, 0, 0, 0,
815 0, 0, 0, 0, 0, 0, 0, 0,
816 128, 0, 0, 0, 0, 0, 0, 0,
817 0, 0, 0, 0, 0, 0, 0, 0,
818 0, 0, 0, 0, 0, 0, 0, 0,
819 0, 0, 0, 0, 0, 0, 0, 0,
820 0, 0, 0, 0, 0, 0, 0, 0,
821 0, 0, 0, 0, 0, 0, 0, 0,
822 0, 0, 0, 0, 0, 0, 0, 0,
823 0, 0, 0, 0, 0, 0, 0, 0,
824 0, 0, 0, 0, 0, 0, 0, 0,
825 0, 0, 0, 0, 0, 0, 0, 0,
826 0, 0, 0, 0, 0, 0, 0, 0,
827 0, 0, 0, 0, 0, 0, 0, 0,
828 0, 0, 0, 0, 0, 0, 0, 0,
829 0, 0, 0, 0, 0, 0, 0, 0,
830 0, 0, 0, 0, 0, 0, 0, 0,
831 0, 0, 0, 0, 0, 0, 0, 0,
832 0, 0, 0, 0, 0, 0, 0, 0,
833 0, 0, 0, 0, 0, 0, 0, 0,
834 0, 0, 0, 0, 0, 0, 0, 0,
835 0, 0, 0, 0, 0, 0, 0, 0,
836 0, 0, 0, 0, 0, 0, 0, 0,
837 0, 0, 0, 0, 0, 0, 0, 0,
838 0, 0, 0, 0, 0, 0, 0, 0,
839 0, 0, 0, 0, 0, 0, 0, 0,
840 0, 0, 0, 0, 0, 0, 0, 0,
841 0, 0, 0, 0, 0, 0, 0, 0,
842 0, 0, 0, 0, 0, 0, 0, 0,
843 0, 0, 0, 0, 0, 0, 0, 0,
844 };
845 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
846 yych = *YYCURSOR;
847 if (yych == ' ') goto yy37;
848 if (yych == '=') goto yy38;
849 ++YYCURSOR;
850 yy36:
851 #line 560 "ext/standard/url_scanner_ex.re"
852 { --YYCURSOR; goto state_next_arg_begin; }
853 #line 854 "ext/standard/url_scanner_ex.c"
854 yy37:
855 yych = *(YYMARKER = ++YYCURSOR);
856 if (yych == ' ') goto yy41;
857 if (yych != '=') goto yy36;
858 yy38:
859 ++YYCURSOR;
860 if (YYLIMIT <= YYCURSOR) YYFILL(1);
861 yych = *YYCURSOR;
862 if (yybm[0+yych] & 128) {
863 goto yy38;
864 }
865 #line 559 "ext/standard/url_scanner_ex.re"
866 { passthru(STD_ARGS); STATE = STATE_VAL; goto state_val; }
867 #line 868 "ext/standard/url_scanner_ex.c"
868 yy41:
869 ++YYCURSOR;
870 if (YYLIMIT <= YYCURSOR) YYFILL(1);
871 yych = *YYCURSOR;
872 if (yych == ' ') goto yy41;
873 if (yych == '=') goto yy38;
874 YYCURSOR = YYMARKER;
875 goto yy36;
876 }
877 #line 561 "ext/standard/url_scanner_ex.re"
878
879
880
881 state_val:
882 start = YYCURSOR;
883
884 #line 885 "ext/standard/url_scanner_ex.c"
885 {
886 YYCTYPE yych;
887 static const unsigned char yybm[] = {
888 224, 224, 224, 224, 224, 224, 224, 224,
889 224, 192, 192, 224, 224, 192, 224, 224,
890 224, 224, 224, 224, 224, 224, 224, 224,
891 224, 224, 224, 224, 224, 224, 224, 224,
892 192, 224, 128, 224, 224, 224, 224, 64,
893 224, 224, 224, 224, 224, 224, 224, 224,
894 224, 224, 224, 224, 224, 224, 224, 224,
895 224, 224, 224, 224, 224, 224, 0, 224,
896 224, 224, 224, 224, 224, 224, 224, 224,
897 224, 224, 224, 224, 224, 224, 224, 224,
898 224, 224, 224, 224, 224, 224, 224, 224,
899 224, 224, 224, 224, 224, 224, 224, 224,
900 224, 224, 224, 224, 224, 224, 224, 224,
901 224, 224, 224, 224, 224, 224, 224, 224,
902 224, 224, 224, 224, 224, 224, 224, 224,
903 224, 224, 224, 224, 224, 224, 224, 224,
904 224, 224, 224, 224, 224, 224, 224, 224,
905 224, 224, 224, 224, 224, 224, 224, 224,
906 224, 224, 224, 224, 224, 224, 224, 224,
907 224, 224, 224, 224, 224, 224, 224, 224,
908 224, 224, 224, 224, 224, 224, 224, 224,
909 224, 224, 224, 224, 224, 224, 224, 224,
910 224, 224, 224, 224, 224, 224, 224, 224,
911 224, 224, 224, 224, 224, 224, 224, 224,
912 224, 224, 224, 224, 224, 224, 224, 224,
913 224, 224, 224, 224, 224, 224, 224, 224,
914 224, 224, 224, 224, 224, 224, 224, 224,
915 224, 224, 224, 224, 224, 224, 224, 224,
916 224, 224, 224, 224, 224, 224, 224, 224,
917 224, 224, 224, 224, 224, 224, 224, 224,
918 224, 224, 224, 224, 224, 224, 224, 224,
919 224, 224, 224, 224, 224, 224, 224, 224,
920 };
921 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
922 yych = *YYCURSOR;
923 if (yybm[0+yych] & 32) {
924 goto yy46;
925 }
926 if (yych <= ' ') goto yy49;
927 if (yych <= '"') goto yy51;
928 if (yych <= '\'') goto yy52;
929 goto yy49;
930 yy46:
931 ++YYCURSOR;
932 if (YYLIMIT <= YYCURSOR) YYFILL(1);
933 yych = *YYCURSOR;
934 if (yybm[0+yych] & 32) {
935 goto yy46;
936 }
937 #line 569 "ext/standard/url_scanner_ex.re"
938 { handle_val(STD_ARGS, 0, ' '); goto state_next_arg_begin; }
939 #line 940 "ext/standard/url_scanner_ex.c"
940 yy49:
941 ++YYCURSOR;
942 yy50:
943 #line 570 "ext/standard/url_scanner_ex.re"
944 { passthru(STD_ARGS); goto state_next_arg_begin; }
945 #line 946 "ext/standard/url_scanner_ex.c"
946 yy51:
947 yych = *(YYMARKER = ++YYCURSOR);
948 if (yych == '>') goto yy50;
949 goto yy54;
950 yy52:
951 yych = *(YYMARKER = ++YYCURSOR);
952 if (yych == '>') goto yy50;
953 goto yy59;
954 yy53:
955 ++YYCURSOR;
956 if (YYLIMIT <= YYCURSOR) YYFILL(1);
957 yych = *YYCURSOR;
958 yy54:
959 if (yybm[0+yych] & 64) {
960 goto yy53;
961 }
962 if (yych <= '"') goto yy56;
963 yy55:
964 YYCURSOR = YYMARKER;
965 goto yy50;
966 yy56:
967 ++YYCURSOR;
968 #line 567 "ext/standard/url_scanner_ex.re"
969 { handle_val(STD_ARGS, 1, '"'); goto state_next_arg_begin; }
970 #line 971 "ext/standard/url_scanner_ex.c"
971 yy58:
972 ++YYCURSOR;
973 if (YYLIMIT <= YYCURSOR) YYFILL(1);
974 yych = *YYCURSOR;
975 yy59:
976 if (yybm[0+yych] & 128) {
977 goto yy58;
978 }
979 if (yych >= '(') goto yy55;
980 ++YYCURSOR;
981 #line 568 "ext/standard/url_scanner_ex.re"
982 { handle_val(STD_ARGS, 1, '\''); goto state_next_arg_begin; }
983 #line 984 "ext/standard/url_scanner_ex.c"
984 }
985 #line 571 "ext/standard/url_scanner_ex.re"
986
987
988 stop:
989 if (YYLIMIT < start) {
990 /* XXX: Crash avoidance. Need to work with reporter to figure out what goes wrong */
991 rest = 0;
992 } else {
993 rest = YYLIMIT - start;
994 scdebug(("stopped in state %d at pos %d (%d:%c) %d\n", STATE, YYCURSOR - ctx->buf.c, *YYCURSOR, *YYCURSOR, rest));
995 }
996
997 if (rest) memmove(ZSTR_VAL(ctx->buf.s), start, rest);
998 ZSTR_LEN(ctx->buf.s) = rest;
999 }
1000
1001
php_url_scanner_adapt_single_url(const char * url,size_t urllen,const char * name,const char * value,size_t * newlen,int encode)1002 PHPAPI char *php_url_scanner_adapt_single_url(const char *url, size_t urllen, const char *name, const char *value, size_t *newlen, int encode)
1003 {
1004 char *result;
1005 smart_str surl = {0};
1006 smart_str buf = {0};
1007 smart_str url_app = {0};
1008 zend_string *encoded;
1009
1010 smart_str_appendl(&surl, url, urllen);
1011
1012 if (encode) {
1013 encoded = php_raw_url_encode(name, strlen(name));
1014 smart_str_appendl(&url_app, ZSTR_VAL(encoded), ZSTR_LEN(encoded));
1015 zend_string_free(encoded);
1016 } else {
1017 smart_str_appends(&url_app, name);
1018 }
1019 smart_str_appendc(&url_app, '=');
1020 if (encode) {
1021 encoded = php_raw_url_encode(value, strlen(value));
1022 smart_str_appendl(&url_app, ZSTR_VAL(encoded), ZSTR_LEN(encoded));
1023 zend_string_free(encoded);
1024 } else {
1025 smart_str_appends(&url_app, value);
1026 }
1027
1028 append_modified_url(&surl, &buf, &url_app, PG(arg_separator).output);
1029
1030 smart_str_0(&buf);
1031 if (newlen) *newlen = ZSTR_LEN(buf.s);
1032 result = estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
1033
1034 smart_str_free(&url_app);
1035 smart_str_free(&buf);
1036
1037 return result;
1038 }
1039
1040
url_adapt_ext(const char * src,size_t srclen,size_t * newlen,zend_bool do_flush,url_adapt_state_ex_t * ctx)1041 static char *url_adapt_ext(const char *src, size_t srclen, size_t *newlen, zend_bool do_flush, url_adapt_state_ex_t *ctx)
1042 {
1043 char *retval;
1044
1045 xx_mainloop(ctx, src, srclen);
1046
1047 if (!ctx->result.s) {
1048 smart_str_appendl(&ctx->result, "", 0);
1049 *newlen = 0;
1050 } else {
1051 *newlen = ZSTR_LEN(ctx->result.s);
1052 }
1053 smart_str_0(&ctx->result);
1054 if (do_flush) {
1055 smart_str_append(&ctx->result, ctx->buf.s);
1056 *newlen += ZSTR_LEN(ctx->buf.s);
1057 smart_str_free(&ctx->buf);
1058 smart_str_free(&ctx->val);
1059 smart_str_free(&ctx->attr_val);
1060 }
1061 retval = estrndup(ZSTR_VAL(ctx->result.s), ZSTR_LEN(ctx->result.s));
1062 smart_str_free(&ctx->result);
1063 return retval;
1064 }
1065
php_url_scanner_ex_activate(int type)1066 static int php_url_scanner_ex_activate(int type)
1067 {
1068 url_adapt_state_ex_t *ctx;
1069
1070 if (type) {
1071 ctx = &BG(url_adapt_session_ex);
1072 } else {
1073 ctx = &BG(url_adapt_output_ex);
1074 }
1075
1076 memset(ctx, 0, ((size_t) &((url_adapt_state_ex_t *)0)->tags));
1077
1078 return SUCCESS;
1079 }
1080
php_url_scanner_ex_deactivate(int type)1081 static int php_url_scanner_ex_deactivate(int type)
1082 {
1083 url_adapt_state_ex_t *ctx;
1084
1085 if (type) {
1086 ctx = &BG(url_adapt_session_ex);
1087 } else {
1088 ctx = &BG(url_adapt_output_ex);
1089 }
1090
1091 smart_str_free(&ctx->result);
1092 smart_str_free(&ctx->buf);
1093 smart_str_free(&ctx->tag);
1094 smart_str_free(&ctx->arg);
1095 smart_str_free(&ctx->attr_val);
1096
1097 return SUCCESS;
1098 }
1099
php_url_scanner_session_handler_impl(char * output,size_t output_len,char ** handled_output,size_t * handled_output_len,int mode,int type)1100 static inline void php_url_scanner_session_handler_impl(char *output, size_t output_len, char **handled_output, size_t *handled_output_len, int mode, int type)
1101 {
1102 size_t len;
1103 url_adapt_state_ex_t *url_state;
1104
1105 if (type) {
1106 url_state = &BG(url_adapt_session_ex);
1107 } else {
1108 url_state = &BG(url_adapt_output_ex);
1109 }
1110
1111 if (ZSTR_LEN(url_state->url_app.s) != 0) {
1112 *handled_output = url_adapt_ext(output, output_len, &len, (zend_bool) (mode & (PHP_OUTPUT_HANDLER_END | PHP_OUTPUT_HANDLER_CONT | PHP_OUTPUT_HANDLER_FLUSH | PHP_OUTPUT_HANDLER_FINAL) ? 1 : 0), url_state);
1113 if (sizeof(uint) < sizeof(size_t)) {
1114 if (len > UINT_MAX)
1115 len = UINT_MAX;
1116 }
1117 *handled_output_len = len;
1118 } else if (ZSTR_LEN(url_state->url_app.s) == 0) {
1119 url_adapt_state_ex_t *ctx = url_state;
1120 if (ctx->buf.s && ZSTR_LEN(ctx->buf.s)) {
1121 smart_str_append(&ctx->result, ctx->buf.s);
1122 smart_str_appendl(&ctx->result, output, output_len);
1123
1124 *handled_output = estrndup(ZSTR_VAL(ctx->result.s), ZSTR_LEN(ctx->result.s));
1125 *handled_output_len = ZSTR_LEN(ctx->buf.s) + output_len;
1126
1127 smart_str_free(&ctx->buf);
1128 smart_str_free(&ctx->result);
1129 } else {
1130 *handled_output = estrndup(output, *handled_output_len = output_len);
1131 }
1132 } else {
1133 *handled_output = NULL;
1134 }
1135 }
1136
php_url_scanner_session_handler(char * output,size_t output_len,char ** handled_output,size_t * handled_output_len,int mode)1137 static void php_url_scanner_session_handler(char *output, size_t output_len, char **handled_output, size_t *handled_output_len, int mode)
1138 {
1139 php_url_scanner_session_handler_impl(output, output_len, handled_output, handled_output_len, mode, 1);
1140 }
1141
php_url_scanner_output_handler(char * output,size_t output_len,char ** handled_output,size_t * handled_output_len,int mode)1142 static void php_url_scanner_output_handler(char *output, size_t output_len, char **handled_output, size_t *handled_output_len, int mode)
1143 {
1144 php_url_scanner_session_handler_impl(output, output_len, handled_output, handled_output_len, mode, 0);
1145 }
1146
php_url_scanner_add_var_impl(char * name,size_t name_len,char * value,size_t value_len,int encode,int type)1147 static inline int php_url_scanner_add_var_impl(char *name, size_t name_len, char *value, size_t value_len, int encode, int type)
1148 {
1149 smart_str sname = {0};
1150 smart_str svalue = {0};
1151 smart_str hname = {0};
1152 smart_str hvalue = {0};
1153 zend_string *encoded;
1154 url_adapt_state_ex_t *url_state;
1155 php_output_handler_func_t handler;
1156
1157 if (type) {
1158 url_state = &BG(url_adapt_session_ex);
1159 handler = php_url_scanner_session_handler;
1160 } else {
1161 url_state = &BG(url_adapt_output_ex);
1162 handler = php_url_scanner_output_handler;
1163 }
1164
1165 if (!url_state->active) {
1166 php_url_scanner_ex_activate(type);
1167 php_output_start_internal(ZEND_STRL("URL-Rewriter"), handler, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
1168 url_state->active = 1;
1169 }
1170
1171 if (url_state->url_app.s && ZSTR_LEN(url_state->url_app.s) != 0) {
1172 smart_str_appends(&url_state->url_app, PG(arg_separator).output);
1173 }
1174
1175 if (encode) {
1176 encoded = php_raw_url_encode(name, name_len);
1177 smart_str_appendl(&sname, ZSTR_VAL(encoded), ZSTR_LEN(encoded)); zend_string_free(encoded);
1178 encoded = php_raw_url_encode(value, value_len);
1179 smart_str_appendl(&svalue, ZSTR_VAL(encoded), ZSTR_LEN(encoded)); zend_string_free(encoded);
1180 encoded = php_escape_html_entities_ex((unsigned char*)name, name_len, 0, ENT_QUOTES|ENT_SUBSTITUTE, SG(default_charset), 0);
1181 smart_str_appendl(&hname, ZSTR_VAL(encoded), ZSTR_LEN(encoded)); zend_string_free(encoded);
1182 encoded = php_escape_html_entities_ex((unsigned char*)value, value_len, 0, ENT_QUOTES|ENT_SUBSTITUTE, SG(default_charset), 0);
1183 smart_str_appendl(&hvalue, ZSTR_VAL(encoded), ZSTR_LEN(encoded)); zend_string_free(encoded);
1184 } else {
1185 smart_str_appendl(&sname, name, name_len);
1186 smart_str_appendl(&svalue, value, value_len);
1187 smart_str_appendl(&hname, name, name_len);
1188 smart_str_appendl(&hvalue, value, value_len);
1189 }
1190
1191 smart_str_append_smart_str(&url_state->url_app, &sname);
1192 smart_str_appendc(&url_state->url_app, '=');
1193 smart_str_append_smart_str(&url_state->url_app, &svalue);
1194
1195 smart_str_appends(&url_state->form_app, "<input type=\"hidden\" name=\"");
1196 smart_str_append_smart_str(&url_state->form_app, &hname);
1197 smart_str_appends(&url_state->form_app, "\" value=\"");
1198 smart_str_append_smart_str(&url_state->form_app, &hvalue);
1199 smart_str_appends(&url_state->form_app, "\" />");
1200
1201 smart_str_free(&sname);
1202 smart_str_free(&svalue);
1203 smart_str_free(&hname);
1204 smart_str_free(&hvalue);
1205
1206 return SUCCESS;
1207 }
1208
1209
php_url_scanner_add_session_var(char * name,size_t name_len,char * value,size_t value_len,int encode)1210 PHPAPI int php_url_scanner_add_session_var(char *name, size_t name_len, char *value, size_t value_len, int encode)
1211 {
1212 return php_url_scanner_add_var_impl(name, name_len, value, value_len, encode, 1);
1213 }
1214
1215
php_url_scanner_add_var(char * name,size_t name_len,char * value,size_t value_len,int encode)1216 PHPAPI int php_url_scanner_add_var(char *name, size_t name_len, char *value, size_t value_len, int encode)
1217 {
1218 return php_url_scanner_add_var_impl(name, name_len, value, value_len, encode, 0);
1219 }
1220
1221
php_url_scanner_reset_vars_impl(int type)1222 static inline void php_url_scanner_reset_vars_impl(int type) {
1223 url_adapt_state_ex_t *url_state;
1224
1225 if (type) {
1226 url_state = &BG(url_adapt_session_ex);
1227 } else {
1228 url_state = &BG(url_adapt_output_ex);
1229 }
1230
1231 if (url_state->form_app.s) {
1232 ZSTR_LEN(url_state->form_app.s) = 0;
1233 }
1234 if (url_state->url_app.s) {
1235 ZSTR_LEN(url_state->url_app.s) = 0;
1236 }
1237 }
1238
1239
php_url_scanner_reset_session_vars(void)1240 PHPAPI int php_url_scanner_reset_session_vars(void)
1241 {
1242 php_url_scanner_reset_vars_impl(1);
1243 return SUCCESS;
1244 }
1245
1246
php_url_scanner_reset_vars(void)1247 PHPAPI int php_url_scanner_reset_vars(void)
1248 {
1249 php_url_scanner_reset_vars_impl(0);
1250 return SUCCESS;
1251 }
1252
1253
php_url_scanner_reset_var_impl(zend_string * name,int encode,int type)1254 static inline int php_url_scanner_reset_var_impl(zend_string *name, int encode, int type)
1255 {
1256 char *start, *end, *limit;
1257 size_t separator_len;
1258 smart_str sname = {0};
1259 smart_str hname = {0};
1260 smart_str url_app = {0};
1261 smart_str form_app = {0};
1262 zend_string *encoded;
1263 int ret = SUCCESS;
1264 zend_bool sep_removed = 0;
1265 url_adapt_state_ex_t *url_state;
1266
1267 if (type) {
1268 url_state = &BG(url_adapt_session_ex);
1269 } else {
1270 url_state = &BG(url_adapt_output_ex);
1271 }
1272
1273 /* Short circuit check. Only check url_app. */
1274 if (!url_state->url_app.s || !ZSTR_LEN(url_state->url_app.s)) {
1275 return SUCCESS;
1276 }
1277
1278 if (encode) {
1279 encoded = php_raw_url_encode(ZSTR_VAL(name), ZSTR_LEN(name));
1280 smart_str_appendl(&sname, ZSTR_VAL(encoded), ZSTR_LEN(encoded));
1281 zend_string_free(encoded);
1282 encoded = php_escape_html_entities_ex((unsigned char *)ZSTR_VAL(name), ZSTR_LEN(name), 0, ENT_QUOTES|ENT_SUBSTITUTE, SG(default_charset), 0);
1283 smart_str_appendl(&hname, ZSTR_VAL(encoded), ZSTR_LEN(encoded));
1284 zend_string_free(encoded);
1285 } else {
1286 smart_str_appendl(&sname, ZSTR_VAL(name), ZSTR_LEN(name));
1287 smart_str_appendl(&hname, ZSTR_VAL(name), ZSTR_LEN(name));
1288 }
1289 smart_str_0(&sname);
1290 smart_str_0(&hname);
1291
1292 smart_str_append_smart_str(&url_app, &sname);
1293 smart_str_appendc(&url_app, '=');
1294 smart_str_0(&url_app);
1295
1296 smart_str_appends(&form_app, "<input type=\"hidden\" name=\"");
1297 smart_str_append_smart_str(&form_app, &hname);
1298 smart_str_appends(&form_app, "\" value=\"");
1299 smart_str_0(&form_app);
1300
1301 /* Short circuit check. Only check url_app. */
1302 start = (char *) php_memnstr(ZSTR_VAL(url_state->url_app.s),
1303 ZSTR_VAL(url_app.s), ZSTR_LEN(url_app.s),
1304 ZSTR_VAL(url_state->url_app.s) + ZSTR_LEN(url_state->url_app.s));
1305 if (!start) {
1306 ret = FAILURE;
1307 goto finish;
1308 }
1309
1310 /* Get end of url var */
1311 limit = ZSTR_VAL(url_state->url_app.s) + ZSTR_LEN(url_state->url_app.s);
1312 end = start + ZSTR_LEN(url_app.s);
1313 separator_len = strlen(PG(arg_separator).output);
1314 while (end < limit) {
1315 if (!memcmp(end, PG(arg_separator).output, separator_len)) {
1316 end += separator_len;
1317 sep_removed = 1;
1318 break;
1319 }
1320 end++;
1321 }
1322 /* Remove all when this is the only rewrite var */
1323 if (ZSTR_LEN(url_state->url_app.s) == end - start) {
1324 php_url_scanner_reset_vars_impl(type);
1325 goto finish;
1326 }
1327 /* Check preceding separator */
1328 if (!sep_removed
1329 && (size_t)(start - PG(arg_separator).output) >= separator_len
1330 && !memcmp(start - separator_len, PG(arg_separator).output, separator_len)) {
1331 start -= separator_len;
1332 }
1333 /* Remove partially */
1334 memmove(start, end,
1335 ZSTR_LEN(url_state->url_app.s) - (end - ZSTR_VAL(url_state->url_app.s)));
1336 ZSTR_LEN(url_state->url_app.s) -= end - start;
1337 ZSTR_VAL(url_state->url_app.s)[ZSTR_LEN(url_state->url_app.s)] = '\0';
1338
1339 /* Remove form var */
1340 start = (char *) php_memnstr(ZSTR_VAL(url_state->form_app.s),
1341 ZSTR_VAL(form_app.s), ZSTR_LEN(form_app.s),
1342 ZSTR_VAL(url_state->form_app.s) + ZSTR_LEN(url_state->form_app.s));
1343 if (!start) {
1344 /* Should not happen */
1345 ret = FAILURE;
1346 php_url_scanner_reset_vars_impl(type);
1347 goto finish;
1348 }
1349 /* Get end of form var */
1350 limit = ZSTR_VAL(url_state->form_app.s) + ZSTR_LEN(url_state->form_app.s);
1351 end = start + ZSTR_LEN(form_app.s);
1352 while (end < limit) {
1353 if (*end == '>') {
1354 end += 1;
1355 break;
1356 }
1357 end++;
1358 }
1359 /* Remove partially */
1360 memmove(start, end,
1361 ZSTR_LEN(url_state->form_app.s) - (end - ZSTR_VAL(url_state->form_app.s)));
1362 ZSTR_LEN(url_state->form_app.s) -= end - start;
1363 ZSTR_VAL(url_state->form_app.s)[ZSTR_LEN(url_state->form_app.s)] = '\0';
1364
1365 finish:
1366 smart_str_free(&url_app);
1367 smart_str_free(&form_app);
1368 smart_str_free(&sname);
1369 smart_str_free(&hname);
1370 return ret;
1371 }
1372
1373
php_url_scanner_reset_session_var(zend_string * name,int encode)1374 PHPAPI int php_url_scanner_reset_session_var(zend_string *name, int encode)
1375 {
1376 return php_url_scanner_reset_var_impl(name, encode, 1);
1377 }
1378
1379
php_url_scanner_reset_var(zend_string * name,int encode)1380 PHPAPI int php_url_scanner_reset_var(zend_string *name, int encode)
1381 {
1382 return php_url_scanner_reset_var_impl(name, encode, 0);
1383 }
1384
1385
PHP_MINIT_FUNCTION(url_scanner)1386 PHP_MINIT_FUNCTION(url_scanner)
1387 {
1388 REGISTER_INI_ENTRIES();
1389 return SUCCESS;
1390 }
1391
PHP_MSHUTDOWN_FUNCTION(url_scanner)1392 PHP_MSHUTDOWN_FUNCTION(url_scanner)
1393 {
1394 UNREGISTER_INI_ENTRIES();
1395
1396 return SUCCESS;
1397 }
1398
PHP_RINIT_FUNCTION(url_scanner)1399 PHP_RINIT_FUNCTION(url_scanner)
1400 {
1401 BG(url_adapt_session_ex).active = 0;
1402 BG(url_adapt_session_ex).tag_type = 0;
1403 BG(url_adapt_session_ex).attr_type = 0;
1404 BG(url_adapt_output_ex).active = 0;
1405 BG(url_adapt_output_ex).tag_type = 0;
1406 BG(url_adapt_output_ex).attr_type = 0;
1407 return SUCCESS;
1408 }
1409
PHP_RSHUTDOWN_FUNCTION(url_scanner)1410 PHP_RSHUTDOWN_FUNCTION(url_scanner)
1411 {
1412 if (BG(url_adapt_session_ex).active) {
1413 php_url_scanner_ex_deactivate(1);
1414 BG(url_adapt_session_ex).active = 0;
1415 BG(url_adapt_session_ex).tag_type = 0;
1416 BG(url_adapt_session_ex).attr_type = 0;
1417 }
1418 smart_str_free(&BG(url_adapt_session_ex).form_app);
1419 smart_str_free(&BG(url_adapt_session_ex).url_app);
1420
1421 if (BG(url_adapt_output_ex).active) {
1422 php_url_scanner_ex_deactivate(0);
1423 BG(url_adapt_output_ex).active = 0;
1424 BG(url_adapt_output_ex).tag_type = 0;
1425 BG(url_adapt_output_ex).attr_type = 0;
1426 }
1427 smart_str_free(&BG(url_adapt_output_ex).form_app);
1428 smart_str_free(&BG(url_adapt_output_ex).url_app);
1429
1430 return SUCCESS;
1431 }
1432