1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * 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, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * URI self-tests
29  *
30  */
31 
32 /* Forcibly enable assertions */
33 #undef NDEBUG
34 
35 #include <string.h>
36 #include <byteswap.h>
37 #include <ipxe/uri.h>
38 #include <ipxe/tcpip.h>
39 #include <ipxe/params.h>
40 #include <ipxe/test.h>
41 
42 /** A URI parsing/formatting test */
43 struct uri_test {
44 	/** URI string */
45 	const char *string;
46 	/** URI */
47 	struct uri uri;
48 };
49 
50 /** A URI port number test */
51 struct uri_port_test {
52 	/** URI string */
53 	const char *string;
54 	/** Default port number */
55 	unsigned int default_port;
56 	/** Expected port number */
57 	unsigned int port;
58 };
59 
60 /** A URI or path resolution test */
61 struct uri_resolve_test {
62 	/** Base path or URI */
63 	const char *base;
64 	/** Relative path or URI */
65 	const char *relative;
66 	/** Expected resolved path or URI */
67 	const char *resolved;
68 };
69 
70 /** A PXE URI test */
71 struct uri_pxe_test {
72 	/** Server address */
73 	union {
74 		struct sockaddr sa;
75 		struct sockaddr_in sin;
76 		struct sockaddr_in6 sin6;
77 		struct sockaddr_tcpip st;
78 	} server;
79 	/** Filename */
80 	const char *filename;
81 	/** URI */
82 	struct uri uri;
83 	/** URI string (for display only; cannot be reparsed) */
84 	const char *string;
85 };
86 
87 /** A current working URI test */
88 struct uri_churi_test {
89 	/** Relative URI */
90 	const char *relative;
91 	/** Expected new working URI */
92 	const char *expected;
93 };
94 
95 /** A form parameter URI test list */
96 struct uri_params_test_list {
97 	/** Key */
98 	const char *key;
99 	/** Value */
100 	const char *value;
101 };
102 
103 /** A form parameter URI test */
104 struct uri_params_test {
105 	/** URI string */
106 	const char *string;
107 	/** URI */
108 	struct uri uri;
109 	/** Parameter list name */
110 	const char *name;
111 	/** Parameter list */
112 	struct uri_params_test_list *list;
113 };
114 
115 /**
116  * Compare two URI component strings
117  *
118  * @v first		First string, or NULL
119  * @v second		Second string, or NULL
120  * @v difference	Difference
121  */
uristrcmp(const char * first,const char * second)122 static int uristrcmp ( const char *first, const char *second ) {
123 
124 	/* Compare strings, allowing for either to be NULL */
125 	if ( first == second ) {
126 		return 0;
127 	} else if ( ( first == NULL ) || ( second == NULL ) ) {
128 		return -1;
129 	} else {
130 		return strcmp ( first, second );
131 	}
132 }
133 
134 /**
135  * Report URI equality test result
136  *
137  * @v uri		URI
138  * @v expected		Expected URI
139  * @v file		Test code file
140  * @v line		Test code line
141  */
uri_okx(struct uri * uri,struct uri * expected,const char * file,unsigned int line)142 static void uri_okx ( struct uri *uri, struct uri *expected, const char *file,
143 		      unsigned int line ) {
144 
145 	okx ( uristrcmp ( uri->scheme, expected->scheme ) == 0, file, line );
146 	okx ( uristrcmp ( uri->opaque, expected->opaque ) == 0, file, line );
147 	okx ( uristrcmp ( uri->user, expected->user ) == 0, file, line );
148 	okx ( uristrcmp ( uri->password, expected->password ) == 0, file, line);
149 	okx ( uristrcmp ( uri->host, expected->host ) == 0, file, line );
150 	okx ( uristrcmp ( uri->port, expected->port ) == 0, file, line );
151 	okx ( uristrcmp ( uri->path, expected->path ) == 0, file, line );
152 	okx ( uristrcmp ( uri->query, expected->query ) == 0, file, line );
153 	okx ( uristrcmp ( uri->fragment, expected->fragment ) == 0, file, line);
154 	okx ( uri->params == expected->params, file, line );
155 }
156 #define uri_ok( uri, expected ) uri_okx ( uri, expected, __FILE__, __LINE__ )
157 
158 /**
159  * Report URI parsing test result
160  *
161  * @v test		URI test
162  * @v file		Test code file
163  * @v line		Test code line
164  */
uri_parse_okx(struct uri_test * test,const char * file,unsigned int line)165 static void uri_parse_okx ( struct uri_test *test, const char *file,
166 			    unsigned int line ) {
167 	struct uri *uri;
168 
169 	/* Parse URI */
170 	uri = parse_uri ( test->string );
171 	okx ( uri != NULL, file, line );
172 	if ( uri )
173 		uri_okx ( uri, &test->uri, file, line );
174 	uri_put ( uri );
175 }
176 #define uri_parse_ok( test ) uri_parse_okx ( test, __FILE__, __LINE__ )
177 
178 /**
179  * Report URI formatting test result
180  *
181  * @v test		URI test
182  * @v file		Test code file
183  * @v line		Test code line
184  */
uri_format_okx(struct uri_test * test,const char * file,unsigned int line)185 static void uri_format_okx ( struct uri_test *test, const char *file,
186 			     unsigned int line ) {
187 	char buf[ strlen ( test->string ) + 1 /* NUL */ ];
188 	char *tmp;
189 	size_t len;
190 
191 	/* Format into fixed-size buffer */
192 	len = format_uri ( &test->uri, buf, sizeof ( buf ) );
193 	okx ( len == ( sizeof ( buf ) - 1 /* NUL */ ), file, line );
194 	okx ( strcmp ( buf, test->string ) == 0, file, line );
195 
196 	/* Format into temporarily allocated buffer */
197 	tmp = format_uri_alloc ( &test->uri );
198 	okx ( tmp != NULL, file, line );
199 	if ( tmp )
200 		okx ( strcmp ( tmp, test->string ) == 0, file, line );
201 	free ( tmp );
202 }
203 #define uri_format_ok( test ) uri_format_okx ( test, __FILE__, __LINE__ )
204 
205 /**
206  * Report URI duplication test result
207  *
208  * @v test		URI
209  * @v file		Test code file
210  * @v line		Test code line
211  */
uri_dup_okx(struct uri * uri,const char * file,unsigned int line)212 static void uri_dup_okx ( struct uri *uri, const char *file,
213 			  unsigned int line ) {
214 	struct uri *dup;
215 
216 	dup = uri_dup ( uri );
217 	okx ( dup != NULL, file, line );
218 	if ( dup )
219 		uri_okx ( dup, uri, file, line );
220 	uri_put ( dup );
221 }
222 #define uri_dup_ok( test ) uri_dup_okx ( test, __FILE__, __LINE__ )
223 
224 /**
225  * Report URI combined parsing and formatting test result
226  *
227  * @v test		URI test
228  * @v file		Test code file
229  * @v line		Test code line
230  */
uri_parse_format_dup_okx(struct uri_test * test,const char * file,unsigned int line)231 static void uri_parse_format_dup_okx ( struct uri_test *test, const char *file,
232 				       unsigned int line ) {
233 
234 	uri_parse_okx ( test, file, line );
235 	uri_format_okx ( test, file, line );
236 	uri_dup_okx ( &test->uri, file, line );
237 }
238 #define uri_parse_format_dup_ok( test ) \
239 	uri_parse_format_dup_okx ( test, __FILE__, __LINE__ )
240 
241 /**
242  * Report URI port number test result
243  *
244  * @v test		URI port number test
245  * @v file		Test code file
246  * @v line		Test code line
247  */
uri_port_okx(struct uri_port_test * test,const char * file,unsigned int line)248 static void uri_port_okx ( struct uri_port_test *test, const char *file,
249 			   unsigned int line ) {
250 	struct uri *uri;
251 	unsigned int port;
252 
253 	/* Parse URI */
254 	uri = parse_uri ( test->string );
255 	okx ( uri != NULL, file, line );
256 	if ( uri ) {
257 		port = uri_port ( uri, test->default_port );
258 		okx ( port == test->port, file, line );
259 	}
260 	uri_put ( uri );
261 }
262 #define uri_port_ok( test ) uri_port_okx ( test, __FILE__, __LINE__ )
263 
264 /**
265  * Report URI resolution test result
266  *
267  * @v test		Path resolution test
268  * @v file		Test code file
269  * @v line		Test code line
270  */
uri_resolve_okx(struct uri_resolve_test * test,const char * file,unsigned int line)271 static void uri_resolve_okx ( struct uri_resolve_test *test,
272 			      const char *file, unsigned int line ) {
273 	struct uri *base;
274 	struct uri *relative;
275 	struct uri *resolved = NULL;
276 	char *formatted;
277 
278 	/* Parse URIs */
279 	base = parse_uri ( test->base );
280 	okx ( base != NULL, file, line );
281 	relative = parse_uri ( test->relative );
282 	okx ( relative != NULL, file, line );
283 
284 	/* Resolve URI  */
285 	if ( base && relative ) {
286 		resolved = resolve_uri ( base, relative );
287 		okx ( resolved != NULL, file, line );
288 	}
289 
290 	/* Format resolved URI */
291 	formatted = format_uri_alloc ( resolved );
292 	okx ( formatted != NULL, file, line );
293 
294 	/* Check resolved URI */
295 	if ( formatted )
296 		okx ( strcmp ( formatted, test->resolved ) == 0, file, line );
297 
298 	free ( formatted );
299 	uri_put ( resolved );
300 	uri_put ( relative );
301 	uri_put ( base );
302 }
303 #define uri_resolve_ok( test ) uri_resolve_okx ( test, __FILE__, __LINE__ )
304 
305 /**
306  * Report path resolution test result
307  *
308  * @v test		Path resolution test
309  * @v file		Test code file
310  * @v line		Test code line
311  */
uri_resolve_path_okx(struct uri_resolve_test * test,const char * file,unsigned int line)312 static void uri_resolve_path_okx ( struct uri_resolve_test *test,
313 				   const char *file, unsigned int line ) {
314 	char *resolved;
315 
316 	/* Resolve paths using resolve_path() directly */
317 	resolved = resolve_path ( test->base, test->relative );
318 	okx ( resolved != NULL, file, line );
319 	if ( resolved )
320 		okx ( strcmp ( resolved, test->resolved ) == 0, file, line );
321 	free ( resolved );
322 
323 	/* Resolve paths as URIs (since all paths are valid URIs) */
324 	uri_resolve_okx ( test, file, line );
325 }
326 #define uri_resolve_path_ok( test ) \
327 	uri_resolve_path_okx ( test, __FILE__, __LINE__ )
328 
329 /**
330  * Report URI PXE test result
331  *
332  * @v test		URI PXE test
333  * @v file		Test code file
334  * @v line		Test code line
335  */
uri_pxe_okx(struct uri_pxe_test * test,const char * file,unsigned int line)336 static void uri_pxe_okx ( struct uri_pxe_test *test, const char *file,
337 			  unsigned int line ) {
338 	char buf[ strlen ( test->string ) + 1 /* NUL */ ];
339 	struct uri *uri;
340 	size_t len;
341 
342 	/* Construct URI */
343 	uri = pxe_uri ( &test->server.sa, test->filename );
344 	okx ( uri != NULL, file, line );
345 	if ( uri ) {
346 		uri_okx ( uri, &test->uri, file, line );
347 		len = format_uri ( uri, buf, sizeof ( buf ) );
348 		okx ( len == ( sizeof ( buf ) - 1 /* NUL */ ), file, line );
349 		okx ( strcmp ( buf, test->string ) == 0, file, line );
350 	}
351 	uri_put ( uri );
352 }
353 #define uri_pxe_ok( test ) uri_pxe_okx ( test, __FILE__, __LINE__ )
354 
355 /**
356  * Report current working URI test result
357  *
358  * @v tests		List of current working URI tests
359  * @v file		Test code file
360  * @v line		Test code line
361  */
uri_churi_okx(struct uri_churi_test * test,const char * file,unsigned int line)362 static void uri_churi_okx ( struct uri_churi_test *test, const char *file,
363 			    unsigned int line ) {
364 	struct uri *old_cwuri;
365 	struct uri *uri;
366 	char *formatted;
367 
368 	/* Preserve original current working URI */
369 	old_cwuri = uri_get ( cwuri );
370 
371 	/* Perform sequence of current working URI changes */
372 	do {
373 		/* Parse relative URI */
374 		uri = parse_uri ( test->relative );
375 		okx ( uri != NULL, file, line );
376 
377 		/* Move to this URI */
378 		churi ( uri );
379 
380 		/* Format new current working URI */
381 		formatted = format_uri_alloc ( cwuri );
382 		okx ( formatted != NULL, file, line );
383 		if ( formatted ) {
384 			okx ( strcmp ( formatted, test->expected ) == 0,
385 			      file, line );
386 		}
387 
388 		/* Free temporary storage */
389 		free ( formatted );
390 		uri_put ( uri );
391 
392 		/* Move to next current working URI test */
393 		test++;
394 
395 	} while ( test->relative != NULL );
396 
397 	/* Restore original current working URI */
398 	churi ( old_cwuri );
399 	uri_put ( old_cwuri );
400 }
401 #define uri_churi_ok( test ) uri_churi_okx ( test, __FILE__, __LINE__ )
402 
403 /**
404  * Report form parameter URI test list result
405  *
406  * @v test		Form parameter URI test
407  * @v uri		URI
408  * @v file		Test code file
409  * @v line		Test code line
410  */
uri_params_list_okx(struct uri_params_test * test,struct uri * uri,const char * file,unsigned int line)411 static void uri_params_list_okx ( struct uri_params_test *test,
412 				  struct uri *uri, const char *file,
413 				  unsigned int line ) {
414 	struct uri_params_test_list *list;
415 	struct parameter *param;
416 
417 	/* Check URI */
418 	uri_okx ( uri, &test->uri, file, line );
419 
420 	/* Check URI parameters */
421 	okx ( uri->params != NULL, file, line );
422 	if ( uri->params ) {
423 		list = test->list;
424 		for_each_param ( param, uri->params ) {
425 			okx ( strcmp ( param->key, list->key ) == 0,
426 			      file, line );
427 			okx ( strcmp ( param->value, list->value ) == 0,
428 			      file, line );
429 			list++;
430 		}
431 		okx ( list->key == NULL, file, line );
432 	}
433 }
434 #define uri_params_list_ok( test ) \
435 	uri_params_list_okx ( test, __FILE__, __LINE__ )
436 
437 /**
438  * Report form parameter URI test result
439  *
440  * @v test		Form parameter URI test
441  * @v file		Test code file
442  * @v line		Test code line
443  */
uri_params_okx(struct uri_params_test * test,const char * file,unsigned int line)444 static void uri_params_okx ( struct uri_params_test *test, const char *file,
445 			     unsigned int line ) {
446 	struct uri_params_test_list *list;
447 	struct parameters *params;
448 	struct parameter *param;
449 	struct uri *uri;
450 	struct uri *dup;
451 
452 	/* Create parameter list */
453 	params = create_parameters ( test->name );
454 	okx ( params != NULL, file, line );
455 	if ( params ) {
456 		for ( list = test->list ; list->key ; list++ ) {
457 			param = add_parameter ( params, list->key, list->value);
458 			okx ( param != NULL, file, line );
459 		}
460 	}
461 
462 	/* Record parameter list as part of expected URI */
463 	test->uri.params = params;
464 
465 	/* Parse URI */
466 	uri = parse_uri ( test->string );
467 	okx ( uri != NULL, file, line );
468 	if ( uri )
469 		uri_params_list_okx ( test, uri, file, line );
470 
471 	/* Duplicate URI */
472 	dup = uri_dup ( uri );
473 	okx ( dup != NULL, file, line );
474 	if ( dup )
475 		uri_params_list_okx ( test, dup, file, line );
476 
477 	/* Clear parameter list in expected URI */
478 	test->uri.params = NULL;
479 
480 	uri_put ( uri );
481 	uri_put ( dup );
482 }
483 #define uri_params_ok( test ) uri_params_okx ( test, __FILE__, __LINE__ )
484 
485 /** Empty URI */
486 static struct uri_test uri_empty = {
487 	.string = "",
488 };
489 
490 /** Basic HTTP URI */
491 static struct uri_test uri_boot_ipxe_org = {
492 	"http://boot.ipxe.org/demo/boot.php",
493 	{ .scheme = "http", .host = "boot.ipxe.org", .path = "/demo/boot.php" }
494 };
495 
496 /** Basic opaque URI */
497 static struct uri_test uri_mailto = {
498 	"mailto:ipxe-devel@lists.ipxe.org",
499 	{ .scheme = "mailto", .opaque = "ipxe-devel@lists.ipxe.org" }
500 };
501 
502 /** Basic path-only URI */
503 static struct uri_test uri_path = {
504 	"/var/lib/tftpboot/pxelinux.0",
505 	{ .path = "/var/lib/tftpboot/pxelinux.0" },
506 };
507 
508 /** Path-only URI with escaped characters */
509 static struct uri_test uri_path_escaped = {
510 	"/hello%20world%3F",
511 	{ .path = "/hello world?" },
512 };
513 
514 /** HTTP URI with all the trimmings */
515 static struct uri_test uri_http_all = {
516 	"http://anon:password@example.com:3001/~foo/cgi-bin/foo.pl?a=b&c=d#bit",
517 	{
518 		.scheme = "http",
519 		.user = "anon",
520 		.password = "password",
521 		.host = "example.com",
522 		.port = "3001",
523 		.path = "/~foo/cgi-bin/foo.pl",
524 		.query = "a=b&c=d",
525 		.fragment = "bit",
526 	},
527 };
528 
529 /** HTTP URI with escaped characters */
530 static struct uri_test uri_http_escaped = {
531 	"https://test.ipxe.org/wtf%3F%0A?kind%23of/uri%20is#this%3F",
532 	{
533 		.scheme = "https",
534 		.host = "test.ipxe.org",
535 		.path = "/wtf?\n",
536 		.query = "kind#of/uri is",
537 		.fragment = "this?",
538 	},
539 };
540 
541 /** HTTP URI with improperly escaped characters */
542 static struct uri_test uri_http_escaped_improper = {
543 	/* We accept for parsing improperly escaped characters.
544 	 * (Formatting the parsed URI would produce the properly
545 	 * encoded form, and so would not exactly match the original
546 	 * URI string.)
547 	 */
548 	"https://test%2eipxe.org/wt%66%3f\n?kind%23of/uri is#this?",
549 	{
550 		.scheme = "https",
551 		.host = "test.ipxe.org",
552 		.path = "/wtf?\n",
553 		.query = "kind#of/uri is",
554 		.fragment = "this?",
555 	},
556 };
557 
558 /** IPv6 URI */
559 static struct uri_test uri_ipv6 = {
560 	"http://[2001:ba8:0:1d4::6950:5845]/",
561 	{
562 		.scheme = "http",
563 		.host = "[2001:ba8:0:1d4::6950:5845]",
564 		.path = "/",
565 	},
566 };
567 
568 /** IPv6 URI with port */
569 static struct uri_test uri_ipv6_port = {
570 	"http://[2001:ba8:0:1d4::6950:5845]:8001/boot",
571 	{
572 		.scheme = "http",
573 		.host = "[2001:ba8:0:1d4::6950:5845]",
574 		.port = "8001",
575 		.path = "/boot",
576 	},
577 };
578 
579 /** IPv6 URI with link-local address */
580 static struct uri_test uri_ipv6_local = {
581 	"http://[fe80::69ff:fe50:5845%25net0]/ipxe",
582 	{
583 		.scheme = "http",
584 		.host = "[fe80::69ff:fe50:5845%net0]",
585 		.path = "/ipxe",
586 	},
587 };
588 
589 /** IPv6 URI with link-local address not conforming to RFC 6874 */
590 static struct uri_test uri_ipv6_local_non_conforming = {
591 	/* We accept for parsing a single "%" in "%net0" (rather than
592 	 * the properly encoded form "%25net0").  (Formatting the
593 	 * parsed URI would produce the properly encoded form, and so
594 	 * would not exactly match the original URI string.)
595 	 */
596 	"http://[fe80::69ff:fe50:5845%net0]/ipxe",
597 	{
598 		.scheme = "http",
599 		.host = "[fe80::69ff:fe50:5845%net0]",
600 		.path = "/ipxe",
601 	},
602 };
603 
604 /** iSCSI URI */
605 static struct uri_test uri_iscsi = {
606 	"iscsi:10.253.253.1::::iqn.2010-04.org.ipxe:rabbit",
607 	{
608 		.scheme = "iscsi",
609 		.opaque = "10.253.253.1::::iqn.2010-04.org.ipxe:rabbit",
610 	},
611 };
612 
613 /** File URI with relative (opaque) path */
614 static struct uri_test uri_file_relative = {
615 	"file:boot/script.ipxe",
616 	{
617 		.scheme = "file",
618 		.opaque = "boot/script.ipxe",
619 	},
620 };
621 
622 /** File URI with absolute path */
623 static struct uri_test uri_file_absolute = {
624 	"file:/boot/script.ipxe",
625 	{
626 		.scheme = "file",
627 		.path = "/boot/script.ipxe",
628 	},
629 };
630 
631 /** File URI with volume name */
632 static struct uri_test uri_file_volume = {
633 	"file://hpilo/boot/script.ipxe",
634 	{
635 		.scheme = "file",
636 		.host = "hpilo",
637 		.path = "/boot/script.ipxe",
638 	},
639 };
640 
641 /** URI with port number */
642 static struct uri_port_test uri_explicit_port = {
643 	"http://192.168.0.1:8080/boot.php",
644 	80,
645 	8080,
646 };
647 
648 /** URI without port number */
649 static struct uri_port_test uri_default_port = {
650 	"http://192.168.0.1/boot.php",
651 	80,
652 	80,
653 };
654 
655 /** Simple path resolution test */
656 static struct uri_resolve_test uri_simple_path = {
657 	"/etc/passwd",
658 	"group",
659 	"/etc/group",
660 };
661 
662 /** Path resolution test with "." and ".." elements */
663 static struct uri_resolve_test uri_relative_path = {
664 	"/var/lib/tftpboot/pxe/pxelinux.0",
665 	"./../ipxe/undionly.kpxe",
666 	"/var/lib/tftpboot/ipxe/undionly.kpxe",
667 };
668 
669 /** Path resolution test terminating with directory */
670 static struct uri_resolve_test uri_directory_path = {
671 	"/test/cgi-bin.pl/boot.ipxe",
672 	"..",
673 	"/test/",
674 };
675 
676 /** Path resolution test with excessive ".." elements */
677 static struct uri_resolve_test uri_excessive_path = {
678 	"/var/lib/tftpboot/ipxe.pxe",
679 	"../../../../../../../foo",
680 	"/foo",
681 };
682 
683 /** Path resolution test with absolute path */
684 static struct uri_resolve_test uri_absolute_path = {
685 	"/var/lib/tftpboot",
686 	"/etc/hostname",
687 	"/etc/hostname",
688 };
689 
690 /** Relative URI resolution test */
691 static struct uri_resolve_test uri_relative = {
692 	"http://boot.ipxe.org/demo/boot.php?vendor=10ec&device=8139",
693 	"initrd.img",
694 	"http://boot.ipxe.org/demo/initrd.img",
695 };
696 
697 /** Absolute URI resolution test */
698 static struct uri_resolve_test uri_absolute = {
699 	"http://boot.ipxe.org/demo/boot.php",
700 	"ftp://192.168.0.1/boot.ipxe",
701 	"ftp://192.168.0.1/boot.ipxe",
702 };
703 
704 /** Absolute path URI resolution test */
705 static struct uri_resolve_test uri_absolute_uri_path = {
706 	"http://boot.ipxe.org/demo/boot.php#test",
707 	"/demo/vmlinuz",
708 	"http://boot.ipxe.org/demo/vmlinuz",
709 };
710 
711 /** Query URI resolution test */
712 static struct uri_resolve_test uri_query = {
713 	"http://10.253.253.1/test.pl?mac=02-00-69-50-58-45",
714 	"?mac=00-1f-16-bc-fe-2f",
715 	"http://10.253.253.1/test.pl?mac=00-1f-16-bc-fe-2f",
716 };
717 
718 /** Fragment URI resolution test */
719 static struct uri_resolve_test uri_fragment = {
720 	"http://192.168.0.254/test#foo",
721 	"#bar",
722 	"http://192.168.0.254/test#bar",
723 };
724 
725 /** PXE URI with absolute URI */
726 static struct uri_pxe_test uri_pxe_absolute = {
727 	{
728 		/* 192.168.0.3 */
729 		.sin = {
730 			.sin_family = AF_INET,
731 			.sin_addr = { .s_addr = htonl ( 0xc0a80003 ) },
732 		},
733 	},
734 	"http://not.a.tftp/uri",
735 	{
736 		.scheme = "http",
737 		.host = "not.a.tftp",
738 		.path = "/uri",
739 	},
740 	"http://not.a.tftp/uri",
741 };
742 
743 /** PXE URI with absolute path */
744 static struct uri_pxe_test uri_pxe_absolute_path = {
745 	{
746 		/* 192.168.0.2 */
747 		.sin = {
748 			.sin_family = AF_INET,
749 			.sin_addr = { .s_addr = htonl ( 0xc0a80002 ) },
750 		},
751 	},
752 	"/absolute/path",
753 	{
754 		.scheme = "tftp",
755 		.host = "192.168.0.2",
756 		.path = "//absolute/path",
757 	},
758 	"tftp://192.168.0.2//absolute/path",
759 };
760 
761 /** PXE URI with relative path */
762 static struct uri_pxe_test uri_pxe_relative_path = {
763 	{
764 		/* 192.168.0.3 */
765 		.sin = {
766 			.sin_family = AF_INET,
767 			.sin_addr = { .s_addr = htonl ( 0xc0a80003 ) },
768 		},
769 	},
770 	"relative/path",
771 	{
772 		.scheme = "tftp",
773 		.host = "192.168.0.3",
774 		.path = "/relative/path",
775 	},
776 	"tftp://192.168.0.3/relative/path",
777 };
778 
779 /** PXE URI with path containing special characters */
780 static struct uri_pxe_test uri_pxe_icky = {
781 	{
782 		/* 10.0.0.6 */
783 		.sin = {
784 			.sin_family = AF_INET,
785 			.sin_addr = { .s_addr = htonl ( 0x0a000006 ) },
786 		},
787 	},
788 	"C:\\tftpboot\\icky#path",
789 	{
790 		.scheme = "tftp",
791 		.host = "10.0.0.6",
792 		.path = "/C:\\tftpboot\\icky#path",
793 	},
794 	"tftp://10.0.0.6/C%3A\\tftpboot\\icky%23path",
795 };
796 
797 /** PXE URI with custom port */
798 static struct uri_pxe_test uri_pxe_port = {
799 	{
800 		/* 192.168.0.1:4069 */
801 		.sin = {
802 			.sin_family = AF_INET,
803 			.sin_addr = { .s_addr = htonl ( 0xc0a80001 ) },
804 			.sin_port = htons ( 4069 ),
805 		},
806 	},
807 	"/another/path",
808 	{
809 		.scheme = "tftp",
810 		.host = "192.168.0.1",
811 		.port = "4069",
812 		.path = "//another/path",
813 	},
814 	"tftp://192.168.0.1:4069//another/path",
815 };
816 
817 /** Current working URI test */
818 static struct uri_churi_test uri_churi[] = {
819 	{
820 		"http://boot.ipxe.org/demo/boot.php",
821 		"http://boot.ipxe.org/demo/boot.php",
822 	},
823 	{
824 		"?vendor=10ec&device=8139",
825 		"http://boot.ipxe.org/demo/boot.php?vendor=10ec&device=8139",
826 	},
827 	{
828 		"fedora/fedora.ipxe",
829 		"http://boot.ipxe.org/demo/fedora/fedora.ipxe",
830 	},
831 	{
832 		"vmlinuz",
833 		"http://boot.ipxe.org/demo/fedora/vmlinuz",
834 	},
835 	{
836 		"http://local/boot/initrd.img",
837 		"http://local/boot/initrd.img",
838 	},
839 	{
840 		"modules/8139too.ko",
841 		"http://local/boot/modules/8139too.ko",
842 	},
843 	{
844 		NULL,
845 		NULL,
846 	}
847 };
848 
849 /** Form parameter URI test list */
850 static struct uri_params_test_list uri_params_list[] = {
851 	{
852 		"vendor",
853 		"10ec",
854 	},
855 	{
856 		"device",
857 		"8139",
858 	},
859 	{
860 		"uuid",
861 		"f59fac00-758f-498f-9fe5-87d790045d94",
862 	},
863 	{
864 		NULL,
865 		NULL,
866 	}
867 };
868 
869 /** Form parameter URI test */
870 static struct uri_params_test uri_params = {
871 	"http://boot.ipxe.org/demo/boot.php##params",
872 	{
873 		.scheme = "http",
874 		.host = "boot.ipxe.org",
875 		.path = "/demo/boot.php",
876 	},
877 	NULL,
878 	uri_params_list,
879 };
880 
881 /** Named form parameter URI test list */
882 static struct uri_params_test_list uri_named_params_list[] = {
883 	{
884 		"mac",
885 		"00:1e:65:80:d3:b6",
886 	},
887 	{
888 		"serial",
889 		"LXTQ20Z1139322762F2000",
890 	},
891 	{
892 		NULL,
893 		NULL,
894 	}
895 };
896 
897 /** Named form parameter URI test */
898 static struct uri_params_test uri_named_params = {
899 	"http://192.168.100.4:3001/register##params=foo",
900 	{
901 		.scheme = "http",
902 		.host = "192.168.100.4",
903 		.port = "3001",
904 		.path = "/register",
905 	},
906 	"foo",
907 	uri_named_params_list,
908 };
909 
910 /**
911  * Perform URI self-test
912  *
913  */
uri_test_exec(void)914 static void uri_test_exec ( void ) {
915 
916 	/* URI parsing, formatting, and duplication tests */
917 	uri_parse_format_dup_ok ( &uri_empty );
918 	uri_parse_format_dup_ok ( &uri_boot_ipxe_org );
919 	uri_parse_format_dup_ok ( &uri_mailto );
920 	uri_parse_format_dup_ok ( &uri_path );
921 	uri_parse_format_dup_ok ( &uri_path_escaped );
922 	uri_parse_format_dup_ok ( &uri_http_all );
923 	uri_parse_format_dup_ok ( &uri_http_escaped );
924 	uri_parse_ok ( &uri_http_escaped_improper ); /* Parse only */
925 	uri_parse_format_dup_ok ( &uri_ipv6 );
926 	uri_parse_format_dup_ok ( &uri_ipv6_port );
927 	uri_parse_format_dup_ok ( &uri_ipv6_local );
928 	uri_parse_ok ( &uri_ipv6_local_non_conforming ); /* Parse only */
929 	uri_parse_format_dup_ok ( &uri_iscsi );
930 	uri_parse_format_dup_ok ( &uri_file_relative );
931 	uri_parse_format_dup_ok ( &uri_file_absolute );
932 	uri_parse_format_dup_ok ( &uri_file_volume );
933 
934 	/** URI port number tests */
935 	uri_port_ok ( &uri_explicit_port );
936 	uri_port_ok ( &uri_default_port );
937 
938 	/** Path resolution tests */
939 	uri_resolve_path_ok ( &uri_simple_path );
940 	uri_resolve_path_ok ( &uri_relative_path );
941 	uri_resolve_path_ok ( &uri_directory_path );
942 	uri_resolve_path_ok ( &uri_excessive_path );
943 	uri_resolve_path_ok ( &uri_absolute_path );
944 
945 	/** URI resolution tests */
946 	uri_resolve_ok ( &uri_relative );
947 	uri_resolve_ok ( &uri_absolute );
948 	uri_resolve_ok ( &uri_absolute_uri_path );
949 	uri_resolve_ok ( &uri_query );
950 	uri_resolve_ok ( &uri_fragment );
951 
952 	/* PXE URI construction tests */
953 	uri_pxe_ok ( &uri_pxe_absolute );
954 	uri_pxe_ok ( &uri_pxe_absolute_path );
955 	uri_pxe_ok ( &uri_pxe_relative_path );
956 	uri_pxe_ok ( &uri_pxe_icky );
957 	uri_pxe_ok ( &uri_pxe_port );
958 
959 	/* Current working URI tests */
960 	uri_churi_ok ( uri_churi );
961 
962 	/* Form parameter URI tests */
963 	uri_params_ok ( &uri_params );
964 	uri_params_ok ( &uri_named_params );
965 }
966 
967 /** URI self-test */
968 struct self_test uri_test __self_test = {
969 	.name = "uri",
970 	.exec = uri_test_exec,
971 };
972