9 #include "libsoup/soup-uri.h"
11 #include "test-utils.h"
14 const char *uri_string, *result;
18 { "foo", NULL, NULL, NULL, 0, "", NULL, NULL } },
19 { "file:/dev/null", "file:/dev/null",
20 { "file", NULL, NULL, NULL, 0, "/dev/null", NULL, NULL } },
21 { "file:///dev/null", "file:///dev/null",
22 { "file", NULL, NULL, "", 0, "/dev/null", NULL, NULL } },
23 { "ftp://user@host/path", "ftp://user@host/path",
24 { "ftp", "user", NULL, "host", 21, "/path", NULL, NULL } },
25 { "ftp://user@host:9999/path", "ftp://user@host:9999/path",
26 { "ftp", "user", NULL, "host", 9999, "/path", NULL, NULL } },
27 { "ftp://user:password@host/path", "ftp://user@host/path",
28 { "ftp", "user", "password", "host", 21, "/path", NULL, NULL } },
29 { "ftp://user:password@host:9999/path", "ftp://user@host:9999/path",
30 { "ftp", "user", "password", "host", 9999, "/path", NULL, NULL } },
31 { "ftp://user:password@host", "ftp://user@host",
32 { "ftp", "user", "password", "host", 21, "", NULL, NULL } },
33 { "http://us%65r@host", "http://user@host/",
34 { "http", "user", NULL, "host", 80, "/", NULL, NULL } },
35 { "http://us%40r@host", "http://us%40r@host/",
36 { "http", "us\x40r", NULL, "host", 80, "/", NULL, NULL } },
37 { "http://us%3ar@host", "http://us%3Ar@host/",
38 { "http", "us\x3ar", NULL, "host", 80, "/", NULL, NULL } },
39 { "http://us%2fr@host", "http://us%2Fr@host/",
40 { "http", "us\x2fr", NULL, "host", 80, "/", NULL, NULL } },
41 { "http://us%3fr@host", "http://us%3Fr@host/",
42 { "http", "us\x3fr", NULL, "host", 80, "/", NULL, NULL } },
43 { "http://host?query", "http://host/?query",
44 { "http", NULL, NULL, "host", 80, "/", "query", NULL } },
45 { "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue¶m=value",
46 "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue¶m=value",
47 { "http", NULL, NULL, "host", 80, "/path", "query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue¶m=value", NULL } },
48 { "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F",
49 "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F",
50 { "http", NULL, NULL, "control-chars", 80, "/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F", NULL, NULL } },
53 { "http", NULL, NULL, "space", 80, "/%20", NULL, NULL } },
54 { "http://delims/%3C%3E%23%25%22",
55 "http://delims/%3C%3E%23%25%22",
56 { "http", NULL, NULL, "delims", 80, "/%3C%3E%23%25%22", NULL, NULL } },
57 { "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60",
58 "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60",
59 { "http", NULL, NULL, "unwise-chars", 80, "/%7B%7D%7C%5C%5E%5B%5D%60", NULL, NULL } },
62 { "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html",
63 "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/index.html",
64 { "http", NULL, NULL, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80, "/index.html", NULL, NULL } },
65 { "http://[1080:0:0:0:8:800:200C:417A]/index.html",
66 "http://[1080:0:0:0:8:800:200C:417A]/index.html",
67 { "http", NULL, NULL, "1080:0:0:0:8:800:200C:417A", 80, "/index.html", NULL, NULL } },
68 { "http://[3ffe:2a00:100:7031::1]",
69 "http://[3ffe:2a00:100:7031::1]/",
70 { "http", NULL, NULL, "3ffe:2a00:100:7031::1", 80, "/", NULL, NULL } },
71 { "http://[1080::8:800:200C:417A]/foo",
72 "http://[1080::8:800:200C:417A]/foo",
73 { "http", NULL, NULL, "1080::8:800:200C:417A", 80, "/foo", NULL, NULL } },
74 { "http://[::192.9.5.5]/ipng",
75 "http://[::192.9.5.5]/ipng",
76 { "http", NULL, NULL, "::192.9.5.5", 80, "/ipng", NULL, NULL } },
77 { "http://[::FFFF:129.144.52.38]:80/index.html",
78 "http://[::FFFF:129.144.52.38]/index.html",
79 { "http", NULL, NULL, "::FFFF:129.144.52.38", 80, "/index.html", NULL, NULL } },
80 { "http://[2010:836B:4179::836B:4179]",
81 "http://[2010:836B:4179::836B:4179]/",
82 { "http", NULL, NULL, "2010:836B:4179::836B:4179", 80, "/", NULL, NULL } },
84 /* Try to recover certain kinds of invalid URIs */
85 { "http://host/path with spaces",
86 "http://host/path%20with%20spaces",
87 { "http", NULL, NULL, "host", 80, "/path%20with%20spaces", NULL, NULL } },
88 { " http://host/path", "http://host/path",
89 { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
90 { "http://host/path ", "http://host/path",
91 { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
92 { "http://host ", "http://host/",
93 { "http", NULL, NULL, "host", 80, "/", NULL, NULL } },
94 { "http://host:999 ", "http://host:999/",
95 { "http", NULL, NULL, "host", 999, "/", NULL, NULL } },
96 { "http://host/pa\nth", "http://host/path",
97 { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
98 { "http:\r\n//host/path", "http://host/path",
99 { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
100 { "http://\thost/path", "http://host/path",
101 { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
103 /* Bug 594405; 0-length is different from not-present */
104 { "http://host/path?", "http://host/path?",
105 { "http", NULL, NULL, "host", 80, "/path", "", NULL } },
106 { "http://host/path#", "http://host/path#",
107 { "http", NULL, NULL, "host", 80, "/path", NULL, "" } },
109 /* Bug 590524; ignore badly-%-encoding */
110 { "http://host/path%", "http://host/path%",
111 { "http", NULL, NULL, "host", 80, "/path%", NULL, NULL } },
112 { "http://h%ost/path", "http://h%25ost/path",
113 { "http", NULL, NULL, "h%ost", 80, "/path", NULL, NULL } },
114 { "http://host/path%%", "http://host/path%%",
115 { "http", NULL, NULL, "host", 80, "/path%%", NULL, NULL } },
116 { "http://host/path%%%", "http://host/path%%%",
117 { "http", NULL, NULL, "host", 80, "/path%%%", NULL, NULL } },
118 { "http://host/path%/x/", "http://host/path%/x/",
119 { "http", NULL, NULL, "host", 80, "/path%/x/", NULL, NULL } },
120 { "http://host/path%0x/", "http://host/path%0x/",
121 { "http", NULL, NULL, "host", 80, "/path%0x/", NULL, NULL } },
122 { "http://host/path%ax", "http://host/path%ax",
123 { "http", NULL, NULL, "host", 80, "/path%ax", NULL, NULL } },
125 /* Bug 662806; %-encode non-ASCII characters */
126 { "http://host/p\xc3\xa4th/", "http://host/p%C3%A4th/",
127 { "http", NULL, NULL, "host", 80, "/p%C3%A4th/", NULL, NULL } },
129 { "HTTP:////////////////", "http:////////////////",
130 { "http", NULL, NULL, "", 80, "//////////////", NULL, NULL } },
132 static int num_abs_tests = G_N_ELEMENTS(abs_tests);
135 static const char *base = "http://a/b/c/d;p?q";
137 const char *uri_string, *result;
141 { "g", NULL, NULL, NULL, 0, "h", NULL, NULL } },
142 { "g", "http://a/b/c/g",
143 { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, NULL } },
144 { "./g", "http://a/b/c/g",
145 { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, NULL } },
146 { "g/", "http://a/b/c/g/",
147 { "http", NULL, NULL, "a", 80, "/b/c/g/", NULL, NULL } },
148 { "/g", "http://a/g",
149 { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
150 { "//g", "http://g/",
151 { "http", NULL, NULL, "g", 80, "/", NULL, NULL } },
152 { "?y", "http://a/b/c/d;p?y",
153 { "http", NULL, NULL, "a", 80, "/b/c/d;p", "y", NULL } },
154 { "g?y", "http://a/b/c/g?y",
155 { "http", NULL, NULL, "a", 80, "/b/c/g", "y", NULL } },
156 { "#s", "http://a/b/c/d;p?q#s",
157 { "http", NULL, NULL, "a", 80, "/b/c/d;p", "q", "s" } },
158 { "g#s", "http://a/b/c/g#s",
159 { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, "s" } },
160 { "g?y#s", "http://a/b/c/g?y#s",
161 { "http", NULL, NULL, "a", 80, "/b/c/g", "y", "s" } },
162 { ";x", "http://a/b/c/;x",
163 { "http", NULL, NULL, "a", 80, "/b/c/;x", NULL, NULL } },
164 { "g;x", "http://a/b/c/g;x",
165 { "http", NULL, NULL, "a", 80, "/b/c/g;x", NULL, NULL } },
166 { "g;x?y#s", "http://a/b/c/g;x?y#s",
167 { "http", NULL, NULL, "a", 80, "/b/c/g;x", "y", "s" } },
168 { ".", "http://a/b/c/",
169 { "http", NULL, NULL, "a", 80, "/b/c/", NULL, NULL } },
170 { "./", "http://a/b/c/",
171 { "http", NULL, NULL, "a", 80, "/b/c/", NULL, NULL } },
172 { "..", "http://a/b/",
173 { "http", NULL, NULL, "a", 80, "/b/", NULL, NULL } },
174 { "../", "http://a/b/",
175 { "http", NULL, NULL, "a", 80, "/b/", NULL, NULL } },
176 { "../g", "http://a/b/g",
177 { "http", NULL, NULL, "a", 80, "/b/g", NULL, NULL } },
178 { "../..", "http://a/",
179 { "http", NULL, NULL, "a", 80, "/", NULL, NULL } },
180 { "../../", "http://a/",
181 { "http", NULL, NULL, "a", 80, "/", NULL, NULL } },
182 { "../../g", "http://a/g",
183 { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
184 { "", "http://a/b/c/d;p?q",
185 { "http", NULL, NULL, "a", 80, "/b/c/d;p", "q", NULL } },
186 { "../../../g", "http://a/g",
187 { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
188 { "../../../../g", "http://a/g",
189 { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
190 { "/./g", "http://a/g",
191 { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
192 { "/../g", "http://a/g",
193 { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
194 { "g.", "http://a/b/c/g.",
195 { "http", NULL, NULL, "a", 80, "/b/c/g.", NULL, NULL } },
196 { ".g", "http://a/b/c/.g",
197 { "http", NULL, NULL, "a", 80, "/b/c/.g", NULL, NULL } },
198 { "g..", "http://a/b/c/g..",
199 { "http", NULL, NULL, "a", 80, "/b/c/g..", NULL, NULL } },
200 { "..g", "http://a/b/c/..g",
201 { "http", NULL, NULL, "a", 80, "/b/c/..g", NULL, NULL } },
202 { "./../g", "http://a/b/g",
203 { "http", NULL, NULL, "a", 80, "/b/g", NULL, NULL } },
204 { "./g/.", "http://a/b/c/g/",
205 { "http", NULL, NULL, "a", 80, "/b/c/g/", NULL, NULL } },
206 { "g/./h", "http://a/b/c/g/h",
207 { "http", NULL, NULL, "a", 80, "/b/c/g/h", NULL, NULL } },
208 { "g/../h", "http://a/b/c/h",
209 { "http", NULL, NULL, "a", 80, "/b/c/h", NULL, NULL } },
210 { "g;x=1/./y", "http://a/b/c/g;x=1/y",
211 { "http", NULL, NULL, "a", 80, "/b/c/g;x=1/y", NULL, NULL } },
212 { "g;x=1/../y", "http://a/b/c/y",
213 { "http", NULL, NULL, "a", 80, "/b/c/y", NULL, NULL } },
214 { "g?y/./x", "http://a/b/c/g?y/./x",
215 { "http", NULL, NULL, "a", 80, "/b/c/g", "y/./x", NULL } },
216 { "g?y/../x", "http://a/b/c/g?y/../x",
217 { "http", NULL, NULL, "a", 80, "/b/c/g", "y/../x", NULL } },
218 { "g#s/./x", "http://a/b/c/g#s/./x",
219 { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, "s/./x" } },
220 { "g#s/../x", "http://a/b/c/g#s/../x",
221 { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, "s/../x" } },
223 /* RFC 3986 notes that some old parsers will parse this as
224 * a relative URL ("http://a/b/c/g"), but it should be
225 * interpreted as absolute. libsoup should parse it
226 * correctly as being absolute, but then reject it since it's
227 * an http URL with no host.
229 { "http:g", NULL, { NULL } }
231 static int num_rel_tests = G_N_ELEMENTS(rel_tests);
234 const char *one, *two;
236 { "example://a/b/c/%7Bfoo%7D", "eXAMPLE://a/./b/../b/%63/%7Bfoo%7D" },
237 { "http://example.com", "http://example.com/" },
239 { "http://abc.com:80/~smith/home.html", "http://abc.com:80/~smith/home.html" },
240 { "http://abc.com:80/~smith/home.html", "http://ABC.com/%7Esmith/home.html" },
241 { "http://abc.com:80/~smith/home.html", "http://ABC.com:/%7esmith/home.html" },
243 static int num_eq_tests = G_N_ELEMENTS(eq_tests);
245 #define test_cmpstr(a, b) _test_cmpstr (#a, #b, a, b)
248 _test_cmpstr (const char *got_desc,
249 const char *exp_desc,
251 const char *expected)
257 debug_printf (1, "ERR\n %s = NULL, expected %s = \"%s\"\n",
258 got_desc, exp_desc, expected);
262 if (expected == NULL) {
263 debug_printf (1, "ERR\n %s = \"%s\", expected %s = NULL\n",
264 got_desc, got, exp_desc);
268 if (strcmp (got, expected) != 0) {
269 debug_printf (1, "ERR\n %s = \"%s\", expected %s = \"%s\"\n",
270 got_desc, got, exp_desc, expected);
278 do_uri (SoupURI *base_uri, const char *base_str,
279 const char *in_uri, const char *out_uri,
286 debug_printf (1, "<%s> + <%s> = <%s>? ", base_str, in_uri,
287 out_uri ? out_uri : "ERR");
288 uri = soup_uri_new_with_base (base_uri, in_uri);
290 debug_printf (1, "<%s> => <%s>? ", in_uri,
291 out_uri ? out_uri : "ERR");
292 uri = soup_uri_new (in_uri);
297 debug_printf (1, "ERR\n Could not parse %s\n", in_uri);
300 debug_printf (1, "OK\n");
306 gboolean failed = FALSE;
308 if (!test_cmpstr (uri->scheme, bits->scheme))
311 if (!test_cmpstr (uri->user, bits->user))
314 if (!test_cmpstr (uri->password, bits->password))
317 if (!test_cmpstr (uri->host, bits->host))
320 if (uri->port != bits->port) {
321 debug_printf (1, "ERR\n port was %u, expected %u\n",
322 uri->port, bits->port);
326 if (!test_cmpstr (uri->path, bits->path))
329 if (!test_cmpstr (uri->query, bits->query))
332 if (!test_cmpstr (uri->fragment, bits->fragment))
339 uri_string = soup_uri_to_string (uri, FALSE);
343 debug_printf (1, "ERR\n Got %s\n", uri_string);
347 if (strcmp (uri_string, out_uri) != 0) {
348 debug_printf (1, "NO\n Unparses to <%s>\n", uri_string);
354 debug_printf (1, "OK\n");
359 do_soup_uri_null_tests (void)
364 debug_printf (1, "\nsoup_uri_new (NULL)\n");
365 uri = soup_uri_new (NULL);
366 if (SOUP_URI_IS_VALID (uri) || SOUP_URI_VALID_FOR_HTTP (uri)) {
367 debug_printf (1, " ERROR: soup_uri_new(NULL) returns valid URI?\n");
371 /* This implicitly also verifies that none of these methods g_warn */
372 if (soup_uri_get_scheme (uri) ||
373 soup_uri_get_user (uri) ||
374 soup_uri_get_password (uri) ||
375 soup_uri_get_host (uri) ||
376 soup_uri_get_port (uri) ||
377 soup_uri_get_path (uri) ||
378 soup_uri_get_query (uri) ||
379 soup_uri_get_fragment (uri)) {
380 debug_printf (1, " ERROR: soup_uri_new(NULL) returns non-empty URI?\n");
384 expect_warning = TRUE;
385 uri2 = soup_uri_new_with_base (uri, "/path");
386 if (uri2 || expect_warning) {
387 debug_printf (1, " ERROR: soup_uri_new_with_base didn't fail on NULL URI?\n");
389 expect_warning = FALSE;
392 expect_warning = TRUE;
393 uri_string = soup_uri_to_string (uri, FALSE);
394 if (expect_warning) {
395 debug_printf (1, " ERROR: soup_uri_to_string didn't fail on NULL URI?\n");
397 expect_warning = FALSE;
398 } else if (*uri_string) {
399 debug_printf (1, " ERROR: soup_uri_to_string on NULL URI returned '%s'\n",
405 soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
406 if (SOUP_URI_IS_VALID (uri) || SOUP_URI_VALID_FOR_HTTP (uri)) {
407 debug_printf (1, " ERROR: setting scheme on NULL URI makes it valid?\n");
411 expect_warning = TRUE;
412 uri_string = soup_uri_to_string (uri, FALSE);
413 if (expect_warning) {
414 debug_printf (1, " ERROR: soup_uri_to_string didn't fail on scheme-only URI?\n");
416 expect_warning = FALSE;
417 } else if (strcmp (uri_string, "http:") != 0) {
418 debug_printf (1, " ERROR: soup_uri_to_string returned '%s' instead of 'http:'\n",
424 soup_uri_set_host (uri, "localhost");
425 if (SOUP_URI_IS_VALID (uri)) {
426 debug_printf (1, " ERROR: setting scheme+host on NULL URI makes it valid?\n");
429 if (SOUP_URI_VALID_FOR_HTTP (uri)) {
430 debug_printf (1, " ERROR: setting scheme+host on NULL URI makes it valid for http?\n");
434 expect_warning = TRUE;
435 uri_string = soup_uri_to_string (uri, FALSE);
436 if (expect_warning) {
437 debug_printf (1, " ERROR: soup_uri_to_string didn't fail on scheme+host URI?\n");
439 expect_warning = FALSE;
440 } else if (strcmp (uri_string, "http://localhost/") != 0) {
441 debug_printf (1, " ERROR: soup_uri_to_string with NULL path returned '%s' instead of 'http://localhost/'\n",
447 expect_warning = TRUE;
448 uri2 = soup_uri_new_with_base (uri, "/path");
449 if (expect_warning) {
450 debug_printf (1, " ERROR: soup_uri_new_with_base didn't warn on NULL+scheme URI?\n");
452 expect_warning = FALSE;
454 debug_printf (1, " ERROR: soup_uri_new_with_base didn't fix path on NULL+scheme URI\n");
459 uri_string = soup_uri_to_string (uri2, FALSE);
461 debug_printf (1, " ERROR: soup_uri_to_string failed on uri2?\n");
463 } else if (strcmp (uri_string, "http://localhost/path") != 0) {
464 debug_printf (1, " ERROR: soup_uri_to_string returned '%s' instead of 'http://localhost/path'\n",
469 soup_uri_free (uri2);
472 expect_warning = TRUE;
473 soup_uri_set_path (uri, NULL);
474 if (expect_warning) {
475 debug_printf (1, " ERROR: setting path to NULL doesn't warn\n");
477 expect_warning = FALSE;
479 if (!uri->path || *uri->path) {
480 debug_printf (1, " ERROR: setting path to NULL != \"\"\n");
482 soup_uri_set_path (uri, "");
485 uri_string = soup_uri_to_string (uri, FALSE);
487 debug_printf (1, " ERROR: soup_uri_to_string failed on complete URI?\n");
489 } else if (strcmp (uri_string, "http://localhost/") != 0) {
490 debug_printf (1, " ERROR: soup_uri_to_string with empty path returned '%s' instead of 'http://localhost/'\n",
496 if (!SOUP_URI_IS_VALID (uri)) {
497 debug_printf (1, " ERROR: setting scheme+path on NULL URI doesn't make it valid?\n");
500 if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
501 debug_printf (1, " ERROR: setting scheme+host+path on NULL URI doesn't make it valid for http?\n");
509 main (int argc, char **argv)
511 SoupURI *base_uri, *uri1, *uri2;
515 test_init (argc, argv, NULL);
517 debug_printf (1, "Absolute URI parsing\n");
518 for (i = 0; i < num_abs_tests; i++) {
519 if (!do_uri (NULL, NULL, abs_tests[i].uri_string,
520 abs_tests[i].result, &abs_tests[i].bits))
524 debug_printf (1, "\nRelative URI parsing\n");
525 base_uri = soup_uri_new (base);
527 fprintf (stderr, "Could not parse %s!\n", base);
531 uri_string = soup_uri_to_string (base_uri, FALSE);
532 if (strcmp (uri_string, base) != 0) {
533 fprintf (stderr, "URI <%s> unparses to <%s>\n",
539 for (i = 0; i < num_rel_tests; i++) {
540 if (!do_uri (base_uri, base, rel_tests[i].uri_string,
541 rel_tests[i].result, &rel_tests[i].bits))
544 soup_uri_free (base_uri);
546 debug_printf (1, "\nURI equality testing\n");
547 for (i = 0; i < num_eq_tests; i++) {
548 uri1 = soup_uri_new (eq_tests[i].one);
549 uri2 = soup_uri_new (eq_tests[i].two);
550 debug_printf (1, "<%s> == <%s>? ", eq_tests[i].one, eq_tests[i].two);
551 if (soup_uri_equal (uri1, uri2))
552 debug_printf (1, "OK\n");
554 debug_printf (1, "NO\n");
555 debug_printf (1, "%s : %s : %s\n%s : %s : %s\n",
556 uri1->scheme, uri1->host, uri1->path,
557 uri2->scheme, uri2->host, uri2->path);
560 soup_uri_free (uri1);
561 soup_uri_free (uri2);
564 do_soup_uri_null_tests ();