From cf3ef363232af040b9ec63ecd23b603f7acf3751 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 16 Feb 2017 17:24:07 +0100 Subject: [PATCH] Fix memory errors in url rewriter Strings aren't terminated here... --- ext/standard/url_scanner_ex.c | 420 ++++++++++++++------------------- ext/standard/url_scanner_ex.re | 9 +- 2 files changed, 187 insertions(+), 242 deletions(-) diff --git a/ext/standard/url_scanner_ex.c b/ext/standard/url_scanner_ex.c index b6663bb9031..4469bb5e08c 100644 --- a/ext/standard/url_scanner_ex.c +++ b/ext/standard/url_scanner_ex.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.14.3 */ +/* Generated by re2c 0.16 */ #line 1 "ext/standard/url_scanner_ex.re" /* +----------------------------------------------------------------------+ @@ -35,6 +35,7 @@ #include "php_ini.h" #include "php_globals.h" +#include "php_string.h" #define STATE_TAG SOME_OTHER_STATE_TAG #include "basic_functions.h" #include "url.h" @@ -100,7 +101,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("url_rewriter.tags", "a=href,area=href,frame=src,form=,fieldset=", PHP_INI_ALL, OnUpdateTags, url_adapt_state_ex, php_basic_globals, basic_globals) PHP_INI_END() -#line 107 "ext/standard/url_scanner_ex.re" +#line 108 "ext/standard/url_scanner_ex.re" #define YYFILL(n) goto done @@ -119,7 +120,8 @@ static inline void append_modified_url(smart_str *url, smart_str *dest, smart_st * Don't modify "//example.com" full path, unless * HTTP_HOST matches. */ - if (ZSTR_VAL(url->s)[0] == '/' && ZSTR_VAL(url->s)[1] == '/') { + if (ZSTR_LEN(url->s) > 2 && ZSTR_VAL(url->s)[0] == '/' && ZSTR_VAL(url->s)[1] == '/') { + const char *end_chars = "/\"'?>\r\n"; zval *tmp = NULL, *http_host = NULL; size_t target_len, host_len; if ((!(tmp = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_SERVER")))) @@ -129,10 +131,13 @@ static inline void append_modified_url(smart_str *url, smart_str *dest, smart_st smart_str_append_smart_str(dest, url); return; } + /* HTTP_HOST could be "example.com:8888", etc. */ /* Need to find end of URL in buffer */ host_len = strcspn(Z_STRVAL_P(http_host), ":"); - target_len = strcspn(ZSTR_VAL(url->s)+2, "/\"'?>\r\n"); + target_len = php_strcspn( + ZSTR_VAL(url->s) + 2, (char *) end_chars, + ZSTR_VAL(url->s) + ZSTR_LEN(url->s), (char *) end_chars + strlen(end_chars)); if (host_len && host_len == target_len && strncasecmp(Z_STRVAL_P(http_host), ZSTR_VAL(url->s)+2, host_len)) { @@ -145,7 +150,7 @@ static inline void append_modified_url(smart_str *url, smart_str *dest, smart_st scan: -#line 149 "ext/standard/url_scanner_ex.c" +#line 154 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -182,40 +187,41 @@ scan: 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, }; - if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; if (yybm[0+yych] & 128) { - goto yy8; + goto yy2; } - if (yych <= '#') goto yy6; - if (yych >= ';') goto yy4; - ++YYCURSOR; -#line 151 "ext/standard/url_scanner_ex.re" - { smart_str_append_smart_str(dest, url); return; } -#line 197 "ext/standard/url_scanner_ex.c" -yy4: - ++YYCURSOR; -#line 152 "ext/standard/url_scanner_ex.re" - { sep = separator; goto scan; } -#line 202 "ext/standard/url_scanner_ex.c" -yy6: - ++YYCURSOR; -#line 153 "ext/standard/url_scanner_ex.re" - { bash = p - 1; goto done; } -#line 207 "ext/standard/url_scanner_ex.c" -yy8: + if (yych <= '#') goto yy5; + if (yych <= ':') goto yy7; + goto yy9; +yy2: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; if (yybm[0+yych] & 128) { - goto yy8; + goto yy2; } -#line 154 "ext/standard/url_scanner_ex.re" +#line 159 "ext/standard/url_scanner_ex.re" { goto scan; } -#line 217 "ext/standard/url_scanner_ex.c" +#line 208 "ext/standard/url_scanner_ex.c" +yy5: + ++YYCURSOR; +#line 158 "ext/standard/url_scanner_ex.re" + { bash = p - 1; goto done; } +#line 213 "ext/standard/url_scanner_ex.c" +yy7: + ++YYCURSOR; +#line 156 "ext/standard/url_scanner_ex.re" + { smart_str_append_smart_str(dest, url); return; } +#line 218 "ext/standard/url_scanner_ex.c" +yy9: + ++YYCURSOR; +#line 157 "ext/standard/url_scanner_ex.re" + { sep = separator; goto scan; } +#line 223 "ext/standard/url_scanner_ex.c" } -#line 155 "ext/standard/url_scanner_ex.re" +#line 160 "ext/standard/url_scanner_ex.re" done: @@ -400,7 +406,7 @@ state_plain_begin: state_plain: start = YYCURSOR; -#line 404 "ext/standard/url_scanner_ex.c" +#line 410 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -440,30 +446,32 @@ state_plain: if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; if (yybm[0+yych] & 128) { - goto yy15; + goto yy13; } - ++YYCURSOR; -#line 339 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); STATE = STATE_TAG; goto state_tag; } -#line 449 "ext/standard/url_scanner_ex.c" -yy15: + goto yy16; +yy13: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; if (yybm[0+yych] & 128) { - goto yy15; + goto yy13; } -#line 340 "ext/standard/url_scanner_ex.re" +#line 345 "ext/standard/url_scanner_ex.re" { passthru(STD_ARGS); goto state_plain; } -#line 459 "ext/standard/url_scanner_ex.c" +#line 462 "ext/standard/url_scanner_ex.c" +yy16: + ++YYCURSOR; +#line 344 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); STATE = STATE_TAG; goto state_tag; } +#line 467 "ext/standard/url_scanner_ex.c" } -#line 341 "ext/standard/url_scanner_ex.re" +#line 346 "ext/standard/url_scanner_ex.re" state_tag: start = YYCURSOR; -#line 467 "ext/standard/url_scanner_ex.c" +#line 475 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -500,39 +508,27 @@ state_tag: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; - if (yych <= '@') { - if (yych != ':') goto yy22; - } else { - if (yych <= 'Z') goto yy20; - if (yych <= '`') goto yy22; - if (yych >= '{') goto yy22; + if (yybm[0+yych] & 128) { + goto yy22; } -yy20: ++YYCURSOR; - yych = *YYCURSOR; - goto yy25; -yy21: -#line 346 "ext/standard/url_scanner_ex.re" - { handle_tag(STD_ARGS); /* Sets STATE */; passthru(STD_ARGS); if (STATE == STATE_PLAIN) goto state_plain; else goto state_next_arg; } +#line 352 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); goto state_plain_begin; } #line 520 "ext/standard/url_scanner_ex.c" yy22: ++YYCURSOR; -#line 347 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); goto state_plain_begin; } -#line 525 "ext/standard/url_scanner_ex.c" -yy24: - ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; -yy25: if (yybm[0+yych] & 128) { - goto yy24; + goto yy22; } - goto yy21; +#line 351 "ext/standard/url_scanner_ex.re" + { handle_tag(STD_ARGS); /* Sets STATE */; passthru(STD_ARGS); if (STATE == STATE_PLAIN) goto state_plain; else goto state_next_arg; } +#line 530 "ext/standard/url_scanner_ex.c" } -#line 348 "ext/standard/url_scanner_ex.re" +#line 353 "ext/standard/url_scanner_ex.re" state_next_arg_begin: @@ -541,7 +537,7 @@ state_next_arg_begin: state_next_arg: start = YYCURSOR; -#line 545 "ext/standard/url_scanner_ex.c" +#line 541 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -580,78 +576,57 @@ state_next_arg: }; if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; - if (yych <= '.') { - if (yych <= '\f') { - if (yych <= 0x08) goto yy36; - if (yych <= '\v') goto yy32; - goto yy36; - } else { - if (yych <= '\r') goto yy32; - if (yych == ' ') goto yy32; - goto yy36; - } + if (yybm[0+yych] & 128) { + goto yy29; + } + if (yych <= '>') { + if (yych == '/') goto yy32; + if (yych >= '>') goto yy33; } else { - if (yych <= '@') { - if (yych <= '/') goto yy28; - if (yych == '>') goto yy30; - goto yy36; + if (yych <= 'Z') { + if (yych >= 'A') goto yy35; } else { - if (yych <= 'Z') goto yy34; - if (yych <= '`') goto yy36; - if (yych <= 'z') goto yy34; - goto yy36; + if (yych <= '`') goto yy27; + if (yych <= 'z') goto yy35; } } +yy27: + ++YYCURSOR; yy28: - ++YYCURSOR; - if ((yych = *YYCURSOR) == '>') goto yy39; -yy29: -#line 359 "ext/standard/url_scanner_ex.re" +#line 364 "ext/standard/url_scanner_ex.re" { passthru(STD_ARGS); goto state_plain_begin; } -#line 612 "ext/standard/url_scanner_ex.c" -yy30: - ++YYCURSOR; -yy31: -#line 356 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); handle_form(STD_ARGS); goto state_plain_begin; } -#line 618 "ext/standard/url_scanner_ex.c" -yy32: - ++YYCURSOR; - yych = *YYCURSOR; - goto yy38; -yy33: -#line 357 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); goto state_next_arg; } -#line 626 "ext/standard/url_scanner_ex.c" -yy34: - ++YYCURSOR; -#line 358 "ext/standard/url_scanner_ex.re" - { --YYCURSOR; STATE = STATE_ARG; goto state_arg; } -#line 631 "ext/standard/url_scanner_ex.c" -yy36: - yych = *++YYCURSOR; - goto yy29; -yy37: +#line 599 "ext/standard/url_scanner_ex.c" +yy29: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; -yy38: if (yybm[0+yych] & 128) { - goto yy37; + goto yy29; } - goto yy33; -yy39: +#line 362 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); goto state_next_arg; } +#line 609 "ext/standard/url_scanner_ex.c" +yy32: + yych = *++YYCURSOR; + if (yych != '>') goto yy28; +yy33: ++YYCURSOR; - yych = *YYCURSOR; - goto yy31; +#line 361 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); handle_form(STD_ARGS); goto state_plain_begin; } +#line 617 "ext/standard/url_scanner_ex.c" +yy35: + ++YYCURSOR; +#line 363 "ext/standard/url_scanner_ex.re" + { --YYCURSOR; STATE = STATE_ARG; goto state_arg; } +#line 622 "ext/standard/url_scanner_ex.c" } -#line 360 "ext/standard/url_scanner_ex.re" +#line 365 "ext/standard/url_scanner_ex.re" state_arg: start = YYCURSOR; -#line 655 "ext/standard/url_scanner_ex.c" +#line 630 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -688,42 +663,35 @@ state_arg: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; - if (yych <= '@') goto yy44; - if (yych <= 'Z') goto yy42; - if (yych <= '`') goto yy44; - if (yych >= '{') goto yy44; -yy42: + if (yych <= '@') goto yy39; + if (yych <= 'Z') goto yy41; + if (yych <= '`') goto yy39; + if (yych <= 'z') goto yy41; +yy39: ++YYCURSOR; - yych = *YYCURSOR; - goto yy47; -yy43: -#line 365 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); handle_arg(STD_ARGS); STATE = STATE_BEFORE_VAL; goto state_before_val; } -#line 705 "ext/standard/url_scanner_ex.c" -yy44: - ++YYCURSOR; -#line 366 "ext/standard/url_scanner_ex.re" +#line 371 "ext/standard/url_scanner_ex.re" { passthru(STD_ARGS); STATE = STATE_NEXT_ARG; goto state_next_arg; } -#line 710 "ext/standard/url_scanner_ex.c" -yy46: +#line 677 "ext/standard/url_scanner_ex.c" +yy41: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; -yy47: if (yybm[0+yych] & 128) { - goto yy46; + goto yy41; } - goto yy43; +#line 370 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); handle_arg(STD_ARGS); STATE = STATE_BEFORE_VAL; goto state_before_val; } +#line 687 "ext/standard/url_scanner_ex.c" } -#line 367 "ext/standard/url_scanner_ex.re" +#line 372 "ext/standard/url_scanner_ex.re" state_before_val: start = YYCURSOR; -#line 727 "ext/standard/url_scanner_ex.c" +#line 695 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -762,54 +730,44 @@ state_before_val: }; if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; - if (yych == ' ') goto yy50; - if (yych == '=') goto yy52; - goto yy54; -yy50: - yych = *(YYMARKER = ++YYCURSOR); - if (yych == ' ') goto yy57; - if (yych == '=') goto yy55; -yy51: -#line 373 "ext/standard/url_scanner_ex.re" + if (yych == ' ') goto yy48; + if (yych == '=') goto yy49; + ++YYCURSOR; +yy47: +#line 378 "ext/standard/url_scanner_ex.re" { --YYCURSOR; goto state_next_arg_begin; } -#line 776 "ext/standard/url_scanner_ex.c" +#line 740 "ext/standard/url_scanner_ex.c" +yy48: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == ' ') goto yy52; + if (yych != '=') goto yy47; +yy49: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy49; + } +#line 377 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); STATE = STATE_VAL; goto state_val; } +#line 754 "ext/standard/url_scanner_ex.c" yy52: - ++YYCURSOR; - yych = *YYCURSOR; - goto yy56; -yy53: -#line 372 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); STATE = STATE_VAL; goto state_val; } -#line 784 "ext/standard/url_scanner_ex.c" -yy54: - yych = *++YYCURSOR; - goto yy51; -yy55: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; -yy56: - if (yybm[0+yych] & 128) { - goto yy55; - } - goto yy53; -yy57: - ++YYCURSOR; - if (YYLIMIT <= YYCURSOR) YYFILL(1); - yych = *YYCURSOR; - if (yych == ' ') goto yy57; - if (yych == '=') goto yy55; + if (yych == ' ') goto yy52; + if (yych == '=') goto yy49; YYCURSOR = YYMARKER; - goto yy51; + goto yy47; } -#line 374 "ext/standard/url_scanner_ex.re" +#line 379 "ext/standard/url_scanner_ex.re" state_val: start = YYCURSOR; -#line 813 "ext/standard/url_scanner_ex.c" +#line 771 "ext/standard/url_scanner_ex.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -817,7 +775,7 @@ state_val: 224, 192, 192, 224, 224, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 192, 224, 64, 224, 224, 224, 224, 128, + 192, 224, 128, 224, 224, 224, 224, 64, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 0, 224, @@ -848,87 +806,69 @@ state_val: }; if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; - if (yych <= ' ') { - if (yych <= '\f') { - if (yych <= 0x08) goto yy65; - if (yych <= '\n') goto yy67; - goto yy65; - } else { - if (yych <= '\r') goto yy67; - if (yych <= 0x1F) goto yy65; - goto yy67; - } - } else { - if (yych <= '&') { - if (yych != '"') goto yy65; - } else { - if (yych <= '\'') goto yy64; - if (yych == '>') goto yy67; - goto yy65; - } - } - yych = *(YYMARKER = ++YYCURSOR); - if (yych != '>') goto yy76; -yy63: -#line 383 "ext/standard/url_scanner_ex.re" - { passthru(STD_ARGS); goto state_next_arg_begin; } -#line 876 "ext/standard/url_scanner_ex.c" -yy64: - yych = *(YYMARKER = ++YYCURSOR); - if (yych == '>') goto yy63; - goto yy71; -yy65: - ++YYCURSOR; - yych = *YYCURSOR; - goto yy69; -yy66: -#line 382 "ext/standard/url_scanner_ex.re" - { handle_val(STD_ARGS, 0, ' '); goto state_next_arg_begin; } -#line 888 "ext/standard/url_scanner_ex.c" -yy67: - yych = *++YYCURSOR; - goto yy63; -yy68: - ++YYCURSOR; - if (YYLIMIT <= YYCURSOR) YYFILL(1); - yych = *YYCURSOR; -yy69: if (yybm[0+yych] & 32) { - goto yy68; + goto yy57; } - goto yy66; -yy70: + if (yych <= ' ') goto yy60; + if (yych <= '"') goto yy62; + if (yych <= '\'') goto yy63; + goto yy60; +yy57: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; -yy71: + if (yybm[0+yych] & 32) { + goto yy57; + } +#line 387 "ext/standard/url_scanner_ex.re" + { handle_val(STD_ARGS, 0, ' '); goto state_next_arg_begin; } +#line 826 "ext/standard/url_scanner_ex.c" +yy60: + ++YYCURSOR; +yy61: +#line 388 "ext/standard/url_scanner_ex.re" + { passthru(STD_ARGS); goto state_next_arg_begin; } +#line 832 "ext/standard/url_scanner_ex.c" +yy62: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '>') goto yy61; + goto yy65; +yy63: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '>') goto yy61; + goto yy70; +yy64: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy65: if (yybm[0+yych] & 64) { - goto yy70; + goto yy64; } - if (yych <= '\'') goto yy73; -yy72: + if (yych <= '"') goto yy67; +yy66: YYCURSOR = YYMARKER; - goto yy63; -yy73: + goto yy61; +yy67: ++YYCURSOR; -#line 381 "ext/standard/url_scanner_ex.re" - { handle_val(STD_ARGS, 1, '\''); goto state_next_arg_begin; } -#line 917 "ext/standard/url_scanner_ex.c" -yy75: +#line 385 "ext/standard/url_scanner_ex.re" + { handle_val(STD_ARGS, 1, '"'); goto state_next_arg_begin; } +#line 857 "ext/standard/url_scanner_ex.c" +yy69: ++YYCURSOR; if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; -yy76: +yy70: if (yybm[0+yych] & 128) { - goto yy75; + goto yy69; } - if (yych >= '#') goto yy72; + if (yych >= '(') goto yy66; ++YYCURSOR; -#line 380 "ext/standard/url_scanner_ex.re" - { handle_val(STD_ARGS, 1, '"'); goto state_next_arg_begin; } -#line 930 "ext/standard/url_scanner_ex.c" +#line 386 "ext/standard/url_scanner_ex.re" + { handle_val(STD_ARGS, 1, '\''); goto state_next_arg_begin; } +#line 870 "ext/standard/url_scanner_ex.c" } -#line 384 "ext/standard/url_scanner_ex.re" +#line 389 "ext/standard/url_scanner_ex.re" stop: diff --git a/ext/standard/url_scanner_ex.re b/ext/standard/url_scanner_ex.re index a5cf50eac34..8bc77db4be6 100644 --- a/ext/standard/url_scanner_ex.re +++ b/ext/standard/url_scanner_ex.re @@ -33,6 +33,7 @@ #include "php_ini.h" #include "php_globals.h" +#include "php_string.h" #define STATE_TAG SOME_OTHER_STATE_TAG #include "basic_functions.h" #include "url.h" @@ -122,7 +123,8 @@ static inline void append_modified_url(smart_str *url, smart_str *dest, smart_st * Don't modify "//example.com" full path, unless * HTTP_HOST matches. */ - if (ZSTR_VAL(url->s)[0] == '/' && ZSTR_VAL(url->s)[1] == '/') { + if (ZSTR_LEN(url->s) > 2 && ZSTR_VAL(url->s)[0] == '/' && ZSTR_VAL(url->s)[1] == '/') { + const char *end_chars = "/\"'?>\r\n"; zval *tmp = NULL, *http_host = NULL; size_t target_len, host_len; if ((!(tmp = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_SERVER")))) @@ -132,10 +134,13 @@ static inline void append_modified_url(smart_str *url, smart_str *dest, smart_st smart_str_append_smart_str(dest, url); return; } + /* HTTP_HOST could be "example.com:8888", etc. */ /* Need to find end of URL in buffer */ host_len = strcspn(Z_STRVAL_P(http_host), ":"); - target_len = strcspn(ZSTR_VAL(url->s)+2, "/\"'?>\r\n"); + target_len = php_strcspn( + ZSTR_VAL(url->s) + 2, (char *) end_chars, + ZSTR_VAL(url->s) + ZSTR_LEN(url->s), (char *) end_chars + strlen(end_chars)); if (host_len && host_len == target_len && strncasecmp(Z_STRVAL_P(http_host), ZSTR_VAL(url->s)+2, host_len)) {