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
,