2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
32 /* Forcibly enable assertions */
38 #include <ipxe/params.h>
39 #include <ipxe/test.h>
41 /** A URI parsing/formatting test */
49 /** A URI port number test */
50 struct uri_port_test {
53 /** Default port number */
54 unsigned int default_port;
55 /** Expected port number */
59 /** A URI or path resolution test */
60 struct uri_resolve_test {
61 /** Base path or URI */
63 /** Relative path or URI */
65 /** Expected resolved path or URI */
69 /** A TFTP URI test */
70 struct uri_tftp_test {
71 /** Next-server address */
72 struct in_addr next_server;
79 /** URI string (for display only; cannot be reparsed) */
83 /** A current working URI test */
84 struct uri_churi_test {
87 /** Expected new working URI */
91 /** A form parameter URI test list */
92 struct uri_params_test_list {
99 /** A form parameter URI test */
100 struct uri_params_test {
105 /** Parameter list name */
107 /** Parameter list */
108 struct uri_params_test_list *list;
112 * Compare two URI component strings
114 * @v first First string, or NULL
115 * @v second Second string, or NULL
116 * @v difference Difference
118 static int uristrcmp ( const char *first, const char *second ) {
120 /* Compare strings, allowing for either to be NULL */
121 if ( first == second ) {
123 } else if ( ( first == NULL ) || ( second == NULL ) ) {
126 return strcmp ( first, second );
131 * Report URI equality test result
134 * @v expected Expected URI
135 * @v file Test code file
136 * @v line Test code line
138 static void uri_okx ( struct uri *uri, struct uri *expected, const char *file,
139 unsigned int line ) {
141 okx ( uristrcmp ( uri->scheme, expected->scheme ) == 0, file, line );
142 okx ( uristrcmp ( uri->opaque, expected->opaque ) == 0, file, line );
143 okx ( uristrcmp ( uri->user, expected->user ) == 0, file, line );
144 okx ( uristrcmp ( uri->password, expected->password ) == 0, file, line);
145 okx ( uristrcmp ( uri->host, expected->host ) == 0, file, line );
146 okx ( uristrcmp ( uri->port, expected->port ) == 0, file, line );
147 okx ( uristrcmp ( uri->path, expected->path ) == 0, file, line );
148 okx ( uristrcmp ( uri->query, expected->query ) == 0, file, line );
149 okx ( uristrcmp ( uri->fragment, expected->fragment ) == 0, file, line);
150 okx ( uri->params == expected->params, file, line );
152 #define uri_ok( uri, expected ) uri_okx ( uri, expected, __FILE__, __LINE__ )
155 * Report URI parsing test result
158 * @v file Test code file
159 * @v line Test code line
161 static void uri_parse_okx ( struct uri_test *test, const char *file,
162 unsigned int line ) {
166 uri = parse_uri ( test->string );
167 okx ( uri != NULL, file, line );
169 uri_okx ( uri, &test->uri, file, line );
172 #define uri_parse_ok( test ) uri_parse_okx ( test, __FILE__, __LINE__ )
175 * Report URI formatting test result
178 * @v file Test code file
179 * @v line Test code line
181 static void uri_format_okx ( struct uri_test *test, const char *file,
182 unsigned int line ) {
183 char buf[ strlen ( test->string ) + 1 /* NUL */ ];
187 /* Format into fixed-size buffer */
188 len = format_uri ( &test->uri, buf, sizeof ( buf ) );
189 okx ( len == ( sizeof ( buf ) - 1 /* NUL */ ), file, line );
190 okx ( strcmp ( buf, test->string ) == 0, file, line );
192 /* Format into temporarily allocated buffer */
193 tmp = format_uri_alloc ( &test->uri );
194 okx ( tmp != NULL, file, line );
196 okx ( strcmp ( tmp, test->string ) == 0, file, line );
199 #define uri_format_ok( test ) uri_format_okx ( test, __FILE__, __LINE__ )
202 * Report URI duplication test result
205 * @v file Test code file
206 * @v line Test code line
208 static void uri_dup_okx ( struct uri *uri, const char *file,
209 unsigned int line ) {
212 dup = uri_dup ( uri );
213 okx ( dup != NULL, file, line );
215 uri_okx ( dup, uri, file, line );
218 #define uri_dup_ok( test ) uri_dup_okx ( test, __FILE__, __LINE__ )
221 * Report URI combined parsing and formatting test result
224 * @v file Test code file
225 * @v line Test code line
227 static void uri_parse_format_dup_okx ( struct uri_test *test, const char *file,
228 unsigned int line ) {
230 uri_parse_okx ( test, file, line );
231 uri_format_okx ( test, file, line );
232 uri_dup_okx ( &test->uri, file, line );
234 #define uri_parse_format_dup_ok( test ) \
235 uri_parse_format_dup_okx ( test, __FILE__, __LINE__ )
238 * Report URI port number test result
240 * @v test URI port number test
241 * @v file Test code file
242 * @v line Test code line
244 static void uri_port_okx ( struct uri_port_test *test, const char *file,
245 unsigned int line ) {
250 uri = parse_uri ( test->string );
251 okx ( uri != NULL, file, line );
253 port = uri_port ( uri, test->default_port );
254 okx ( port == test->port, file, line );
258 #define uri_port_ok( test ) uri_port_okx ( test, __FILE__, __LINE__ )
261 * Report URI resolution test result
263 * @v test Path resolution test
264 * @v file Test code file
265 * @v line Test code line
267 static void uri_resolve_okx ( struct uri_resolve_test *test,
268 const char *file, unsigned int line ) {
270 struct uri *relative;
271 struct uri *resolved = NULL;
275 base = parse_uri ( test->base );
276 okx ( base != NULL, file, line );
277 relative = parse_uri ( test->relative );
278 okx ( relative != NULL, file, line );
281 if ( base && relative ) {
282 resolved = resolve_uri ( base, relative );
283 okx ( resolved != NULL, file, line );
286 /* Format resolved URI */
287 formatted = format_uri_alloc ( resolved );
288 okx ( formatted != NULL, file, line );
290 /* Check resolved URI */
292 okx ( strcmp ( formatted, test->resolved ) == 0, file, line );
295 uri_put ( resolved );
296 uri_put ( relative );
299 #define uri_resolve_ok( test ) uri_resolve_okx ( test, __FILE__, __LINE__ )
302 * Report path resolution test result
304 * @v test Path resolution test
305 * @v file Test code file
306 * @v line Test code line
308 static void uri_resolve_path_okx ( struct uri_resolve_test *test,
309 const char *file, unsigned int line ) {
312 /* Resolve paths using resolve_path() directly */
313 resolved = resolve_path ( test->base, test->relative );
314 okx ( resolved != NULL, file, line );
316 okx ( strcmp ( resolved, test->resolved ) == 0, file, line );
319 /* Resolve paths as URIs (since all paths are valid URIs) */
320 uri_resolve_okx ( test, file, line );
322 #define uri_resolve_path_ok( test ) \
323 uri_resolve_path_okx ( test, __FILE__, __LINE__ )
326 * Report URI TFTP test result
328 * @v test URI TFTP test
329 * @v file Test code file
330 * @v line Test code line
332 static void uri_tftp_okx ( struct uri_tftp_test *test, const char *file,
333 unsigned int line ) {
334 char buf[ strlen ( test->string ) + 1 /* NUL */ ];
339 uri = tftp_uri ( test->next_server, test->port, test->filename );
340 okx ( uri != NULL, file, line );
342 uri_okx ( uri, &test->uri, file, line );
343 len = format_uri ( uri, buf, sizeof ( buf ) );
344 okx ( len == ( sizeof ( buf ) - 1 /* NUL */ ), file, line );
345 okx ( strcmp ( buf, test->string ) == 0, file, line );
349 #define uri_tftp_ok( test ) uri_tftp_okx ( test, __FILE__, __LINE__ )
352 * Report current working URI test result
354 * @v tests List of current working URI tests
355 * @v file Test code file
356 * @v line Test code line
358 static void uri_churi_okx ( struct uri_churi_test *test, const char *file,
359 unsigned int line ) {
360 struct uri *old_cwuri;
364 /* Preserve original current working URI */
365 old_cwuri = uri_get ( cwuri );
367 /* Perform sequence of current working URI changes */
369 /* Parse relative URI */
370 uri = parse_uri ( test->relative );
371 okx ( uri != NULL, file, line );
373 /* Move to this URI */
376 /* Format new current working URI */
377 formatted = format_uri_alloc ( cwuri );
378 okx ( formatted != NULL, file, line );
380 okx ( strcmp ( formatted, test->expected ) == 0,
384 /* Free temporary storage */
388 /* Move to next current working URI test */
391 } while ( test->relative != NULL );
393 /* Restore original current working URI */
395 uri_put ( old_cwuri );
397 #define uri_churi_ok( test ) uri_churi_okx ( test, __FILE__, __LINE__ )
400 * Report form parameter URI test list result
402 * @v test Form parameter URI test
404 * @v file Test code file
405 * @v line Test code line
407 static void uri_params_list_okx ( struct uri_params_test *test,
408 struct uri *uri, const char *file,
409 unsigned int line ) {
410 struct uri_params_test_list *list;
411 struct parameter *param;
414 uri_okx ( uri, &test->uri, file, line );
416 /* Check URI parameters */
417 okx ( uri->params != NULL, file, line );
420 for_each_param ( param, uri->params ) {
421 okx ( strcmp ( param->key, list->key ) == 0,
423 okx ( strcmp ( param->value, list->value ) == 0,
427 okx ( list->key == NULL, file, line );
430 #define uri_params_list_ok( test ) \
431 uri_params_list_okx ( test, __FILE__, __LINE__ )
434 * Report form parameter URI test result
436 * @v test Form parameter URI test
437 * @v file Test code file
438 * @v line Test code line
440 static void uri_params_okx ( struct uri_params_test *test, const char *file,
441 unsigned int line ) {
442 struct uri_params_test_list *list;
443 struct parameters *params;
444 struct parameter *param;
448 /* Create parameter list */
449 params = create_parameters ( test->name );
450 okx ( params != NULL, file, line );
452 for ( list = test->list ; list->key ; list++ ) {
453 param = add_parameter ( params, list->key, list->value);
454 okx ( param != NULL, file, line );
458 /* Record parameter list as part of expected URI */
459 test->uri.params = params;
462 uri = parse_uri ( test->string );
463 okx ( uri != NULL, file, line );
465 uri_params_list_okx ( test, uri, file, line );
468 dup = uri_dup ( uri );
469 okx ( dup != NULL, file, line );
471 uri_params_list_okx ( test, dup, file, line );
473 /* Clear parameter list in expected URI */
474 test->uri.params = NULL;
479 #define uri_params_ok( test ) uri_params_okx ( test, __FILE__, __LINE__ )
482 static struct uri_test uri_empty = {
486 /** Basic HTTP URI */
487 static struct uri_test uri_boot_ipxe_org = {
488 "http://boot.ipxe.org/demo/boot.php",
489 { .scheme = "http", .host = "boot.ipxe.org", .path = "/demo/boot.php" }
492 /** Basic opaque URI */
493 static struct uri_test uri_mailto = {
494 "mailto:ipxe-devel@lists.ipxe.org",
495 { .scheme = "mailto", .opaque = "ipxe-devel@lists.ipxe.org" }
498 /** HTTP URI with all the trimmings */
499 static struct uri_test uri_http_all = {
500 "http://anon:password@example.com:3001/~foo/cgi-bin/foo.pl?a=b&c=d#bit",
504 .password = "password",
505 .host = "example.com",
507 .path = "/~foo/cgi-bin/foo.pl",
513 /** HTTP URI with escaped characters */
514 static struct uri_test uri_http_escaped = {
515 "https://test.ipxe.org/wtf%3F%0A?kind%23of/uri%20is#this%3F",
518 .host = "test.ipxe.org",
520 .query = "kind#of/uri is",
525 /** HTTP URI with improperly escaped characters */
526 static struct uri_test uri_http_escaped_improper = {
527 /* We accept for parsing improperly escaped characters.
528 * (Formatting the parsed URI would produce the properly
529 * encoded form, and so would not exactly match the original
532 "https://test%2eipxe.org/wt%66%3f\n?kind%23of/uri is#this?",
535 .host = "test.ipxe.org",
537 .query = "kind#of/uri is",
543 static struct uri_test uri_ipv6 = {
544 "http://[2001:ba8:0:1d4::6950:5845]/",
547 .host = "[2001:ba8:0:1d4::6950:5845]",
552 /** IPv6 URI with port */
553 static struct uri_test uri_ipv6_port = {
554 "http://[2001:ba8:0:1d4::6950:5845]:8001/boot",
557 .host = "[2001:ba8:0:1d4::6950:5845]",
563 /** IPv6 URI with link-local address */
564 static struct uri_test uri_ipv6_local = {
565 "http://[fe80::69ff:fe50:5845%25net0]/ipxe",
568 .host = "[fe80::69ff:fe50:5845%net0]",
573 /** IPv6 URI with link-local address not conforming to RFC 6874 */
574 static struct uri_test uri_ipv6_local_non_conforming = {
575 /* We accept for parsing a single "%" in "%net0" (rather than
576 * the properly encoded form "%25net0"). (Formatting the
577 * parsed URI would produce the properly encoded form, and so
578 * would not exactly match the original URI string.)
580 "http://[fe80::69ff:fe50:5845%net0]/ipxe",
583 .host = "[fe80::69ff:fe50:5845%net0]",
589 static struct uri_test uri_iscsi = {
590 "iscsi:10.253.253.1::::iqn.2010-04.org.ipxe:rabbit",
593 .opaque = "10.253.253.1::::iqn.2010-04.org.ipxe:rabbit",
597 /** URI with port number */
598 static struct uri_port_test uri_explicit_port = {
599 "http://192.168.0.1:8080/boot.php",
604 /** URI without port number */
605 static struct uri_port_test uri_default_port = {
606 "http://192.168.0.1/boot.php",
611 /** Simple path resolution test */
612 static struct uri_resolve_test uri_simple_path = {
618 /** Path resolution test with "." and ".." elements */
619 static struct uri_resolve_test uri_relative_path = {
620 "/var/lib/tftpboot/pxe/pxelinux.0",
621 "./../ipxe/undionly.kpxe",
622 "/var/lib/tftpboot/ipxe/undionly.kpxe",
625 /** Path resolution test terminating with directory */
626 static struct uri_resolve_test uri_directory_path = {
627 "/test/cgi-bin.pl/boot.ipxe",
632 /** Path resolution test with excessive ".." elements */
633 static struct uri_resolve_test uri_excessive_path = {
634 "/var/lib/tftpboot/ipxe.pxe",
635 "../../../../../../../foo",
639 /** Path resolution test with absolute path */
640 static struct uri_resolve_test uri_absolute_path = {
646 /** Relative URI resolution test */
647 static struct uri_resolve_test uri_relative = {
648 "http://boot.ipxe.org/demo/boot.php?vendor=10ec&device=8139",
650 "http://boot.ipxe.org/demo/initrd.img",
653 /** Absolute URI resolution test */
654 static struct uri_resolve_test uri_absolute = {
655 "http://boot.ipxe.org/demo/boot.php",
656 "ftp://192.168.0.1/boot.ipxe",
657 "ftp://192.168.0.1/boot.ipxe",
660 /** Absolute path URI resolution test */
661 static struct uri_resolve_test uri_absolute_uri_path = {
662 "http://boot.ipxe.org/demo/boot.php#test",
664 "http://boot.ipxe.org/demo/vmlinuz",
667 /** Query URI resolution test */
668 static struct uri_resolve_test uri_query = {
669 "http://10.253.253.1/test.pl?mac=02-00-69-50-58-45",
670 "?mac=00-1f-16-bc-fe-2f",
671 "http://10.253.253.1/test.pl?mac=00-1f-16-bc-fe-2f",
674 /** Fragment URI resolution test */
675 static struct uri_resolve_test uri_fragment = {
676 "http://192.168.0.254/test#foo",
678 "http://192.168.0.254/test#bar",
681 /** TFTP URI with absolute path */
682 static struct uri_tftp_test uri_tftp_absolute = {
683 { .s_addr = htonl ( 0xc0a80002 ) /* 192.168.0.2 */ }, 0,
687 .host = "192.168.0.2",
688 .path = "/absolute/path",
690 "tftp://192.168.0.2/absolute/path",
693 /** TFTP URI with relative path */
694 static struct uri_tftp_test uri_tftp_relative = {
695 { .s_addr = htonl ( 0xc0a80003 ) /* 192.168.0.3 */ }, 0,
699 .host = "192.168.0.3",
700 .path = "relative/path",
702 "tftp://192.168.0.3/relative/path",
705 /** TFTP URI with path containing special characters */
706 static struct uri_tftp_test uri_tftp_icky = {
707 { .s_addr = htonl ( 0x0a000006 ) /* 10.0.0.6 */ }, 0,
708 "C:\\tftpboot\\icky#path",
712 .path = "C:\\tftpboot\\icky#path",
714 "tftp://10.0.0.6/C%3A\\tftpboot\\icky%23path",
717 /** TFTP URI with custom port */
718 static struct uri_tftp_test uri_tftp_port = {
719 { .s_addr = htonl ( 0xc0a80001 ) /* 192.168.0.1 */ }, 4069,
723 .host = "192.168.0.1",
725 .path = "/another/path",
727 "tftp://192.168.0.1:4069/another/path",
730 /** Current working URI test */
731 static struct uri_churi_test uri_churi[] = {
733 "http://boot.ipxe.org/demo/boot.php",
734 "http://boot.ipxe.org/demo/boot.php",
737 "?vendor=10ec&device=8139",
738 "http://boot.ipxe.org/demo/boot.php?vendor=10ec&device=8139",
741 "fedora/fedora.ipxe",
742 "http://boot.ipxe.org/demo/fedora/fedora.ipxe",
746 "http://boot.ipxe.org/demo/fedora/vmlinuz",
749 "http://local/boot/initrd.img",
750 "http://local/boot/initrd.img",
753 "modules/8139too.ko",
754 "http://local/boot/modules/8139too.ko",
762 /** Form parameter URI test list */
763 static struct uri_params_test_list uri_params_list[] = {
774 "f59fac00-758f-498f-9fe5-87d790045d94",
782 /** Form parameter URI test */
783 static struct uri_params_test uri_params = {
784 "http://boot.ipxe.org/demo/boot.php##params",
787 .host = "boot.ipxe.org",
788 .path = "/demo/boot.php",
794 /** Named form parameter URI test list */
795 static struct uri_params_test_list uri_named_params_list[] = {
802 "LXTQ20Z1139322762F2000",
810 /** Named form parameter URI test */
811 static struct uri_params_test uri_named_params = {
812 "http://192.168.100.4:3001/register##params=foo",
815 .host = "192.168.100.4",
820 uri_named_params_list,
824 * Perform URI self-test
827 static void uri_test_exec ( void ) {
829 /* URI parsing, formatting, and duplication tests */
830 uri_parse_format_dup_ok ( &uri_empty );
831 uri_parse_format_dup_ok ( &uri_boot_ipxe_org );
832 uri_parse_format_dup_ok ( &uri_mailto );
833 uri_parse_format_dup_ok ( &uri_http_all );
834 uri_parse_format_dup_ok ( &uri_http_escaped );
835 uri_parse_ok ( &uri_http_escaped_improper ); /* Parse only */
836 uri_parse_format_dup_ok ( &uri_ipv6 );
837 uri_parse_format_dup_ok ( &uri_ipv6_port );
838 uri_parse_format_dup_ok ( &uri_ipv6_local );
839 uri_parse_ok ( &uri_ipv6_local_non_conforming ); /* Parse only */
840 uri_parse_format_dup_ok ( &uri_iscsi );
842 /** URI port number tests */
843 uri_port_ok ( &uri_explicit_port );
844 uri_port_ok ( &uri_default_port );
846 /** Path resolution tests */
847 uri_resolve_path_ok ( &uri_simple_path );
848 uri_resolve_path_ok ( &uri_relative_path );
849 uri_resolve_path_ok ( &uri_directory_path );
850 uri_resolve_path_ok ( &uri_excessive_path );
851 uri_resolve_path_ok ( &uri_absolute_path );
853 /** URI resolution tests */
854 uri_resolve_ok ( &uri_relative );
855 uri_resolve_ok ( &uri_absolute );
856 uri_resolve_ok ( &uri_absolute_uri_path );
857 uri_resolve_ok ( &uri_query );
858 uri_resolve_ok ( &uri_fragment );
860 /* TFTP URI construction tests */
861 uri_tftp_ok ( &uri_tftp_absolute );
862 uri_tftp_ok ( &uri_tftp_relative );
863 uri_tftp_ok ( &uri_tftp_icky );
864 uri_tftp_ok ( &uri_tftp_port );
866 /* Current working URI tests */
867 uri_churi_ok ( uri_churi );
869 /* Form parameter URI tests */
870 uri_params_ok ( &uri_params );
871 uri_params_ok ( &uri_named_params );
875 struct self_test uri_test __self_test = {
877 .exec = uri_test_exec,