1 /* Generated by re2c 1.2.1 on Wed Apr  1 00:57:32 2020 */
2 #line 1 "src/net/URL.re"
3 /*
4  * Copyright (C) Tildeslash Ltd. All rights reserved.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * In addition, as a special exception, the copyright holders give
18  * permission to link the code of portions of this program with the
19  * OpenSSL library under certain conditions as described in each
20  * individual source file, and distribute linked combinations
21  * including the two.
22  *
23  * You must obey the GNU General Public License in all respects
24  * for all of the code used other than OpenSSL.
25  */
26 
27 
28 #include "Config.h"
29 
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <limits.h>
35 
36 #include "URL.h"
37 
38 
39 /**
40  * Implementation of the URL interface. The scanner handle
41  * ISO Latin 1 or UTF-8 encoded url's transparently.
42  *
43  * @file
44  */
45 
46 
47 /* ----------------------------------------------------------- Definitions */
48 
49 
50 typedef struct param_t {
51         char *name;
52         char *value;
53         struct param_t *next;
54 } *param_t;
55 
56 #define T URL_T
57 struct URL_S {
58         int ip6;
59 	int port;
60        	char *ref;
61 	char *path;
62 	char *host;
63 	char *user;
64         char *qptr;
65 	char *query;
66 	char *portStr;
67 	char *protocol;
68 	char *password;
69 	char *toString;
70         param_t params;
71         char **paramNames;
72 	uchar_t *data;
73 	uchar_t *buffer;
74 	uchar_t *marker, *ctx, *limit, *token;
75         /* Keep the above align with zild URL_T */
76 };
77 
78 /* Unsafe URL characters: [00-1F, 7F-FF] <>\"#%}{|\\^[] ` */
79 static const uchar_t urlunsafe[256] = {
80 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
81 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
82 	1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
84 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
86 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
88 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
89 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
90 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
91 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
92 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
93 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
94 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
95 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
96 };
97 
98 #define UNKNOWN_PORT -1
99 #define YYCURSOR     U->buffer
100 #define YYLIMIT      U->limit
101 #define YYTOKEN      U->token
102 #define SET_PROTOCOL(PORT) *(YYCURSOR-3)=0; U->protocol=U->token; U->port=PORT; goto authority
103 
104 
105 /* ------------------------------------------------------- Private methods */
106 
107 
_parseURL(T U)108 static bool _parseURL(T U) {
109         param_t param = NULL;
110 	#line 127 "src/net/URL.re"
111 
112 proto:
113 	if (YYCURSOR >= YYLIMIT)
114 		return false;
115 	YYTOKEN = YYCURSOR;
116 
117 #line 118 "<stdout>"
118 {
119 	unsigned char yych;
120 	static const unsigned char yybm[] = {
121 		  0,   0,   0,   0,   0,   0,   0,   0,
122 		  0,   0,   0,   0,   0,   0,   0,   0,
123 		  0,   0,   0,   0,   0,   0,   0,   0,
124 		  0,   0,   0,   0,   0,   0,   0,   0,
125 		  0,   0,   0,   0,   0,   0,   0,   0,
126 		  0,   0,   0,   0,   0,   0,   0,   0,
127 		128, 128, 128, 128, 128, 128, 128, 128,
128 		128, 128,   0,   0,   0,   0,   0,   0,
129 		  0, 128, 128, 128, 128, 128, 128, 128,
130 		128, 128, 128, 128, 128, 128, 128, 128,
131 		128, 128, 128, 128, 128, 128, 128, 128,
132 		128, 128, 128,   0,   0,   0,   0,   0,
133 		  0, 128, 128, 128, 128, 128, 128, 128,
134 		128, 128, 128, 128, 128, 128, 128, 128,
135 		128, 128, 128, 128, 128, 128, 128, 128,
136 		128, 128, 128,   0,   0,   0,   0,   0,
137 		  0,   0,   0,   0,   0,   0,   0,   0,
138 		  0,   0,   0,   0,   0,   0,   0,   0,
139 		  0,   0,   0,   0,   0,   0,   0,   0,
140 		  0,   0,   0,   0,   0,   0,   0,   0,
141 		  0,   0,   0,   0,   0,   0,   0,   0,
142 		  0,   0,   0,   0,   0,   0,   0,   0,
143 		  0,   0,   0,   0,   0,   0,   0,   0,
144 		  0,   0,   0,   0,   0,   0,   0,   0,
145 		  0,   0,   0,   0,   0,   0,   0,   0,
146 		  0,   0,   0,   0,   0,   0,   0,   0,
147 		  0,   0,   0,   0,   0,   0,   0,   0,
148 		  0,   0,   0,   0,   0,   0,   0,   0,
149 		  0,   0,   0,   0,   0,   0,   0,   0,
150 		  0,   0,   0,   0,   0,   0,   0,   0,
151 		  0,   0,   0,   0,   0,   0,   0,   0,
152 		  0,   0,   0,   0,   0,   0,   0,   0,
153 	};
154 	yych = *U->buffer;
155 	if (yych <= '@') {
156 		if (yych <= '\r') {
157 			if (yych <= 0x08) goto yy2;
158 			if (yych <= '\n') goto yy4;
159 			if (yych >= '\r') goto yy4;
160 		} else {
161 			if (yych <= ' ') {
162 				if (yych >= ' ') goto yy4;
163 			} else {
164 				if (yych <= '/') goto yy2;
165 				if (yych <= '9') goto yy6;
166 			}
167 		}
168 	} else {
169 		if (yych <= 'm') {
170 			if (yych <= 'Z') goto yy6;
171 			if (yych <= '`') goto yy2;
172 			if (yych <= 'l') goto yy6;
173 			goto yy7;
174 		} else {
175 			if (yych <= 'o') {
176 				if (yych <= 'n') goto yy6;
177 				goto yy8;
178 			} else {
179 				if (yych <= 'p') goto yy9;
180 				if (yych <= 'z') goto yy6;
181 			}
182 		}
183 	}
184 yy2:
185 	++U->buffer;
186 yy3:
187 #line 154 "src/net/URL.re"
188 	{
189                 goto proto;
190          }
191 #line 192 "<stdout>"
192 yy4:
193 	++U->buffer;
194 #line 134 "src/net/URL.re"
195 	{
196                 goto proto;
197          }
198 #line 199 "<stdout>"
199 yy6:
200 	yych = *(U->marker = ++U->buffer);
201 	if (yych <= '@') {
202 		if (yych <= '/') goto yy3;
203 		if (yych <= ':') goto yy11;
204 		goto yy3;
205 	} else {
206 		if (yych <= 'Z') goto yy11;
207 		if (yych <= '`') goto yy3;
208 		if (yych <= 'z') goto yy11;
209 		goto yy3;
210 	}
211 yy7:
212 	yych = *(U->marker = ++U->buffer);
213 	if (yych <= 'Z') {
214 		if (yych <= '/') goto yy3;
215 		if (yych <= ':') goto yy11;
216 		if (yych <= '@') goto yy3;
217 		goto yy11;
218 	} else {
219 		if (yych <= 'x') {
220 			if (yych <= '`') goto yy3;
221 			goto yy11;
222 		} else {
223 			if (yych <= 'y') goto yy14;
224 			if (yych <= 'z') goto yy11;
225 			goto yy3;
226 		}
227 	}
228 yy8:
229 	yych = *(U->marker = ++U->buffer);
230 	if (yych <= 'Z') {
231 		if (yych <= '/') goto yy3;
232 		if (yych <= ':') goto yy11;
233 		if (yych <= '@') goto yy3;
234 		goto yy11;
235 	} else {
236 		if (yych <= 'q') {
237 			if (yych <= '`') goto yy3;
238 			goto yy11;
239 		} else {
240 			if (yych <= 'r') goto yy15;
241 			if (yych <= 'z') goto yy11;
242 			goto yy3;
243 		}
244 	}
245 yy9:
246 	yych = *(U->marker = ++U->buffer);
247 	if (yych <= 'Z') {
248 		if (yych <= '/') goto yy3;
249 		if (yych <= ':') goto yy11;
250 		if (yych <= '@') goto yy3;
251 		goto yy11;
252 	} else {
253 		if (yych <= 'n') {
254 			if (yych <= '`') goto yy3;
255 			goto yy11;
256 		} else {
257 			if (yych <= 'o') goto yy16;
258 			if (yych <= 'z') goto yy11;
259 			goto yy3;
260 		}
261 	}
262 yy10:
263 	yych = *++U->buffer;
264 yy11:
265 	if (yybm[0+yych] & 128) {
266 		goto yy10;
267 	}
268 	if (yych <= '/') goto yy12;
269 	if (yych <= ':') goto yy13;
270 yy12:
271 	U->buffer = U->marker;
272 	goto yy3;
273 yy13:
274 	yych = *++U->buffer;
275 	if (yych == '/') goto yy17;
276 	goto yy12;
277 yy14:
278 	yych = *++U->buffer;
279 	if (yych == 's') goto yy18;
280 	goto yy11;
281 yy15:
282 	yych = *++U->buffer;
283 	if (yych == 'a') goto yy19;
284 	goto yy11;
285 yy16:
286 	yych = *++U->buffer;
287 	if (yych == 's') goto yy20;
288 	goto yy11;
289 yy17:
290 	yych = *++U->buffer;
291 	if (yych == '/') goto yy21;
292 	goto yy12;
293 yy18:
294 	yych = *++U->buffer;
295 	if (yych == 'q') goto yy23;
296 	goto yy11;
297 yy19:
298 	yych = *++U->buffer;
299 	if (yych == 'c') goto yy24;
300 	goto yy11;
301 yy20:
302 	yych = *++U->buffer;
303 	if (yych == 't') goto yy25;
304 	goto yy11;
305 yy21:
306 	++U->buffer;
307 #line 150 "src/net/URL.re"
308 	{
309                 SET_PROTOCOL(UNKNOWN_PORT);
310          }
311 #line 312 "<stdout>"
312 yy23:
313 	yych = *++U->buffer;
314 	if (yych == 'l') goto yy26;
315 	goto yy11;
316 yy24:
317 	yych = *++U->buffer;
318 	if (yych == 'l') goto yy27;
319 	goto yy11;
320 yy25:
321 	yych = *++U->buffer;
322 	if (yych == 'g') goto yy28;
323 	goto yy11;
324 yy26:
325 	yych = *++U->buffer;
326 	if (yych == ':') goto yy29;
327 	goto yy11;
328 yy27:
329 	yych = *++U->buffer;
330 	if (yych == 'e') goto yy30;
331 	goto yy11;
332 yy28:
333 	yych = *++U->buffer;
334 	if (yych == 'r') goto yy31;
335 	goto yy11;
336 yy29:
337 	yych = *++U->buffer;
338 	if (yych == '/') goto yy32;
339 	goto yy12;
340 yy30:
341 	yych = *++U->buffer;
342 	if (yych == ':') goto yy33;
343 	goto yy11;
344 yy31:
345 	yych = *++U->buffer;
346 	if (yych == 'e') goto yy34;
347 	goto yy11;
348 yy32:
349 	yych = *++U->buffer;
350 	if (yych == '/') goto yy35;
351 	goto yy12;
352 yy33:
353 	yych = *++U->buffer;
354 	if (yych == '/') goto yy37;
355 	goto yy12;
356 yy34:
357 	yych = *++U->buffer;
358 	if (yych == 's') goto yy38;
359 	goto yy11;
360 yy35:
361 	++U->buffer;
362 #line 138 "src/net/URL.re"
363 	{
364                 SET_PROTOCOL(MYSQL_DEFAULT_PORT);
365          }
366 #line 367 "<stdout>"
367 yy37:
368 	yych = *++U->buffer;
369 	if (yych == '/') goto yy39;
370 	goto yy12;
371 yy38:
372 	yych = *++U->buffer;
373 	if (yych == 'q') goto yy41;
374 	goto yy11;
375 yy39:
376 	++U->buffer;
377 #line 146 "src/net/URL.re"
378 	{
379                 SET_PROTOCOL(ORACLE_DEFAULT_PORT);
380          }
381 #line 382 "<stdout>"
382 yy41:
383 	yych = *++U->buffer;
384 	if (yych != 'l') goto yy11;
385 	yych = *++U->buffer;
386 	if (yych != ':') goto yy11;
387 	yych = *++U->buffer;
388 	if (yych != '/') goto yy12;
389 	yych = *++U->buffer;
390 	if (yych != '/') goto yy12;
391 	++U->buffer;
392 #line 142 "src/net/URL.re"
393 	{
394                 SET_PROTOCOL(POSTGRESQL_DEFAULT_PORT);
395          }
396 #line 397 "<stdout>"
397 }
398 #line 157 "src/net/URL.re"
399 
400 authority:
401 	if (YYCURSOR >= YYLIMIT)
402 		return true;
403 	YYTOKEN = YYCURSOR;
404 
405 #line 406 "<stdout>"
406 {
407 	unsigned char yych;
408 	unsigned int yyaccept = 0;
409 	static const unsigned char yybm[] = {
410 		  0,   0,   0,   0,   0,   0,   0,   0,
411 		  0,   0,   0,   0,   0,   0,   0,   0,
412 		  0,   0,   0,   0,   0,   0,   0,   0,
413 		  0,   0,   0,   0,   0,   0,   0,   0,
414 		 16,  56,  56,  16,  56, 184,  56,  56,
415 		 56,  56,  56,  56,  56,  60,  56,  56,
416 		252, 252, 252, 252, 252, 252, 252, 252,
417 		252, 252, 184,  16,  56,  56,  56,  16,
418 		 32, 188, 188, 188, 188, 188, 188, 188,
419 		188, 188, 188, 188, 188, 188, 188, 188,
420 		188, 188, 188, 188, 188, 188, 188, 188,
421 		188, 188, 188,  32,  56,  32,  56,  56,
422 		 56, 188, 188, 188, 188, 188, 188, 188,
423 		188, 188, 188, 188, 188, 188, 188, 188,
424 		188, 188, 188, 188, 188, 188, 188, 188,
425 		188, 188, 188,  56,  56,  56,  56,  56,
426 		 56,  56,  56,  56,  56,  56,  56,  56,
427 		 56,  56,  56,  56,  56,  56,  56,  56,
428 		 56,  56,  56,  56,  56,  56,  56,  56,
429 		 56,  56,  56,  56,  56,  56,  56,  56,
430 		 56,  56,  56,  56,  56,  56,  56,  56,
431 		 56,  56,  56,  56,  56,  56,  56,  56,
432 		 56,  56,  56,  56,  56,  56,  56,  56,
433 		 56,  56,  56,  56,  56,  56,  56,  56,
434 		 56,  56,  56,  56,  56,  56,  56,  56,
435 		 56,  56,  56,  56,  56,  56,  56,  56,
436 		 56,  56,  56,  56,  56,  56,  56,  56,
437 		 56,  56,  56,  56,  56,  56,  56,  56,
438 		 56,  56,  56,  56,  56,  56,  56,  56,
439 		 56,  56,  56,  56,  56,  56,  56,  56,
440 		 56,  56,  56,  56,  56,  56,  56,  56,
441 		 56,  56,  56,  56,  56,  56,  56,  56,
442 	};
443 	yych = *U->buffer;
444 	if (yybm[0+yych] & 4) {
445 		goto yy55;
446 	}
447 	if (yych <= '.') {
448 		if (yych <= '\f') {
449 			if (yych <= 0x08) goto yy49;
450 			if (yych <= '\n') goto yy51;
451 		} else {
452 			if (yych <= '\r') goto yy51;
453 			if (yych <= 0x1F) goto yy49;
454 			if (yych <= ' ') goto yy53;
455 			goto yy54;
456 		}
457 	} else {
458 		if (yych <= '@') {
459 			if (yych <= '/') goto yy58;
460 			if (yych <= ':') goto yy61;
461 			if (yych <= '?') goto yy54;
462 		} else {
463 			if (yych <= '[') goto yy62;
464 			if (yych != ']') goto yy54;
465 		}
466 	}
467 yy49:
468 	++U->buffer;
469 yy50:
470 #line 209 "src/net/URL.re"
471 	{
472                 return true;
473          }
474 #line 475 "<stdout>"
475 yy51:
476 	++U->buffer;
477 yy52:
478 #line 164 "src/net/URL.re"
479 	{
480                 goto authority;
481          }
482 #line 483 "<stdout>"
483 yy53:
484 	yyaccept = 0;
485 	yych = *(U->marker = ++U->buffer);
486 	if (yych <= '[') {
487 		if (yych <= 0x1F) goto yy52;
488 		if (yych <= 'Z') goto yy64;
489 		goto yy52;
490 	} else {
491 		if (yych == ']') goto yy52;
492 		goto yy64;
493 	}
494 yy54:
495 	yyaccept = 1;
496 	yych = *(U->marker = ++U->buffer);
497 	if (yych <= '[') {
498 		if (yych <= 0x1F) goto yy50;
499 		if (yych <= 'Z') goto yy64;
500 		goto yy50;
501 	} else {
502 		if (yych == ']') goto yy50;
503 		goto yy64;
504 	}
505 yy55:
506 	yyaccept = 2;
507 	yych = *(U->marker = ++U->buffer);
508 	if (yybm[0+yych] & 4) {
509 		goto yy55;
510 	}
511 	if (yych <= '?') {
512 		if (yych <= 0x1F) goto yy57;
513 		if (yych <= ',') goto yy63;
514 		if (yych <= '.') goto yy68;
515 		goto yy63;
516 	} else {
517 		if (yych <= '[') {
518 			if (yych <= '@') goto yy66;
519 		} else {
520 			if (yych != ']') goto yy63;
521 		}
522 	}
523 yy57:
524 #line 186 "src/net/URL.re"
525 	{
526                 U->host = Str_ndup(YYTOKEN, (int)(YYCURSOR - YYTOKEN));
527                 goto authority;
528          }
529 #line 530 "<stdout>"
530 yy58:
531 	yyaccept = 3;
532 	yych = *(U->marker = ++U->buffer);
533 	if (yybm[0+yych] & 8) {
534 		goto yy58;
535 	}
536 	if (yych <= 0x1F) goto yy60;
537 	if (yych <= ';') goto yy63;
538 	if (yych <= '?') goto yy69;
539 	if (yych <= '@') goto yy71;
540 	goto yy72;
541 yy60:
542 #line 197 "src/net/URL.re"
543 	{
544                 *YYCURSOR = 0;
545                 U->path = URL_unescape(YYTOKEN);
546                 return true;
547          }
548 #line 549 "<stdout>"
549 yy61:
550 	yyaccept = 1;
551 	yych = *(U->marker = ++U->buffer);
552 	if (yybm[0+yych] & 64) {
553 		goto yy74;
554 	}
555 	if (yych <= '[') {
556 		if (yych <= 0x1F) goto yy50;
557 		if (yych <= 'Z') goto yy64;
558 		goto yy50;
559 	} else {
560 		if (yych == ']') goto yy50;
561 		goto yy64;
562 	}
563 yy62:
564 	yyaccept = 1;
565 	yych = *(U->marker = ++U->buffer);
566 	if (yybm[0+yych] & 128) {
567 		goto yy77;
568 	}
569 	goto yy50;
570 yy63:
571 	yych = *++U->buffer;
572 yy64:
573 	if (yybm[0+yych] & 16) {
574 		goto yy63;
575 	}
576 	if (yych <= 0x1F) goto yy65;
577 	if (yych <= '@') goto yy66;
578 yy65:
579 	U->buffer = U->marker;
580 	if (yyaccept <= 2) {
581 		if (yyaccept <= 1) {
582 			if (yyaccept == 0) {
583 				goto yy52;
584 			} else {
585 				goto yy50;
586 			}
587 		} else {
588 			goto yy57;
589 		}
590 	} else {
591 		if (yyaccept <= 4) {
592 			if (yyaccept == 3) {
593 				goto yy60;
594 			} else {
595 				goto yy70;
596 			}
597 		} else {
598 			goto yy76;
599 		}
600 	}
601 yy66:
602 	++U->buffer;
603 yy67:
604 #line 168 "src/net/URL.re"
605 	{
606                 *(YYCURSOR - 1) = 0;
607                 U->user = YYTOKEN;
608                 char *p = strchr(U->user, ':');
609                 if (p) {
610                         *(p++) = 0;
611                         U->password = URL_unescape(p);
612                 }
613                 URL_unescape(U->user);
614                 goto authority;
615          }
616 #line 617 "<stdout>"
617 yy68:
618 	yych = *++U->buffer;
619 	if (yybm[0+yych] & 4) {
620 		goto yy55;
621 	}
622 	if (yych <= '@') {
623 		if (yych <= 0x1F) goto yy65;
624 		if (yych <= '?') goto yy63;
625 		goto yy66;
626 	} else {
627 		if (yych == '\\') goto yy63;
628 		if (yych <= ']') goto yy65;
629 		goto yy63;
630 	}
631 yy69:
632 	yyaccept = 4;
633 	yych = *(U->marker = ++U->buffer);
634 	if (yych <= '[') {
635 		if (yych <= 0x1F) goto yy70;
636 		if (yych <= 'Z') goto yy64;
637 	} else {
638 		if (yych != ']') goto yy64;
639 	}
640 yy70:
641 #line 203 "src/net/URL.re"
642 	{
643                 *(YYCURSOR-1) = 0;
644                 U->path = URL_unescape(YYTOKEN);
645                 goto query;
646          }
647 #line 648 "<stdout>"
648 yy71:
649 	yych = *++U->buffer;
650 	if (yych <= '#') {
651 		if (yych <= ' ') goto yy67;
652 		if (yych <= '"') goto yy73;
653 		goto yy67;
654 	} else {
655 		if (yych == ';') goto yy67;
656 		goto yy73;
657 	}
658 yy72:
659 	yych = *++U->buffer;
660 yy73:
661 	if (yybm[0+yych] & 32) {
662 		goto yy72;
663 	}
664 	if (yych <= ';') goto yy60;
665 	goto yy79;
666 yy74:
667 	yyaccept = 5;
668 	yych = *(U->marker = ++U->buffer);
669 	if (yybm[0+yych] & 64) {
670 		goto yy74;
671 	}
672 	if (yych <= 'Z') {
673 		if (yych <= 0x1F) goto yy76;
674 		if (yych == '@') goto yy66;
675 		goto yy63;
676 	} else {
677 		if (yych == '\\') goto yy63;
678 		if (yych >= '^') goto yy63;
679 	}
680 yy76:
681 #line 191 "src/net/URL.re"
682 	{
683                 U->portStr = YYTOKEN + 1; // read past ':'
684                 U->port = Str_parseInt(U->portStr);
685                 goto authority;
686          }
687 #line 688 "<stdout>"
688 yy77:
689 	yych = *++U->buffer;
690 	if (yybm[0+yych] & 128) {
691 		goto yy77;
692 	}
693 	if (yych == ']') goto yy80;
694 	goto yy65;
695 yy79:
696 	++U->buffer;
697 	goto yy70;
698 yy80:
699 	++U->buffer;
700 #line 180 "src/net/URL.re"
701 	{
702                 U->ip6 = true;
703                 U->host = Str_ndup(YYTOKEN + 1, (int)(YYCURSOR - YYTOKEN - 2));
704                 goto authority;
705          }
706 #line 707 "<stdout>"
707 }
708 #line 212 "src/net/URL.re"
709 
710 query:
711         if (YYCURSOR >= YYLIMIT)
712 		return true;
713 	YYTOKEN =  YYCURSOR;
714 
715 #line 716 "<stdout>"
716 {
717 	unsigned char yych;
718 	static const unsigned char yybm[] = {
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 		128, 128, 128,   0, 128, 128, 128, 128,
724 		128, 128, 128, 128, 128, 128, 128, 128,
725 		128, 128, 128, 128, 128, 128, 128, 128,
726 		128, 128, 128, 128, 128, 128, 128, 128,
727 		128, 128, 128, 128, 128, 128, 128, 128,
728 		128, 128, 128, 128, 128, 128, 128, 128,
729 		128, 128, 128, 128, 128, 128, 128, 128,
730 		128, 128, 128, 128, 128, 128, 128, 128,
731 		128, 128, 128, 128, 128, 128, 128, 128,
732 		128, 128, 128, 128, 128, 128, 128, 128,
733 		128, 128, 128, 128, 128, 128, 128, 128,
734 		128, 128, 128, 128, 128, 128, 128, 128,
735 		128, 128, 128, 128, 128, 128, 128, 128,
736 		128, 128, 128, 128, 128, 128, 128, 128,
737 		128, 128, 128, 128, 128, 128, 128, 128,
738 		128, 128, 128, 128, 128, 128, 128, 128,
739 		128, 128, 128, 128, 128, 128, 128, 128,
740 		128, 128, 128, 128, 128, 128, 128, 128,
741 		128, 128, 128, 128, 128, 128, 128, 128,
742 		128, 128, 128, 128, 128, 128, 128, 128,
743 		128, 128, 128, 128, 128, 128, 128, 128,
744 		128, 128, 128, 128, 128, 128, 128, 128,
745 		128, 128, 128, 128, 128, 128, 128, 128,
746 		128, 128, 128, 128, 128, 128, 128, 128,
747 		128, 128, 128, 128, 128, 128, 128, 128,
748 		128, 128, 128, 128, 128, 128, 128, 128,
749 		128, 128, 128, 128, 128, 128, 128, 128,
750 		128, 128, 128, 128, 128, 128, 128, 128,
751 	};
752 	yych = *U->buffer;
753 	if (yybm[0+yych] & 128) {
754 		goto yy86;
755 	}
756 	++U->buffer;
757 #line 226 "src/net/URL.re"
758 	{
759                 return true;
760          }
761 #line 762 "<stdout>"
762 yy86:
763 	yych = *++U->buffer;
764 	if (yybm[0+yych] & 128) {
765 		goto yy86;
766 	}
767 #line 219 "src/net/URL.re"
768 	{
769                 *YYCURSOR = 0;
770                 U->query = Str_ndup(YYTOKEN, (int)(YYCURSOR - YYTOKEN));
771                 YYCURSOR = YYTOKEN; // backtrack to start of query string after terminating it and
772                 goto params;
773          }
774 #line 775 "<stdout>"
775 }
776 #line 229 "src/net/URL.re"
777 
778 params:
779 	if (YYCURSOR >= YYLIMIT)
780 		return true;
781 	YYTOKEN =  YYCURSOR;
782 
783 #line 784 "<stdout>"
784 {
785 	unsigned char yych;
786 	static const unsigned char yybm[] = {
787 		  0,   0,   0,   0,   0,   0,   0,   0,
788 		  0,   0,   0,   0,   0,   0,   0,   0,
789 		  0,   0,   0,   0,   0,   0,   0,   0,
790 		  0,   0,   0,   0,   0,   0,   0,   0,
791 		 64, 192, 192, 192, 192, 192, 128, 192,
792 		192, 192, 192, 192, 192, 192, 192, 192,
793 		192, 192, 192, 192, 192, 192, 192, 192,
794 		192, 192, 192, 192, 192,  64, 192, 192,
795 		192, 192, 192, 192, 192, 192, 192, 192,
796 		192, 192, 192, 192, 192, 192, 192, 192,
797 		192, 192, 192, 192, 192, 192, 192, 192,
798 		192, 192, 192, 192, 192, 192, 192, 192,
799 		192, 192, 192, 192, 192, 192, 192, 192,
800 		192, 192, 192, 192, 192, 192, 192, 192,
801 		192, 192, 192, 192, 192, 192, 192, 192,
802 		192, 192, 192, 192, 192, 192, 192, 192,
803 		192, 192, 192, 192, 192, 192, 192, 192,
804 		192, 192, 192, 192, 192, 192, 192, 192,
805 		192, 192, 192, 192, 192, 192, 192, 192,
806 		192, 192, 192, 192, 192, 192, 192, 192,
807 		192, 192, 192, 192, 192, 192, 192, 192,
808 		192, 192, 192, 192, 192, 192, 192, 192,
809 		192, 192, 192, 192, 192, 192, 192, 192,
810 		192, 192, 192, 192, 192, 192, 192, 192,
811 		192, 192, 192, 192, 192, 192, 192, 192,
812 		192, 192, 192, 192, 192, 192, 192, 192,
813 		192, 192, 192, 192, 192, 192, 192, 192,
814 		192, 192, 192, 192, 192, 192, 192, 192,
815 		192, 192, 192, 192, 192, 192, 192, 192,
816 		192, 192, 192, 192, 192, 192, 192, 192,
817 		192, 192, 192, 192, 192, 192, 192, 192,
818 		192, 192, 192, 192, 192, 192, 192, 192,
819 	};
820 	yych = *U->buffer;
821 	if (yych <= ' ') goto yy91;
822 	if (yych == '=') goto yy94;
823 	goto yy93;
824 yy91:
825 	++U->buffer;
826 yy92:
827 #line 254 "src/net/URL.re"
828 	{
829                 return true;
830          }
831 #line 832 "<stdout>"
832 yy93:
833 	yych = *(U->marker = ++U->buffer);
834 	if (yych <= ' ') goto yy92;
835 	goto yy98;
836 yy94:
837 	yych = *++U->buffer;
838 	if (yybm[0+yych] & 64) {
839 		goto yy94;
840 	}
841 	if (yych >= ' ') goto yy102;
842 yy96:
843 #line 244 "src/net/URL.re"
844 	{
845                 *YYTOKEN++ = 0;
846                 if (*(YYCURSOR - 1) == '&')
847                         *(YYCURSOR - 1) = 0;
848                 if (! param) // format error
849                         return true;
850                 param->value = URL_unescape(YYTOKEN);
851                 goto params;
852          }
853 #line 854 "<stdout>"
854 yy97:
855 	yych = *++U->buffer;
856 yy98:
857 	if (yybm[0+yych] & 128) {
858 		goto yy97;
859 	}
860 	if (yych >= '!') goto yy100;
861 	U->buffer = U->marker;
862 	goto yy92;
863 yy100:
864 	++U->buffer;
865 	U->buffer -= 1;
866 #line 236 "src/net/URL.re"
867 	{
868                 NEW(param);
869                 param->name = YYTOKEN;
870                 param->next = U->params;
871                 U->params = param;
872                 goto params;
873          }
874 #line 875 "<stdout>"
875 yy102:
876 	++U->buffer;
877 	goto yy96;
878 }
879 #line 257 "src/net/URL.re"
880 
881         return false;
882 }
883 
884 
_x2b(uchar_t * x)885 static inline int _x2b(uchar_t *x) {
886 	register int b;
887 	b = ((x[0] >= 'A') ? ((x[0] & 0xdf) - 'A')+10 : (x[0] - '0'));
888 	b *= 16;
889 	b += (x[1] >= 'A' ? ((x[1] & 0xdf) - 'A')+10 : (x[1] - '0'));
890 	return b;
891 }
892 
893 
_b2x(uchar_t b,uchar_t * x)894 static inline uchar_t *_b2x(uchar_t b, uchar_t *x) {
895         static const char _b2x_table[] = "0123456789ABCDEF";
896         *x++ = '%';
897         *x++ = _b2x_table[b >> 4];
898         *x = _b2x_table[b & 0xf];
899         return x;
900 }
901 
902 
_freeParams(param_t p)903 static void _freeParams(param_t p) {
904         for (param_t q = NULL; p; p = q) {
905                 q = p->next;
906                 FREE(p);
907         }
908 }
909 
910 
_ctor(uchar_t * data)911 static T _ctor(uchar_t *data) {
912         T U;
913 	NEW(U);
914 	U->data = data;
915 	YYCURSOR = U->data;
916 	U->port = UNKNOWN_PORT;
917 	YYLIMIT = U->data + strlen(U->data);
918 	if (! _parseURL(U))
919                 URL_free(&U);
920 	return U;
921 }
922 
923 
924 /* -------------------------------------------------------- Public methods */
925 
926 
URL_new(const char * url)927 T URL_new(const char *url) {
928         if (STR_UNDEF(url))
929                 return NULL;
930         Exception_init();
931         return _ctor((uchar_t*)Str_dup(url));
932 }
933 
934 
URL_create(const char * url,...)935 T URL_create(const char *url, ...) {
936         if (STR_UNDEF(url))
937                 return NULL;
938         Exception_init();
939 	va_list ap;
940         va_start(ap, url);
941 	T U = _ctor((uchar_t*)Str_vcat(url, ap));
942   	va_end(ap);
943         return U;
944 }
945 
URL_free(T * U)946 void URL_free(T *U) {
947 	assert(U && *U);
948         _freeParams((*U)->params);
949         FREE((*U)->paramNames);
950 	FREE((*U)->toString);
951 	FREE((*U)->query);
952 	FREE((*U)->data);
953 	FREE((*U)->host);
954 	FREE(*U);
955 }
956 
957 
958 /* ------------------------------------------------------------ Properties */
959 
960 
URL_getProtocol(T U)961 const char *URL_getProtocol(T U) {
962 	assert(U);
963 	return U->protocol;
964 }
965 
966 
URL_getUser(T U)967 const char *URL_getUser(T U) {
968 	assert(U);
969 	return U->user;
970 }
971 
972 
URL_getPassword(T U)973 const char *URL_getPassword(T U) {
974 	assert(U);
975 	return U->password;
976 }
977 
978 
URL_getHost(T U)979 const char *URL_getHost(T U) {
980 	assert(U);
981 	return U->host;
982 }
983 
984 
URL_getPort(T U)985 int URL_getPort(T U) {
986 	assert(U);
987 	return U->port;
988 }
989 
990 
URL_getPath(T U)991 const char *URL_getPath(T U) {
992 	assert(U);
993 	return U->path;
994 }
995 
996 
URL_getQueryString(T U)997 const char *URL_getQueryString(T U) {
998 	assert(U);
999 	return U->query;
1000 }
1001 
1002 
URL_getParameterNames(T U)1003 const char **URL_getParameterNames(T U) {
1004         assert(U);
1005         if (U->params && (U->paramNames == NULL)) {
1006                 param_t p;
1007                 int i = 0, len = 0;
1008                 for (p = U->params; p; p = p->next) len++;
1009                 U->paramNames = ALLOC((len + 1) * sizeof *(U->paramNames));
1010                 for (p = U->params; p; p = p->next)
1011                         U->paramNames[i++] = p->name;
1012                 U->paramNames[i] = NULL;
1013         }
1014 	return (const char **)U->paramNames;
1015 }
1016 
1017 
URL_getParameter(T U,const char * name)1018 const char *URL_getParameter(T U, const char *name) {
1019 	assert(U);
1020         assert(name);
1021         for (param_t p = U->params; p; p = p->next) {
1022                 if (Str_isByteEqual(p->name, name))
1023                         return p->value;
1024         }
1025         return NULL;
1026 }
1027 
1028 
1029 /* ---------------------------------------------------------------- Public */
1030 
1031 
URL_toString(T U)1032 const char *URL_toString(T U) {
1033 	assert(U);
1034 	if (! U->toString) {
1035                 uchar_t port[11] = {};
1036                 if (U->portStr) // port seen in URL
1037                         snprintf(port, 10, ":%d", U->port);
1038 		U->toString = Str_cat("%s://%s%s%s%s%s%s%s%s%s%s%s",
1039                                       U->protocol,
1040                                       U->user ? U->user : "",
1041                                       U->password ? ":" : "",
1042                                       U->password ? U->password : "",
1043                                       U->user ? "@" : "",
1044                                       U->ip6 ? "[" : "",
1045                                       U->host ? U->host : "",
1046                                       U->ip6 ? "]" : "",
1047                                       port,
1048                                       U->path ? U->path : "",
1049                                       U->query ? "?" : "",
1050                                       U->query ? U->query : "");
1051 	}
1052 	return U->toString;
1053 }
1054 
1055 
1056 /* --------------------------------------------------------- Class methods */
1057 
1058 
URL_unescape(char * url)1059 char *URL_unescape(char *url) {
1060 	if (STR_DEF(url)) {
1061                 register int x, y;
1062                 for (x = 0, y = 0; url[y]; x++, y++) {
1063                         if ((url[x] = url[y]) == '+')
1064                                 url[x] = ' ';
1065                         else if (url[x] == '%') {
1066                                 if (! (url[y + 1] && url[y + 2]))
1067                                         break;
1068                                 url[x] = _x2b(url + y + 1);
1069                                 y += 2;
1070                         }
1071                 }
1072                 url[x] = 0;
1073         }
1074 	return url;
1075 }
1076 
1077 
URL_escape(const char * url)1078 char *URL_escape(const char *url) {
1079         char *escaped = 0;
1080         if (url) {
1081                 char *p;
1082                 int i, n;
1083                 for (n = i = 0; url[i]; i++)
1084                         if (urlunsafe[(unsigned char)(url[i])])
1085                                 n += 2;
1086                 p = escaped = ALLOC(i + n + 1);
1087                 for (; *url; url++, p++) {
1088                         if (urlunsafe[(unsigned char)(*p = *url)])
1089                                 p = _b2x(*url, p);
1090                 }
1091                 *p = 0;
1092         }
1093         return escaped;
1094 }
1095 
1096