url_scanner_ex.c 38 KB

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