1/* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GLib Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GLib at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include <glib.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29
30typedef struct
31{
32 char *filename;
33 char *hostname;
34 char *expected_result;
35 gint expected_error; /* If failed */
36} FileToUriTest;
37
38FileToUriTest
39file_to_uri_tests[] = {
40 { "/etc", NULL, "file:///etc", 0 },
41 { "/etc", "", "file:///etc", 0 },
42 { "/etc", "otherhost", "file://otherhost/etc", 0 },
43#ifdef G_OS_WIN32
44 { "/etc", "localhost", "file:///etc", 0 },
45 { "c:\\windows", NULL, "file:///c:/windows", 0 },
46 { "c:\\windows", "localhost", "file:///c:/windows", 0 },
47 { "c:\\windows", "otherhost", "file://otherhost/c:/windows", 0 },
48 { "\\\\server\\share\\dir", NULL, "file:////server/share/dir", 0 },
49 { "\\\\server\\share\\dir", "localhost", "file:////server/share/dir", 0 },
50#else
51 { "/etc", "localhost", "file://localhost/etc", 0 },
52 { "c:\\windows", NULL, NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH}, /* it's important to get this error on Unix */
53 { "c:\\windows", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
54 { "c:\\windows", "otherhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
55#endif
56 { "etc", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
57#ifndef G_PLATFORM_WIN32
58 { "/etc/\xE5\xE4\xF6", NULL, "file:///etc/%E5%E4%F6", 0 },
59 { "/etc/\xC3\xB6\xC3\xA4\xC3\xA5", NULL, "file:///etc/%C3%B6%C3%A4%C3%A5", 0 },
60#endif
61 { "/etc", "\xC3\xB6\xC3\xA4\xC3\xA5", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
62 { "/etc", "\xE5\xE4\xF6", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
63 { "/etc/file with #%", NULL, "file:///etc/file%20with%20%23%25", 0 },
64 { "", NULL, NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
65 { "", "", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
66 { "", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
67 { "", "otherhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
68 { "/0123456789", NULL, "file:///0123456789", 0 },
69 { "/ABCDEFGHIJKLMNOPQRSTUVWXYZ", NULL, "file:///ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0 },
70 { "/abcdefghijklmnopqrstuvwxyz", NULL, "file:///abcdefghijklmnopqrstuvwxyz", 0 },
71 { "/-_.!~*'()", NULL, "file:///-_.!~*'()", 0 },
72#ifdef G_OS_WIN32
73 /* As '\\' is a path separator on Win32, it gets turned into '/' in the URI */
74 { "/\"#%<>[\\]^`{|}\x7F", NULL, "file:///%22%23%25%3C%3E%5B/%5D%5E%60%7B%7C%7D%7F", 0 },
75#else
76 /* On Unix, '\\' is a normal character in the file name */
77 { "/\"#%<>[\\]^`{|}\x7F", NULL, "file:///%22%23%25%3C%3E%5B%5C%5D%5E%60%7B%7C%7D%7F", 0 },
78#endif
79 { "/;@+$,", NULL, "file:///%3B@+$,", 0 },
80 /* This and some of the following are of course as such illegal file names on Windows,
81 * and would not occur in real life.
82 */
83 { "/:", NULL, "file:///:", 0 },
84 { "/?&=", NULL, "file:///%3F&=", 0 },
85 { "/", "0123456789-", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
86 { "/", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "file://ABCDEFGHIJKLMNOPQRSTUVWXYZ/", 0 },
87 { "/", "abcdefghijklmnopqrstuvwxyz", "file://abcdefghijklmnopqrstuvwxyz/", 0 },
88 { "/", "_.!~*'()", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
89 { "/", "\"#%<>[\\]^`{|}\x7F", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
90 { "/", ";?&=+$,", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
91 { "/", "/", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
92 { "/", "@:", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
93 { "/", "\x80\xFF", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
94 { "/", "\xC3\x80\xC3\xBF", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
95};
96
97
98typedef struct
99{
100 char *uri;
101 char *expected_filename;
102 char *expected_hostname;
103 gint expected_error; /* If failed */
104} FileFromUriTest;
105
106FileFromUriTest
107file_from_uri_tests[] = {
108 { "file:///etc", "/etc", NULL, 0 },
109 { "FILE:///etc", "/etc", NULL, 0 },
110 { "file:/etc", "/etc", NULL, 0 },
111#ifdef G_OS_WIN32
112 /* On Win32 we don't return "localhost" hostames, just in case
113 * it isn't recognized anyway.
114 */
115 { "file://localhost/etc", "/etc", NULL, 0 },
116 { "file://localhost/etc/%23%25%20file", "/etc/#% file", NULL, 0 },
117 { "file://localhost/\xE5\xE4\xF6", "/\xe5\xe4\xf6", NULL, 0 },
118 { "file://localhost/%E5%E4%F6", "/\xe5\xe4\xf6", NULL, 0 },
119#else
120 { "file://localhost/etc", "/etc", "localhost", 0 },
121 { "file://localhost/etc/%23%25%20file", "/etc/#% file", "localhost", 0 },
122 { "file://localhost/\xE5\xE4\xF6", "/\xe5\xe4\xf6", "localhost", 0 },
123 { "file://localhost/%E5%E4%F6", "/\xe5\xe4\xf6", "localhost", 0 },
124#endif
125 { "file://otherhost/etc", "/etc", "otherhost", 0 },
126 { "file://otherhost/etc/%23%25%20file", "/etc/#% file", "otherhost", 0 },
127 { "file://%C3%B6%C3%A4%C3%A5/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
128 { "file:////etc/%C3%B6%C3%C3%C3%A5", "//etc/\xc3\xb6\xc3\xc3\xc3\xa5", NULL, 0 },
129 { "file://\xE5\xE4\xF6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
130 { "file://%E5%E4%F6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
131 { "file:///some/file#bad", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
132 { "file://some", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
133 { "", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
134 { "file:test", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
135 { "http://www.yahoo.com/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
136 { "file:////etc", "//etc", NULL, 0 },
137 { "file://///etc", "///etc", NULL, 0 },
138#ifdef G_OS_WIN32
139 /* URIs with backslashes come from some nonstandard application, but accept them anyhow */
140 { "file:///c:\\foo", "c:\\foo", NULL, 0 },
141 { "file:///c:/foo\\bar", "c:\\foo\\bar", NULL, 0 },
142 /* Accept also the old Netscape drive-letter-and-vertical bar convention */
143 { "file:///c|/foo", "c:\\foo", NULL, 0 },
144 { "file:////server/share/dir", "\\\\server\\share\\dir", NULL, 0 },
145 { "file://localhost//server/share/foo", "\\\\server\\share\\foo", NULL, 0 },
146 { "file://otherhost//server/share/foo", "\\\\server\\share\\foo", "otherhost", 0 },
147#else
148 { "file:///c:\\foo", "/c:\\foo", NULL, 0 },
149 { "file:///c:/foo", "/c:/foo", NULL, 0 },
150 { "file:////c:/foo", "//c:/foo", NULL, 0 },
151#endif
152 { "file://0123456789/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
153 { "file://ABCDEFGHIJKLMNOPQRSTUVWXYZ/", "/", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0 },
154 { "file://abcdefghijklmnopqrstuvwxyz/", "/", "abcdefghijklmnopqrstuvwxyz", 0 },
155 { "file://-_.!~*'()/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
156 { "file://\"<>[\\]^`{|}\x7F/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
157 { "file://;?&=+$,/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
158 { "file://%C3%80%C3%BF/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
159 { "file://@/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
160 { "file://:/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
161 { "file://#/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
162 { "file://%23/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
163 { "file://%2F/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
164};
165
166static void
167run_file_to_uri_tests (void)
168{
169 gsize i;
170 gchar *res;
171 GError *error;
172
173 for (i = 0; i < G_N_ELEMENTS (file_to_uri_tests); i++)
174 {
175 error = NULL;
176 res = g_filename_to_uri (filename: file_to_uri_tests[i].filename,
177 hostname: file_to_uri_tests[i].hostname,
178 error: &error);
179
180 if (res)
181 g_assert_cmpstr (res, ==, file_to_uri_tests[i].expected_result);
182 else
183 g_assert_error (error, G_CONVERT_ERROR, file_to_uri_tests[i].expected_error);
184
185 g_free (mem: res);
186 g_clear_error (err: &error);
187 }
188}
189
190static void
191run_file_from_uri_tests (void)
192{
193 gsize i;
194 gchar *res;
195 gchar *hostname;
196 GError *error;
197
198 for (i = 0; i < G_N_ELEMENTS (file_from_uri_tests); i++)
199 {
200 error = NULL;
201 res = g_filename_from_uri (uri: file_from_uri_tests[i].uri,
202 hostname: &hostname,
203 error: &error);
204
205#ifdef G_OS_WIN32
206 if (file_from_uri_tests[i].expected_filename)
207 {
208 gchar *p, *slash;
209 p = file_from_uri_tests[i].expected_filename =
210 g_strdup (file_from_uri_tests[i].expected_filename);
211 while ((slash = strchr (p, '/')) != NULL)
212 {
213 *slash = '\\';
214 p = slash + 1;
215 }
216 }
217#endif
218 if (res)
219 g_assert_cmpstr (res, ==, file_from_uri_tests[i].expected_filename);
220 else
221 g_assert_error (error, G_CONVERT_ERROR, file_from_uri_tests[i].expected_error);
222 g_assert_cmpstr (hostname, ==, file_from_uri_tests[i].expected_hostname);
223
224 g_free (mem: res);
225 g_free (mem: hostname);
226 g_clear_error (err: &error);
227 }
228}
229
230static gint
231safe_strcmp_filename (const gchar *a, const gchar *b)
232{
233#ifndef G_OS_WIN32
234 return g_strcmp0 (str1: a, str2: b);
235#else
236 if (!a || !b)
237 return g_strcmp0 (a, b);
238 else
239 {
240 while (*a && *b)
241 {
242 if ((G_IS_DIR_SEPARATOR (*a) && G_IS_DIR_SEPARATOR (*b)) ||
243 *a == *b)
244 a++, b++;
245 else
246 return (*a - *b);
247 }
248 return (*a - *b);
249 }
250#endif
251}
252
253static gint
254safe_strcmp_hostname (const gchar *a, const gchar *b)
255{
256 if (a == NULL)
257 a = "";
258 if (b == NULL)
259 b = "";
260#ifndef G_OS_WIN32
261 return strcmp (s1: a, s2: b);
262#else
263 if (strcmp (a, "localhost") == 0 && !*b)
264 return 0;
265 else
266 return strcmp (a, b);
267#endif
268}
269
270static void
271run_file_roundtrip_tests (void)
272{
273 gsize i;
274 gchar *uri, *hostname, *res;
275 GError *error;
276
277 for (i = 0; i < G_N_ELEMENTS (file_to_uri_tests); i++)
278 {
279 if (file_to_uri_tests[i].expected_error != 0)
280 continue;
281
282 error = NULL;
283 uri = g_filename_to_uri (filename: file_to_uri_tests[i].filename,
284 hostname: file_to_uri_tests[i].hostname,
285 error: &error);
286 g_assert_no_error (error);
287
288 hostname = NULL;
289 res = g_filename_from_uri (uri, hostname: &hostname, error: &error);
290 g_assert_no_error (error);
291
292 g_assert_cmpint (safe_strcmp_filename (file_to_uri_tests[i].filename, res), ==, 0);
293 g_assert_cmpint (safe_strcmp_hostname (file_to_uri_tests[i].hostname, hostname), ==, 0);
294 g_free (mem: res);
295 g_free (mem: uri);
296 g_free (mem: hostname);
297 }
298}
299
300static void
301run_uri_list_tests (void)
302{
303 /* straight from the RFC */
304 gchar *list =
305 "# urn:isbn:0-201-08372-8\r\n"
306 "http://www.huh.org/books/foo.html\r\n"
307 "http://www.huh.org/books/foo.pdf \r\n"
308 " ftp://ftp.foo.org/books/foo.txt\r\n";
309 gchar *expected_uris[] = {
310 "http://www.huh.org/books/foo.html",
311 "http://www.huh.org/books/foo.pdf",
312 "ftp://ftp.foo.org/books/foo.txt"
313 };
314
315 gchar **uris;
316 gint j;
317
318 uris = g_uri_list_extract_uris (uri_list: list);
319 g_assert_cmpint (g_strv_length (uris), ==, 3);
320
321 for (j = 0; j < 3; j++)
322 g_assert_cmpstr (uris[j], ==, expected_uris[j]);
323
324 g_strfreev (str_array: uris);
325
326 uris = g_uri_list_extract_uris (uri_list: "# just hot air\r\n# more hot air");
327 g_assert_cmpint (g_strv_length (uris), ==, 0);
328 g_strfreev (str_array: uris);
329}
330
331static void
332test_uri_unescape_string (void)
333{
334 const struct
335 {
336 /* Inputs */
337 const gchar *escaped; /* (nullable) */
338 const gchar *illegal_characters; /* (nullable) */
339 /* Outputs */
340 const gchar *expected_unescaped; /* (nullable) */
341 }
342 tests[] =
343 {
344 { "%2Babc %4F", NULL, "+abc O" },
345 { "%2Babc %4F", "+", NULL },
346 { "%00abc %4F", "+/", NULL },
347 { "/cursors/none.png", "/", "/cursors/none.png" },
348 { "/cursors%2fbad-subdir/none.png", "/", NULL },
349 { "%0", NULL, NULL },
350 { "%ra", NULL, NULL },
351 { "%2r", NULL, NULL },
352 { "Timm B\344der", NULL, "Timm B\344der" },
353 { NULL, NULL, NULL }, /* actually a valid test, not a delimiter */
354 };
355 gsize i;
356
357 for (i = 0; i < G_N_ELEMENTS (tests); i++)
358 {
359 gchar *s = NULL;
360
361 g_test_message (format: "Test %" G_GSIZE_FORMAT ": %s", i, tests[i].escaped);
362
363 s = g_uri_unescape_string (escaped_string: tests[i].escaped, illegal_characters: tests[i].illegal_characters);
364 g_assert_cmpstr (s, ==, tests[i].expected_unescaped);
365 g_free (mem: s);
366 }
367}
368
369static void
370test_uri_unescape_bytes (gconstpointer test_data)
371{
372 GError *error = NULL;
373 gboolean use_nul_terminated = GPOINTER_TO_INT (test_data);
374 const struct
375 {
376 /* Inputs */
377 const gchar *escaped; /* (nullable) */
378 const gchar *illegal;
379 /* Outputs */
380 gssize expected_unescaped_len; /* -1 => error expected */
381 const guint8 *expected_unescaped; /* (nullable) */
382 }
383 tests[] =
384 {
385 { "%00%00", NULL, 2, (const guint8 *) "\x00\x00" },
386 { "/cursors/none.png", "/", 17, (const guint8 *) "/cursors/none.png" },
387 { "/cursors%2fbad-subdir/none.png", "/", -1, NULL },
388 { "%%", NULL, -1, NULL },
389 { "%", NULL, -1, NULL },
390 };
391 gsize i;
392
393 for (i = 0; i < G_N_ELEMENTS (tests); i++)
394 {
395 gssize escaped_len = 0;
396 gchar *escaped = NULL;
397 GBytes *bytes = NULL;
398
399 g_test_message (format: "Test %" G_GSIZE_FORMAT ": %s", i, tests[i].escaped);
400
401 /* The tests get run twice: once with the length unspecified, using a
402 * nul-terminated string; and once with the length specified and a copy of
403 * the string with the trailing nul explicitly removed (to help catch
404 * buffer overflows). */
405 if (use_nul_terminated)
406 {
407 escaped_len = -1;
408 escaped = g_strdup (str: tests[i].escaped);
409 }
410 else
411 {
412 escaped_len = strlen (s: tests[i].escaped); /* no trailing nul */
413 escaped = g_memdup2 (mem: tests[i].escaped, byte_size: escaped_len);
414 }
415
416 bytes = g_uri_unescape_bytes (escaped_string: escaped, length: escaped_len, illegal_characters: tests[i].illegal, error: &error);
417
418 if (tests[i].expected_unescaped_len < 0)
419 {
420 g_assert_null (bytes);
421 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED);
422 g_clear_error (err: &error);
423 }
424 else
425 {
426 g_assert_no_error (error);
427 g_assert_cmpmem (g_bytes_get_data (bytes, NULL),
428 g_bytes_get_size (bytes),
429 tests[i].expected_unescaped,
430 tests[i].expected_unescaped_len);
431 }
432
433 g_clear_pointer (&bytes, g_bytes_unref);
434 g_free (mem: escaped);
435 }
436}
437
438static void
439test_uri_unescape_segment (void)
440{
441 const gchar *escaped_segment = "%2Babc %4F---";
442 gchar *s = NULL;
443
444 s = g_uri_unescape_segment (escaped_string: escaped_segment, escaped_string_end: escaped_segment + 10, NULL);
445 g_assert_cmpstr (s, ==, "+abc O");
446 g_free (mem: s);
447
448 s = g_uri_unescape_segment (escaped_string: "%2Babc%00cde", NULL, NULL);
449 g_assert_null (s);
450}
451
452static void
453test_uri_escape_string (void)
454{
455 const struct
456 {
457 /* Inputs */
458 const gchar *unescaped;
459 const gchar *reserved_chars_allowed;
460 gboolean allow_utf8;
461 /* Outputs */
462 const gchar *expected_escaped;
463 }
464 tests[] =
465 {
466 { "abcdefgABCDEFG._~", NULL, FALSE, "abcdefgABCDEFG._~" },
467 { ":+ \\?#", NULL, FALSE, "%3A%2B%20%5C%3F%23" },
468 { "a+b:c", "+", FALSE, "a+b%3Ac" },
469 { "a+b:c\303\234", "+", TRUE, "a+b%3Ac\303\234" },
470 /* Incomplete UTF-8 sequence: */
471 { "\xfc\x3b\xd2", NULL, TRUE, "%FC%3B%D2" },
472 /* Invalid sequence: */
473 { "\xc3\xb1\xc3\x28", NULL, TRUE, "ñ%C3%28" },
474 };
475 gsize i;
476
477 for (i = 0; i < G_N_ELEMENTS (tests); i++)
478 {
479 gchar *s = NULL;
480
481 g_test_message (format: "Test %" G_GSIZE_FORMAT ": %s", i, tests[i].unescaped);
482
483 s = g_uri_escape_string (unescaped: tests[i].unescaped,
484 reserved_chars_allowed: tests[i].reserved_chars_allowed,
485 allow_utf8: tests[i].allow_utf8);
486 g_assert_cmpstr (s, ==, tests[i].expected_escaped);
487 g_free (mem: s);
488 }
489}
490
491static void
492test_uri_escape_bytes (void)
493{
494 gchar *s = NULL;
495
496 s = g_uri_escape_bytes (unescaped: (guchar*)"\0\0", length: 2, NULL);
497 g_assert_cmpstr (s, ==, "%00%00");
498 g_free (mem: s);
499}
500
501static void
502test_uri_scheme (void)
503{
504 const gchar *s1, *s2;
505 gchar *s;
506
507 s = g_uri_parse_scheme (uri: "ftp://ftp.gtk.org");
508 g_assert_cmpstr (s, ==, "ftp");
509 g_free (mem: s);
510
511 s = g_uri_parse_scheme (uri: "good-scheme.but+weird:gtk.org");
512 g_assert_cmpstr (s, ==, "good-scheme.but+weird");
513 g_free (mem: s);
514
515 s = g_uri_parse_scheme (uri: "1bad:");
516 g_assert_null (s);
517 s = g_uri_parse_scheme (uri: "bad");
518 g_assert_null (s);
519 s = g_uri_parse_scheme (uri: "99http://host/path");
520 g_assert_null (s);
521 s = g_uri_parse_scheme (uri: ".http://host/path");
522 g_assert_null (s);
523 s = g_uri_parse_scheme (uri: "+http://host/path");
524 g_assert_null (s);
525
526 s1 = g_uri_peek_scheme (uri: "ftp://ftp.gtk.org");
527 g_assert_cmpstr (s1, ==, "ftp");
528 s2 = g_uri_peek_scheme (uri: "FTP://ftp.gtk.org");
529 g_assert_cmpstr (s2, ==, "ftp");
530 g_assert_true (s1 == s2);
531 s1 = g_uri_peek_scheme (uri: "1bad:");
532 g_assert_null (s1);
533 s1 = g_uri_peek_scheme (uri: "bad");
534 g_assert_null (s1);
535}
536
537typedef struct {
538 const gchar *scheme;
539 const gchar *userinfo;
540 const gchar *host;
541 gint port;
542 const gchar *path;
543 const gchar *query;
544 const gchar *fragment;
545} UriParts;
546
547typedef struct {
548 /* Inputs */
549 const gchar *orig;
550 GUriFlags flags;
551 /* Outputs */
552 gboolean expected_success;
553 gint expected_error_code; /* unused if @expected_success is true */
554 const UriParts expected_parts; /* unused if @expected_success is false */
555} UriAbsoluteTest;
556
557static const UriAbsoluteTest absolute_tests[] = {
558 { "foo:", G_URI_FLAGS_NONE, TRUE, 0,
559 { "foo", NULL, NULL, -1, "", NULL, NULL }
560 },
561 { "file:/dev/null", G_URI_FLAGS_NONE, TRUE, 0,
562 { "file", NULL, NULL, -1, "/dev/null", NULL, NULL }
563 },
564 { "file:///dev/null", G_URI_FLAGS_NONE, TRUE, 0,
565 { "file", NULL, "", -1, "/dev/null", NULL, NULL }
566 },
567 { "ftp://user@host/path", G_URI_FLAGS_NONE, TRUE, 0,
568 { "ftp", "user", "host", -1, "/path", NULL, NULL }
569 },
570 { "ftp://user@host:9999/path", G_URI_FLAGS_NONE, TRUE, 0,
571 { "ftp", "user", "host", 9999, "/path", NULL, NULL }
572 },
573 { "ftp://user:password@host/path", G_URI_FLAGS_NONE, TRUE, 0,
574 { "ftp", "user:password", "host", -1, "/path", NULL, NULL }
575 },
576 { "ftp://user:password@host:9999/path", G_URI_FLAGS_NONE, TRUE, 0,
577 { "ftp", "user:password", "host", 9999, "/path", NULL, NULL }
578 },
579 { "ftp://user:password@host", G_URI_FLAGS_NONE, TRUE, 0,
580 { "ftp", "user:password", "host", -1, "", NULL, NULL }
581 },
582 { "http://us%65r@host", G_URI_FLAGS_NONE, TRUE, 0,
583 { "http", "user", "host", -1, "", NULL, NULL }
584 },
585 { "http://us%40r@host", G_URI_FLAGS_NONE, TRUE, 0,
586 { "http", "us@r", "host", -1, "", NULL, NULL }
587 },
588 { "http://us%3ar@host", G_URI_FLAGS_NONE, TRUE, 0,
589 { "http", "us:r", "host", -1, "", NULL, NULL }
590 },
591 { "http://us%2fr@host", G_URI_FLAGS_NONE, TRUE, 0,
592 { "http", "us/r", "host", -1, "", NULL, NULL }
593 },
594 { "http://us%3fr@host", G_URI_FLAGS_NONE, TRUE, 0,
595 { "http", "us?r", "host", -1, "", NULL, NULL }
596 },
597 { "http://host?query", G_URI_FLAGS_NONE, TRUE, 0,
598 { "http", NULL, "host", -1, "", "query", NULL }
599 },
600 { "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue&param=value", G_URI_FLAGS_NONE, TRUE, 0,
601 { "http", NULL, "host", -1, "/path", "query=http://host/path?childparam=childvalue&param=value", NULL }
602 },
603 { "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", G_URI_FLAGS_NONE, TRUE, 0,
604 { "http", NULL, "control-chars", -1, "/\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F", NULL, NULL }
605 },
606 { "http://space/%20", G_URI_FLAGS_NONE, TRUE, 0,
607 { "http", NULL, "space", -1, "/ ", NULL, NULL }
608 },
609 { "http://delims/%3C%3E%23%25%22", G_URI_FLAGS_NONE, TRUE, 0,
610 { "http", NULL, "delims", -1, "/<>#%\"", NULL, NULL }
611 },
612 { "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60", G_URI_FLAGS_NONE, TRUE, 0,
613 { "http", NULL, "unwise-chars", -1, "/{}|\\^[]`", NULL, NULL }
614 },
615
616 /* From RFC 2732 */
617 { "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html", G_URI_FLAGS_NONE, TRUE, 0,
618 { "http", NULL, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80, "/index.html", NULL, NULL }
619 },
620 { "http://[1080:0:0:0:8:800:200C:417A]/index.html", G_URI_FLAGS_NONE, TRUE, 0,
621 { "http", NULL, "1080:0:0:0:8:800:200C:417A", -1, "/index.html", NULL, NULL }
622 },
623 { "http://[3ffe:2a00:100:7031::1]", G_URI_FLAGS_NONE, TRUE, 0,
624 { "http", NULL, "3ffe:2a00:100:7031::1", -1, "", NULL, NULL }
625 },
626 { "http://[1080::8:800:200C:417A]/foo", G_URI_FLAGS_NONE, TRUE, 0,
627 { "http", NULL, "1080::8:800:200C:417A", -1, "/foo", NULL, NULL }
628 },
629 { "http://[::192.9.5.5]/ipng", G_URI_FLAGS_NONE, TRUE, 0,
630 { "http", NULL, "::192.9.5.5", -1, "/ipng", NULL, NULL }
631 },
632 { "http://[::FFFF:129.144.52.38]:80/index.html", G_URI_FLAGS_NONE, TRUE, 0,
633 { "http", NULL, "::FFFF:129.144.52.38", 80, "/index.html", NULL, NULL }
634 },
635 { "http://[2010:836B:4179::836B:4179]", G_URI_FLAGS_NONE, TRUE, 0,
636 { "http", NULL, "2010:836B:4179::836B:4179", -1, "", NULL, NULL }
637 },
638
639 /* some problematic URIs that are handled differently in libsoup */
640 { "http://host/path with spaces", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
641 { "http", NULL, "host", -1, "/path with spaces", NULL, NULL }
642 },
643 { " http://host/path", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
644 { "http", NULL, "host", -1, "/path", NULL, NULL }
645 },
646 { "http://host/path ", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
647 { "http", NULL, "host", -1, "/path", NULL, NULL }
648 },
649 { "http://host ", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
650 { "http", NULL, "host", -1, "", NULL, NULL }
651 },
652 { "http://host:999 ", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
653 { "http", NULL, "host", 999, "", NULL, NULL }
654 },
655 { "http://host/pa\nth", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
656 { "http", NULL, "host", -1, "/path", NULL, NULL }
657 },
658 { "http:\r\n//host/path", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
659 { "http", NULL, "host", -1, "/path", NULL, NULL }
660 },
661 { "http://\thost/path", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
662 { "http", NULL, "host", -1, "/path", NULL, NULL }
663 },
664
665 /* Bug 594405; 0-length is different from not-present */
666 { "http://host/path?", G_URI_FLAGS_NONE, TRUE, 0,
667 { "http", NULL, "host", -1, "/path", "", NULL }
668 },
669 { "http://host/path#", G_URI_FLAGS_NONE, TRUE, 0,
670 { "http", NULL, "host", -1, "/path", NULL, "" },
671 },
672
673 /* Bug 590524; ignore bad %-encoding */
674 { "http://host/path%", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
675 { "http", NULL, "host", -1, "/path%", NULL, NULL }
676 },
677 { "http://h%ost/path", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
678 { "http", NULL, "h%ost", -1, "/path", NULL, NULL }
679 },
680 { "http://host/path%%", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
681 { "http", NULL, "host", -1, "/path%%", NULL, NULL }
682 },
683 { "http://host/path%%%", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
684 { "http", NULL, "host", -1, "/path%%%", NULL, NULL }
685 },
686 { "http://host/path%/x/", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
687 { "http", NULL, "host", -1, "/path%/x/", NULL, NULL }
688 },
689 { "http://host/path%0x/", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
690 { "http", NULL, "host", -1, "/path%0x/", NULL, NULL }
691 },
692 { "http://host/path%ax", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
693 { "http", NULL, "host", -1, "/path%ax", NULL, NULL }
694 },
695
696 /* GUri doesn't %-encode non-ASCII characters */
697 { "http://host/p\xc3\xa4th/", G_URI_FLAGS_NONE, TRUE, 0,
698 { "http", NULL, "host", -1, "/p\xc3\xa4th/", NULL, NULL }
699 },
700
701 { "HTTP:////////////////", G_URI_FLAGS_NONE, TRUE, 0,
702 { "http", NULL, "", -1, "//////////////", NULL, NULL }
703 },
704
705 { "http://@host", G_URI_FLAGS_NONE, TRUE, 0,
706 { "http", "", "host", -1, "", NULL, NULL }
707 },
708 { "http://:@host", G_URI_FLAGS_NONE, TRUE, 0,
709 { "http", ":", "host", -1, "", NULL, NULL }
710 },
711 { "scheme://foo%3Abar._webdav._tcp.local", G_URI_FLAGS_NONE, TRUE, 0,
712 { "scheme", NULL, "foo:bar._webdav._tcp.local", -1, "", NULL, NULL}
713 },
714
715 /* ".." past top */
716 { "http://example.com/..", G_URI_FLAGS_NONE, TRUE, 0,
717 { "http", NULL, "example.com", -1, "/..", NULL, NULL }
718 },
719
720 /* scheme parsing */
721 { "foo0://host/path", G_URI_FLAGS_NONE, TRUE, 0,
722 { "foo0", NULL, "host", -1, "/path", NULL, NULL } },
723 { "f0.o://host/path", G_URI_FLAGS_NONE, TRUE, 0,
724 { "f0.o", NULL, "host", -1, "/path", NULL, NULL } },
725 { "http++://host/path", G_URI_FLAGS_NONE, TRUE, 0,
726 { "http++", NULL, "host", -1, "/path", NULL, NULL } },
727 { "http-ish://host/path", G_URI_FLAGS_NONE, TRUE, 0,
728 { "http-ish", NULL, "host", -1, "/path", NULL, NULL } },
729
730 /* IPv6 scope ID parsing (both correct and incorrect) */
731 { "http://[fe80::dead:beef%]/", G_URI_FLAGS_PARSE_RELAXED, FALSE, G_URI_ERROR_BAD_HOST,
732 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
733 { "http://[fe80::dead:beef%em1]/", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
734 { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } },
735 { "http://[fe80::dead:beef%em1]/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
736 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
737 { "http://[fe80::dead:beef%25em1]/", G_URI_FLAGS_NONE, TRUE, 0,
738 { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } },
739 { "http://[fe80::dead:beef%25em1%20]/", G_URI_FLAGS_NONE, TRUE, 0,
740 { "http", NULL, "fe80::dead:beef%em1 ", -1, "/", NULL, NULL } },
741 { "http://[fe80::dead:beef%25em%31]/", G_URI_FLAGS_NONE, TRUE, 0,
742 { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } },
743 { "http://[fe80::dead:beef%10]/", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
744 { "http", NULL, "fe80::dead:beef%10", -1, "/", NULL, NULL } },
745 { "http://[fe80::dead:beef%10]/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
746 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
747 { "http://[fe80::dead:beef%25]/", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
748 { "http", NULL, "fe80::dead:beef%25", -1, "/", NULL, NULL } },
749 { "http://[fe80::dead:beef%25]/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
750 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
751 { "http://[192.168.0.1%25em1]/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
752 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
753 { "http://[fe80::dead:beef%2em1]/", G_URI_FLAGS_PARSE_RELAXED, TRUE, 0,
754 { "http", NULL, "fe80::dead:beef%2em1", -1, "/", NULL, NULL } },
755 { "http://[fe80::dead:beef%2em1]/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
756 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
757 { "http://[fe80::dead:beef%25em1%00]/", G_URI_FLAGS_PARSE_RELAXED, FALSE, G_URI_ERROR_BAD_HOST,
758 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
759 { "http://[fe80::dead:beef%25em1%00]/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
760 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
761
762 /* Invalid IDN hostname */
763 { "http://xn--mixed-\xc3\xbcp/", G_URI_FLAGS_NONE, FALSE, G_URI_ERROR_BAD_HOST,
764 { NULL, NULL, NULL, -1, NULL, NULL, NULL } },
765};
766
767static void
768test_uri_parsing_absolute (void)
769{
770 gsize i;
771
772 for (i = 0; i < G_N_ELEMENTS (absolute_tests); i++)
773 {
774 const UriAbsoluteTest *test = &absolute_tests[i];
775 GError *error = NULL;
776 GUri *uri;
777
778 g_test_message (format: "Test %" G_GSIZE_FORMAT ": %s", i, test->orig);
779
780 uri = g_uri_parse (uri_string: test->orig, flags: test->flags, error: &error);
781 if (test->expected_success)
782 {
783 g_assert_no_error (error);
784
785 g_assert_cmpstr (g_uri_get_scheme (uri), ==, test->expected_parts.scheme);
786 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, test->expected_parts.userinfo);
787 g_assert_cmpstr (g_uri_get_host (uri), ==, test->expected_parts.host);
788 g_assert_cmpint (g_uri_get_port (uri), ==, test->expected_parts.port);
789 g_assert_cmpstr (g_uri_get_path (uri), ==, test->expected_parts.path);
790 g_assert_cmpstr (g_uri_get_query (uri), ==, test->expected_parts.query);
791 g_assert_cmpstr (g_uri_get_fragment (uri), ==, test->expected_parts.fragment);
792 }
793 else
794 {
795 g_assert_error (error, G_URI_ERROR, test->expected_error_code);
796 g_assert_null (uri);
797 }
798
799 g_clear_pointer (&uri, g_uri_unref);
800 g_clear_error (err: &error);
801 }
802}
803
804typedef struct {
805 const gchar *orig, *resolved;
806 UriParts parts;
807} UriRelativeTest;
808
809/* This all comes from RFC 3986 */
810static const char *relative_test_base = "http://a/b/c/d;p?q";
811static const UriRelativeTest relative_tests[] = {
812 { "g:h", "g:h",
813 { "g", NULL, NULL, -1, "h", NULL, NULL } },
814 { "g", "http://a/b/c/g",
815 { "http", NULL, "a", -1, "/b/c/g", NULL, NULL } },
816 { "./g", "http://a/b/c/g",
817 { "http", NULL, "a", -1, "/b/c/g", NULL, NULL } },
818 { "g/", "http://a/b/c/g/",
819 { "http", NULL, "a", -1, "/b/c/g/", NULL, NULL } },
820 { "/g", "http://a/g",
821 { "http", NULL, "a", -1, "/g", NULL, NULL } },
822 { "//g", "http://g",
823 { "http", NULL, "g", -1, "", NULL, NULL } },
824 { "?y", "http://a/b/c/d;p?y",
825 { "http", NULL, "a", -1, "/b/c/d;p", "y", NULL } },
826 { "g?y", "http://a/b/c/g?y",
827 { "http", NULL, "a", -1, "/b/c/g", "y", NULL } },
828 { "#s", "http://a/b/c/d;p?q#s",
829 { "http", NULL, "a", -1, "/b/c/d;p", "q", "s" } },
830 { "g#s", "http://a/b/c/g#s",
831 { "http", NULL, "a", -1, "/b/c/g", NULL, "s" } },
832 { "g?y#s", "http://a/b/c/g?y#s",
833 { "http", NULL, "a", -1, "/b/c/g", "y", "s" } },
834 { ";x", "http://a/b/c/;x",
835 { "http", NULL, "a", -1, "/b/c/;x", NULL, NULL } },
836 { "g;x", "http://a/b/c/g;x",
837 { "http", NULL, "a", -1, "/b/c/g;x", NULL, NULL } },
838 { "g;x?y#s", "http://a/b/c/g;x?y#s",
839 { "http", NULL, "a", -1, "/b/c/g;x", "y", "s" } },
840 { ".", "http://a/b/c/",
841 { "http", NULL, "a", -1, "/b/c/", NULL, NULL } },
842 { "./", "http://a/b/c/",
843 { "http", NULL, "a", -1, "/b/c/", NULL, NULL } },
844 { "..", "http://a/b/",
845 { "http", NULL, "a", -1, "/b/", NULL, NULL } },
846 { "../", "http://a/b/",
847 { "http", NULL, "a", -1, "/b/", NULL, NULL } },
848 { "../g", "http://a/b/g",
849 { "http", NULL, "a", -1, "/b/g", NULL, NULL } },
850 { "../..", "http://a/",
851 { "http", NULL, "a", -1, "/", NULL, NULL } },
852 { "../../", "http://a/",
853 { "http", NULL, "a", -1, "/", NULL, NULL } },
854 { "../../g", "http://a/g",
855 { "http", NULL, "a", -1, "/g", NULL, NULL } },
856 { "", "http://a/b/c/d;p?q",
857 { "http", NULL, "a", -1, "/b/c/d;p", "q", NULL } },
858 { "../../../g", "http://a/g",
859 { "http", NULL, "a", -1, "/g", NULL, NULL } },
860 { "../../../../g", "http://a/g",
861 { "http", NULL, "a", -1, "/g", NULL, NULL } },
862 { "/./g", "http://a/g",
863 { "http", NULL, "a", -1, "/g", NULL, NULL } },
864 { "/../g", "http://a/g",
865 { "http", NULL, "a", -1, "/g", NULL, NULL } },
866 { "g.", "http://a/b/c/g.",
867 { "http", NULL, "a", -1, "/b/c/g.", NULL, NULL } },
868 { ".g", "http://a/b/c/.g",
869 { "http", NULL, "a", -1, "/b/c/.g", NULL, NULL } },
870 { "g..", "http://a/b/c/g..",
871 { "http", NULL, "a", -1, "/b/c/g..", NULL, NULL } },
872 { "..g", "http://a/b/c/..g",
873 { "http", NULL, "a", -1, "/b/c/..g", NULL, NULL } },
874 { "./../g", "http://a/b/g",
875 { "http", NULL, "a", -1, "/b/g", NULL, NULL } },
876 { "./g/.", "http://a/b/c/g/",
877 { "http", NULL, "a", -1, "/b/c/g/", NULL, NULL } },
878 { "g/./h", "http://a/b/c/g/h",
879 { "http", NULL, "a", -1, "/b/c/g/h", NULL, NULL } },
880 { "g/../h", "http://a/b/c/h",
881 { "http", NULL, "a", -1, "/b/c/h", NULL, NULL } },
882 { "g;x=1/./y", "http://a/b/c/g;x=1/y",
883 { "http", NULL, "a", -1, "/b/c/g;x=1/y", NULL, NULL } },
884 { "g;x=1/../y", "http://a/b/c/y",
885 { "http", NULL, "a", -1, "/b/c/y", NULL, NULL } },
886 { "g?y/./x", "http://a/b/c/g?y/./x",
887 { "http", NULL, "a", -1, "/b/c/g", "y/./x", NULL } },
888 { "g?y/../x", "http://a/b/c/g?y/../x",
889 { "http", NULL, "a", -1, "/b/c/g", "y/../x", NULL } },
890 { "g#s/./x", "http://a/b/c/g#s/./x",
891 { "http", NULL, "a", -1, "/b/c/g", NULL, "s/./x" } },
892 { "g#s/../x", "http://a/b/c/g#s/../x",
893 { "http", NULL, "a", -1, "/b/c/g", NULL, "s/../x" } },
894 { "http:g", "http:g",
895 { "http", NULL, NULL, -1, "g", NULL, NULL } },
896 { "http://a/../..", "http://a/",
897 { "http", NULL, "a", -1, "/", NULL, NULL } },
898 { "ScHeMe://User:P%61ss@HOST.%63om:1234/path/./from/../to%7d/item%2dobj?qu%65ry=something#fr%61gment",
899 "scheme://User:Pass@HOST.com:1234/path/to%7D/item-obj?query=something#fragment",
900 { "scheme", "User:Pass", "HOST.com", 1234, "/path/to}/item-obj", "query=something", "fragment" } },
901};
902static int num_relative_tests = G_N_ELEMENTS (relative_tests);
903
904static void
905test_uri_parsing_relative (void)
906{
907 int i;
908 GUri *base, *uri;
909 GError *error = NULL;
910 gchar *resolved;
911
912 base = g_uri_parse (uri_string: relative_test_base, flags: G_URI_FLAGS_NONE, error: &error);
913 g_assert_no_error (error);
914
915 for (i = 0; i < num_relative_tests; i++)
916 {
917 const UriRelativeTest *test = &relative_tests[i];
918 gchar *tostring;
919
920 uri = g_uri_parse_relative (base_uri: base, uri_ref: test->orig, flags: G_URI_FLAGS_NONE, error: &error);
921 g_assert_no_error (error);
922
923 g_assert_cmpstr (g_uri_get_scheme (uri), ==, test->parts.scheme);
924 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, test->parts.userinfo);
925 g_assert_cmpstr (g_uri_get_host (uri), ==, test->parts.host);
926 g_assert_cmpint (g_uri_get_port (uri), ==, test->parts.port);
927 g_assert_cmpstr (g_uri_get_path (uri), ==, test->parts.path);
928 g_assert_cmpstr (g_uri_get_query (uri), ==, test->parts.query);
929 g_assert_cmpstr (g_uri_get_fragment (uri), ==, test->parts.fragment);
930
931 tostring = g_uri_to_string (uri);
932 g_assert_cmpstr (tostring, ==, test->resolved);
933 g_free (mem: tostring);
934
935 g_uri_unref (uri);
936
937 resolved = g_uri_resolve_relative (base_uri_string: relative_test_base, uri_ref: test->orig, flags: G_URI_FLAGS_NONE, error: &error);
938 g_assert_no_error (error);
939 g_assert_cmpstr (resolved, ==, test->resolved);
940 g_free (mem: resolved);
941 }
942 uri = g_uri_parse_relative (base_uri: base, uri_ref: "%%", flags: G_URI_FLAGS_NONE, error: &error);
943 g_assert_null (uri);
944 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PATH);
945 g_clear_error (err: &error);
946
947 g_uri_unref (uri: base);
948
949 resolved = g_uri_resolve_relative (NULL, uri_ref: "http://a", flags: G_URI_FLAGS_NONE, error: &error);
950 g_assert_no_error (error);
951 g_assert_cmpstr (resolved, ==, "http://a");
952 g_free (mem: resolved);
953
954 resolved = g_uri_resolve_relative (base_uri_string: "http://a", uri_ref: "b", flags: G_URI_FLAGS_NONE, error: &error);
955 g_assert_no_error (error);
956 g_assert_cmpstr (resolved, ==, "http://a/b");
957 g_free (mem: resolved);
958
959 resolved = g_uri_resolve_relative (NULL, uri_ref: "a", flags: G_URI_FLAGS_NONE, error: &error);
960 g_assert_null (resolved);
961 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED);
962 g_clear_error (err: &error);
963
964 resolved = g_uri_resolve_relative (base_uri_string: "../b", uri_ref: "a", flags: G_URI_FLAGS_NONE, error: &error);
965 g_assert_null (resolved);
966 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED);
967 g_clear_error (err: &error);
968
969 resolved = g_uri_resolve_relative (base_uri_string: "%%", uri_ref: "a", flags: G_URI_FLAGS_PARSE_RELAXED, error: &error);
970 g_assert_null (resolved);
971 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED);
972 g_clear_error (err: &error);
973}
974
975static void
976test_uri_to_string (void)
977{
978 GUri *uri;
979 gchar *tostring;
980
981 uri = g_uri_build (flags: G_URI_FLAGS_NONE, scheme: "scheme", userinfo: "userinfo", host: "host", port: 1234,
982 path: "/path", query: "query", fragment: "fragment");
983
984 tostring = g_uri_to_string (uri);
985 g_assert_cmpstr (tostring, ==, "scheme://userinfo@host:1234/path?query#fragment");
986 g_free (mem: tostring);
987 g_uri_unref (uri);
988
989 uri = g_uri_build (flags: G_URI_FLAGS_NONE, scheme: "scheme", NULL, host: "fe80::dead:beef%em1", port: -1, path: "", NULL, NULL);
990 tostring = g_uri_to_string (uri);
991 g_assert_cmpstr (tostring, ==, "scheme://[fe80::dead:beef%25em1]");
992 g_free (mem: tostring);
993 g_uri_unref (uri);
994
995 uri = g_uri_build_with_user (flags: G_URI_FLAGS_NONE, scheme: "scheme", user: "user", password: "pass", auth_params: "auth", host: "host", port: 1234,
996 path: "/path", query: "query", fragment: "fragment");
997 tostring = g_uri_to_string (uri);
998 g_assert_cmpstr (tostring, ==, "scheme://user:pass;auth@host:1234/path?query#fragment");
999 g_free (mem: tostring);
1000 tostring = g_uri_to_string_partial (uri, flags: G_URI_HIDE_USERINFO);
1001 g_assert_cmpstr (tostring, ==, "scheme://host:1234/path?query#fragment");
1002 g_free (mem: tostring);
1003 tostring = g_uri_to_string_partial (uri, flags: G_URI_HIDE_QUERY);
1004 g_assert_cmpstr (tostring, ==, "scheme://user:pass;auth@host:1234/path#fragment");
1005 g_free (mem: tostring);
1006 tostring = g_uri_to_string_partial (uri, flags: G_URI_HIDE_FRAGMENT);
1007 g_assert_cmpstr (tostring, ==, "scheme://user:pass;auth@host:1234/path?query");
1008 g_free (mem: tostring);
1009 g_uri_unref (uri);
1010
1011 uri = g_uri_build_with_user (flags: G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_HAS_AUTH_PARAMS,
1012 scheme: "scheme", user: "us:er", password: "pass", auth_params: "auth", host: "host", port: 1234,
1013 path: "/path", query: "query", fragment: "fragment");
1014 tostring = g_uri_to_string (uri);
1015 g_assert_cmpstr (tostring, ==, "scheme://us%3Aer:pass;auth@host:1234/path?query#fragment");
1016 g_free (mem: tostring);
1017 tostring = g_uri_to_string_partial (uri, flags: G_URI_HIDE_PASSWORD);
1018 g_assert_cmpstr (tostring, ==, "scheme://us%3Aer;auth@host:1234/path?query#fragment");
1019 g_free (mem: tostring);
1020 tostring = g_uri_to_string_partial (uri, flags: G_URI_HIDE_AUTH_PARAMS);
1021 g_assert_cmpstr (tostring, ==, "scheme://us%3Aer:pass@host:1234/path?query#fragment");
1022 g_free (mem: tostring);
1023 tostring = g_uri_to_string_partial (uri, flags: G_URI_HIDE_QUERY);
1024 g_assert_cmpstr (tostring, ==, "scheme://us%3Aer:pass;auth@host:1234/path#fragment");
1025 g_free (mem: tostring);
1026 g_uri_unref (uri);
1027}
1028
1029static void
1030test_uri_build (void)
1031{
1032 GUri *uri;
1033
1034 uri = g_uri_build (flags: G_URI_FLAGS_NON_DNS, scheme: "scheme", userinfo: "userinfo", host: "host", port: 1234,
1035 path: "/path", query: "query", fragment: "fragment");
1036
1037 /* check ref/unref */
1038 g_uri_ref (uri);
1039 g_uri_unref (uri);
1040
1041 g_assert_cmpint (g_uri_get_flags (uri), ==, G_URI_FLAGS_NON_DNS);
1042 g_assert_cmpstr (g_uri_get_scheme (uri), ==, "scheme");
1043 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, "userinfo");
1044 g_assert_cmpstr (g_uri_get_host (uri), ==, "host");
1045 g_assert_cmpint (g_uri_get_port (uri), ==, 1234);
1046 g_assert_cmpstr (g_uri_get_path (uri), ==, "/path");
1047 g_assert_cmpstr (g_uri_get_query (uri), ==, "query");
1048 g_assert_cmpstr (g_uri_get_fragment (uri), ==, "fragment");
1049 g_assert_cmpstr (g_uri_get_user (uri), ==, NULL);
1050 g_assert_cmpstr (g_uri_get_password (uri), ==, NULL);
1051 g_uri_unref (uri);
1052
1053 uri = g_uri_build_with_user (flags: G_URI_FLAGS_NON_DNS, scheme: "scheme", user: "user", password: "password",
1054 auth_params: "authparams", host: "host", port: 1234,
1055 path: "/path", query: "query", fragment: "fragment");
1056
1057 g_assert_cmpint (g_uri_get_flags (uri), ==, G_URI_FLAGS_NON_DNS | G_URI_FLAGS_HAS_PASSWORD);
1058 g_assert_cmpstr (g_uri_get_scheme (uri), ==, "scheme");
1059 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, "user:password;authparams");
1060 g_assert_cmpstr (g_uri_get_host (uri), ==, "host");
1061 g_assert_cmpint (g_uri_get_port (uri), ==, 1234);
1062 g_assert_cmpstr (g_uri_get_path (uri), ==, "/path");
1063 g_assert_cmpstr (g_uri_get_query (uri), ==, "query");
1064 g_assert_cmpstr (g_uri_get_fragment (uri), ==, "fragment");
1065 g_assert_cmpstr (g_uri_get_user (uri), ==, "user");
1066 g_assert_cmpstr (g_uri_get_password (uri), ==, "password");
1067 g_assert_cmpstr (g_uri_get_auth_params (uri), ==, "authparams");
1068 g_uri_unref (uri);
1069
1070 uri = g_uri_build_with_user (flags: G_URI_FLAGS_NONE, scheme: "scheme", user: "user\001", password: "password\002",
1071 auth_params: "authparams\003", host: "host", port: 1234,
1072 path: "/path", query: "query", fragment: "fragment");
1073 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, "user\001:password\002;authparams\003");
1074 g_uri_unref (uri);
1075
1076 uri = g_uri_build_with_user (flags: G_URI_FLAGS_ENCODED, scheme: "scheme", user: "user%01", password: "password%02",
1077 auth_params: "authparams%03", host: "host", port: 1234,
1078 path: "/path", query: "query", fragment: "fragment");
1079 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, "user%01:password%02;authparams%03");
1080 g_uri_unref (uri);
1081
1082 uri = g_uri_build_with_user (flags: G_URI_FLAGS_ENCODED, scheme: "scheme", NULL, NULL,
1083 NULL, host: "host", port: 1234,
1084 path: "/path", query: "query", fragment: "fragment");
1085 g_assert_null (g_uri_get_userinfo (uri));
1086 g_uri_unref (uri);
1087
1088 uri = g_uri_build_with_user (flags: G_URI_FLAGS_NONE, scheme: "scheme", user: "user", NULL, NULL,
1089 host: "host", port: 1234,
1090 path: "/path", query: "query", fragment: "fragment");
1091 g_assert_cmpstr (g_uri_get_userinfo (uri), ==, "user");
1092 g_uri_unref (uri);
1093}
1094
1095static void
1096test_uri_split (void)
1097{
1098 gchar *scheme = NULL;
1099 gchar *userinfo = NULL;
1100 gchar *user = NULL;
1101 gchar *pass = NULL;
1102 gchar *authparams = NULL;
1103 gchar *host = NULL;
1104 gchar *path = NULL;
1105 gchar *query = NULL;
1106 gchar *fragment = NULL;
1107 GError *error = NULL;
1108 gint port;
1109
1110 g_uri_split (uri_ref: "scheme://user%3Apass%3Bauth@host:1234/path?query#fragment",
1111 flags: G_URI_FLAGS_NONE,
1112 scheme: &scheme,
1113 userinfo: &userinfo,
1114 host: &host,
1115 port: &port,
1116 path: &path,
1117 query: &query,
1118 fragment: &fragment,
1119 error: &error);
1120 g_assert_no_error (error);
1121 g_assert_cmpstr (scheme, ==, "scheme");
1122 g_assert_cmpstr (userinfo, ==, "user:pass;auth");
1123 g_assert_cmpstr (host, ==, "host");
1124 g_assert_cmpint (port, ==, 1234);
1125 g_assert_cmpstr (path, ==, "/path");
1126 g_assert_cmpstr (query, ==, "query");
1127 g_assert_cmpstr (fragment, ==, "fragment");
1128 g_free (mem: scheme);
1129 g_free (mem: userinfo);
1130 g_free (mem: host);
1131 g_free (mem: path);
1132 g_free (mem: query);
1133 g_free (mem: fragment);
1134
1135 g_uri_split (uri_ref: "scheme://user%3Apass%3Bauth@h%01st:1234/path?query#fragment",
1136 flags: G_URI_FLAGS_ENCODED,
1137 NULL,
1138 NULL,
1139 host: &host,
1140 NULL,
1141 NULL,
1142 NULL,
1143 NULL,
1144 error: &error);
1145 g_assert_no_error (error);
1146 g_assert_cmpstr (host, ==, "h\001st");
1147 g_free (mem: host);
1148
1149 g_uri_split (uri_ref: "scheme://@@@host:1234/path?query#fragment",
1150 flags: G_URI_FLAGS_ENCODED | G_URI_FLAGS_PARSE_RELAXED,
1151 NULL,
1152 userinfo: &userinfo,
1153 NULL,
1154 NULL,
1155 NULL,
1156 NULL,
1157 NULL,
1158 error: &error);
1159 g_assert_no_error (error);
1160 g_assert_cmpstr (userinfo, ==, "@@");
1161 g_free (mem: userinfo);
1162
1163
1164 g_uri_split (uri_ref: "http://f;oo/",
1165 flags: G_URI_FLAGS_NONE | G_URI_FLAGS_PARSE_RELAXED,
1166 NULL,
1167 NULL,
1168 NULL,
1169 NULL,
1170 path: &path,
1171 NULL,
1172 NULL,
1173 error: &error);
1174 g_assert_no_error (error);
1175 g_assert_cmpstr (path, ==, ";oo/");
1176 g_free (mem: path);
1177
1178 g_uri_split (uri_ref: "http://h%01st/path?saisons=%C3%89t%C3%A9%2Bhiver",
1179 flags: G_URI_FLAGS_NONE,
1180 NULL,
1181 NULL,
1182 host: &host,
1183 NULL,
1184 NULL,
1185 query: &query,
1186 NULL,
1187 error: &error);
1188 g_assert_no_error (error);
1189 g_assert_cmpstr (host, ==, "h\001st");
1190 g_assert_cmpstr (query, ==, "saisons=Été+hiver");
1191 g_free (mem: host);
1192 g_free (mem: query);
1193
1194 g_uri_split (uri_ref: "http://h%01st/path?saisons=%C3%89t%C3%A9%2Bhiver",
1195 flags: G_URI_FLAGS_ENCODED_QUERY,
1196 NULL,
1197 NULL,
1198 host: &host,
1199 NULL,
1200 NULL,
1201 query: &query,
1202 NULL,
1203 error: &error);
1204 g_assert_no_error (error);
1205 g_assert_cmpstr (host, ==, "h\001st");
1206 g_assert_cmpstr (query, ==, "saisons=%C3%89t%C3%A9%2Bhiver");
1207 g_free (mem: host);
1208 g_free (mem: query);
1209
1210 g_uri_split (uri_ref: "http://h%01st/%C3%89t%C3%A9%2Bhiver",
1211 flags: G_URI_FLAGS_ENCODED_PATH,
1212 NULL,
1213 NULL,
1214 NULL,
1215 NULL,
1216 path: &path,
1217 NULL,
1218 NULL,
1219 error: &error);
1220 g_assert_no_error (error);
1221 g_assert_cmpstr (path, ==, "/%C3%89t%C3%A9%2Bhiver");
1222 g_free (mem: path);
1223
1224 g_uri_split (uri_ref: "file:///path/to/some%20file",
1225 flags: G_URI_FLAGS_NONE,
1226 NULL,
1227 NULL,
1228 NULL,
1229 NULL,
1230 path: &path,
1231 NULL,
1232 NULL,
1233 error: &error);
1234 g_assert_no_error (error);
1235 g_assert_cmpstr (path, ==, "/path/to/some file");
1236 g_free (mem: path);
1237
1238 g_uri_split (uri_ref: "http://h%01st/path#%C3%89t%C3%A9%2Bhiver",
1239 flags: G_URI_FLAGS_ENCODED_FRAGMENT,
1240 NULL,
1241 NULL,
1242 NULL,
1243 NULL,
1244 NULL,
1245 NULL,
1246 fragment: &fragment,
1247 error: &error);
1248 g_assert_no_error (error);
1249 g_assert_cmpstr (fragment, ==, "%C3%89t%C3%A9%2Bhiver");
1250 g_free (mem: fragment);
1251
1252 g_uri_split_with_user (uri_ref: "scheme://user:pass;auth@host:1234/path?query#fragment",
1253 flags: G_URI_FLAGS_HAS_AUTH_PARAMS|G_URI_FLAGS_HAS_PASSWORD,
1254 NULL,
1255 user: &user,
1256 password: &pass,
1257 auth_params: &authparams,
1258 NULL,
1259 NULL,
1260 NULL,
1261 NULL,
1262 NULL,
1263 error: &error);
1264 g_assert_no_error (error);
1265 g_assert_cmpstr (user, ==, "user");
1266 g_assert_cmpstr (pass, ==, "pass");
1267 g_assert_cmpstr (authparams, ==, "auth");
1268 g_free (mem: user);
1269 g_free (mem: pass);
1270 g_free (mem: authparams);
1271
1272 g_uri_split_network (uri_string: "scheme://user:pass;auth@host:1234/path?query#fragment",
1273 flags: G_URI_FLAGS_NONE,
1274 NULL,
1275 NULL,
1276 NULL,
1277 error: &error);
1278 g_assert_no_error (error);
1279
1280 g_uri_split_network (uri_string: "scheme://user:pass;auth@host:1234/path?query#fragment",
1281 flags: G_URI_FLAGS_NONE,
1282 scheme: &scheme,
1283 host: &host,
1284 port: &port,
1285 error: &error);
1286 g_assert_no_error (error);
1287 g_assert_cmpstr (scheme, ==, "scheme");
1288 g_assert_cmpstr (host, ==, "host");
1289 g_assert_cmpint (port, ==, 1234);
1290 g_free (mem: scheme);
1291 g_free (mem: host);
1292
1293 g_uri_split_network (uri_string: "%00",
1294 flags: G_URI_FLAGS_NONE, NULL, NULL, NULL, error: &error);
1295 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PATH);
1296 g_clear_error (err: &error);
1297
1298 g_uri_split_network (uri_string: "/a",
1299 flags: G_URI_FLAGS_NONE,
1300 scheme: &scheme,
1301 host: &host,
1302 port: &port,
1303 error: &error);
1304 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_SCHEME);
1305 g_clear_error (err: &error);
1306
1307 g_uri_split_network (uri_string: "schme:#",
1308 flags: G_URI_FLAGS_NONE,
1309 scheme: &scheme,
1310 host: &host,
1311 port: &port,
1312 error: &error);
1313 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1314 g_clear_error (err: &error);
1315
1316 g_uri_split_network (uri_string: "scheme://[]/a",
1317 flags: G_URI_FLAGS_NONE, NULL, NULL, NULL, error: &error);
1318 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1319 g_clear_error (err: &error);
1320
1321 g_uri_split_network (uri_string: "scheme://user%00:pass;auth@host",
1322 flags: G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_HAS_AUTH_PARAMS,
1323 NULL, NULL, NULL, error: &error);
1324 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_USER);
1325 g_clear_error (err: &error);
1326
1327 g_uri_split_network (uri_string: "scheme://user:pass%00;auth@host",
1328 flags: G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_HAS_AUTH_PARAMS,
1329 NULL, NULL, NULL, error: &error);
1330 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PASSWORD);
1331 g_clear_error (err: &error);
1332
1333 g_uri_split_network (uri_string: "scheme://user:pass;auth@host:1234/path?quer%00y#fragment",
1334 flags: G_URI_FLAGS_NONE,
1335 NULL, NULL, NULL, error: &error);
1336 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_QUERY);
1337 g_clear_error (err: &error);
1338
1339 g_uri_split_network (uri_string: "scheme://use%00r:pass;auth@host:1234/path",
1340 flags: G_URI_FLAGS_NONE,
1341 NULL, NULL, NULL, error: &error);
1342 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_USER);
1343 g_clear_error (err: &error);
1344
1345 g_uri_split (uri_ref: "scheme://user:pass;auth@host:1234/path?query#fragm%00ent",
1346 flags: G_URI_FLAGS_NONE,
1347 scheme: &scheme,
1348 userinfo: &userinfo,
1349 host: &host,
1350 port: &port,
1351 path: &path,
1352 query: &query,
1353 fragment: &fragment,
1354 error: &error);
1355 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_FRAGMENT);
1356 g_clear_error (err: &error);
1357
1358 g_uri_split_with_user (uri_ref: "scheme://user:pa%x0s;auth@host:1234/path?query#fragment",
1359 flags: G_URI_FLAGS_HAS_PASSWORD,
1360 scheme: &scheme,
1361 user: &user,
1362 password: &pass,
1363 auth_params: &authparams,
1364 host: &host,
1365 port: &port,
1366 path: &path,
1367 query: &query,
1368 fragment: &fragment,
1369 error: &error);
1370 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PASSWORD);
1371 g_clear_error (err: &error);
1372
1373 g_uri_split_with_user (uri_ref: "scheme://user:pass;auth%00@host",
1374 flags: G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_HAS_AUTH_PARAMS,
1375 scheme: &scheme,
1376 user: &user,
1377 password: &pass,
1378 auth_params: &authparams,
1379 host: &host,
1380 port: &port,
1381 path: &path,
1382 query: &query,
1383 fragment: &fragment,
1384 error: &error);
1385 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_AUTH_PARAMS);
1386 g_clear_error (err: &error);
1387
1388 g_uri_split_network (uri_string: "scheme://user:pass%00;auth@host",
1389 flags: G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_HAS_AUTH_PARAMS,
1390 NULL, NULL, NULL, error: &error);
1391 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PASSWORD);
1392 g_clear_error (err: &error);
1393
1394 /* Path not started correctly */
1395 g_uri_split(uri_ref: "scheme://hostname:123path?query#fragment",
1396 flags: G_URI_FLAGS_NONE,
1397 scheme: &scheme,
1398 userinfo: &userinfo,
1399 host: &host,
1400 port: &port,
1401 path: &path,
1402 query: &query,
1403 fragment: &fragment,
1404 error: &error);
1405 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT);
1406 g_clear_error (err: &error);
1407
1408 /* Brackets that don't close */
1409 g_uri_split(uri_ref: "scheme://[01:23:45:67:89:ab:cd:ef:123/path",
1410 flags: G_URI_FLAGS_NONE,
1411 scheme: &scheme,
1412 userinfo: &userinfo,
1413 host: &host,
1414 port: &port,
1415 path: &path,
1416 query: &query,
1417 fragment: &fragment,
1418 error: &error);
1419 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1420 g_clear_error (err: &error);
1421
1422 /* IPv6 hostname without brackets */
1423 g_uri_split(uri_ref: "scheme://01:23:45:67:89:ab:cd:ef:123/path",
1424 flags: G_URI_FLAGS_NONE,
1425 scheme: &scheme,
1426 userinfo: &userinfo,
1427 host: &host,
1428 port: &port,
1429 path: &path,
1430 query: &query,
1431 fragment: &fragment,
1432 error: &error);
1433 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT);
1434 g_clear_error (err: &error);
1435}
1436
1437static void
1438test_uri_is_valid (void)
1439{
1440 GError *error = NULL;
1441
1442 g_assert_true (g_uri_is_valid ("http://[::192.9.5.5]/ipng", G_URI_FLAGS_NONE, NULL));
1443 g_assert_true (g_uri_is_valid ("http://127.127.127.127/", G_URI_FLAGS_NONE, NULL));
1444 g_assert_true (g_uri_is_valid ("http://127.127.127.b/", G_URI_FLAGS_NONE, NULL));
1445 g_assert_true (g_uri_is_valid ("http://\xc3\x89XAMPLE.COM/", G_URI_FLAGS_NONE, NULL));
1446
1447 g_assert_true (g_uri_is_valid (" \r http\t://f oo \t\n ", G_URI_FLAGS_PARSE_RELAXED, NULL));
1448 g_assert_false (g_uri_is_valid (" \r http\t://f oo \t\n ", G_URI_FLAGS_NONE, &error));
1449 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_SCHEME);
1450 g_clear_error (err: &error);
1451
1452 g_assert_false (g_uri_is_valid ("http://[::192.9.5.5/ipng", G_URI_FLAGS_NONE, &error));
1453 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1454 g_clear_error (err: &error);
1455
1456 g_assert_true (g_uri_is_valid ("http://[fe80::dead:beef%25wef]/", G_URI_FLAGS_NONE, NULL));
1457 g_assert_false (g_uri_is_valid ("http://[fe80::dead:beef%wef%]/", G_URI_FLAGS_NONE, &error));
1458 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1459 g_clear_error (err: &error);
1460
1461 g_assert_false (g_uri_is_valid ("http://%00/", G_URI_FLAGS_NON_DNS, &error));
1462 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1463 g_clear_error (err: &error);
1464
1465 g_assert_true (g_uri_is_valid ("http://foo/", G_URI_FLAGS_NON_DNS, &error));
1466
1467 g_assert_false (g_uri_is_valid ("http://%00/", G_URI_FLAGS_NONE, &error));
1468 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1469 g_clear_error (err: &error);
1470
1471 g_assert_false (g_uri_is_valid ("http://%30.%30.%30.%30/", G_URI_FLAGS_NONE, &error));
1472 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST);
1473 g_clear_error (err: &error);
1474
1475 g_assert_false (g_uri_is_valid ("http://host:port", G_URI_FLAGS_NONE, &error));
1476 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT);
1477 g_clear_error (err: &error);
1478
1479 g_assert_false (g_uri_is_valid ("http://host:65536", G_URI_FLAGS_NONE, &error));
1480 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT);
1481 g_clear_error (err: &error);
1482
1483 g_assert_false (g_uri_is_valid ("http://host:6553l", G_URI_FLAGS_NONE, &error));
1484 g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT);
1485 g_clear_error (err: &error);
1486
1487 g_assert_true (g_uri_is_valid ("data:,Hello", G_URI_FLAGS_NONE, &error));
1488
1489 g_assert_true (g_uri_is_valid ("B:\\foo.txt", G_URI_FLAGS_NONE, &error));
1490 g_assert_true (g_uri_is_valid ("B:/foo.txt", G_URI_FLAGS_NONE, &error));
1491 g_assert_true (g_uri_is_valid ("B://foo.txt", G_URI_FLAGS_NONE, &error));
1492 g_assert_true (g_uri_is_valid ("B:foo.txt", G_URI_FLAGS_NONE, &error));
1493
1494 g_assert_true (g_uri_is_valid ("fd://0", G_URI_FLAGS_NONE, &error));
1495 g_assert_true (g_uri_is_valid ("AB:\\foo.txt", G_URI_FLAGS_NONE, &error));
1496 g_assert_true (g_uri_is_valid ("AB:/foo.txt", G_URI_FLAGS_NONE, &error));
1497 g_assert_true (g_uri_is_valid ("AB://foo.txt", G_URI_FLAGS_NONE, &error));
1498 g_assert_true (g_uri_is_valid ("AB:foo.txt", G_URI_FLAGS_NONE, &error));
1499
1500 g_assert_true (g_uri_is_valid ("ABC:/foo.txt", G_URI_FLAGS_NONE, &error));
1501 g_assert_true (g_uri_is_valid ("ABC://foo.txt", G_URI_FLAGS_NONE, &error));
1502 g_assert_true (g_uri_is_valid ("ABC:foo.txt", G_URI_FLAGS_NONE, &error));
1503
1504 g_assert_true (g_uri_is_valid ("ABCD:/foo.txt", G_URI_FLAGS_NONE, &error));
1505 g_assert_true (g_uri_is_valid ("ABCD://foo.txt", G_URI_FLAGS_NONE, &error));
1506 g_assert_true (g_uri_is_valid ("ABCD:foo.txt", G_URI_FLAGS_NONE, &error));
1507}
1508
1509static const struct
1510{
1511 /* Inputs */
1512 const gchar *uri;
1513 gchar *separators;
1514 GUriParamsFlags flags;
1515 /* Outputs */
1516 /* key, value, key, value, …, limited to length 2*expected_n_params */
1517 gssize expected_n_iter; /* -1 => error expected */
1518 const gchar *expected_iter_key_values[6];
1519 gssize expected_n_params; /* -1 => error expected */
1520 const gchar *expected_param_key_values[6];
1521} params_tests[] =
1522 {
1523 { "p1=foo&p2=bar;p3=baz", "&;", G_URI_PARAMS_NONE,
1524 3, { "p1", "foo", "p2", "bar", "p3", "baz" },
1525 3, { "p1", "foo", "p2", "bar", "p3", "baz" }},
1526 { "p1=foo&p2=bar", "", G_URI_PARAMS_NONE,
1527 1, { "p1", "foo&p2=bar" },
1528 1, { "p1", "foo&p2=bar" }},
1529 { "p1=foo&&P1=bar", "&", G_URI_PARAMS_NONE,
1530 1, { "p1", "foo" },
1531 -1, { NULL, }},
1532 { "%00=foo", "&", G_URI_PARAMS_NONE,
1533 0, { NULL, },
1534 -1, { NULL, }},
1535 { "p1=%00", "&", G_URI_PARAMS_NONE,
1536 0, { NULL, },
1537 -1, { NULL, }},
1538 { "p1=foo&p1=bar", "&", G_URI_PARAMS_NONE,
1539 2, { "p1", "foo", "p1", "bar" },
1540 1, { "p1", "bar", NULL, }},
1541 { "p1=foo&P1=bar", "&", G_URI_PARAMS_CASE_INSENSITIVE,
1542 2, { "p1", "foo", "P1", "bar" },
1543 1, { "p1", "bar", NULL, }},
1544 { "=%", "&", G_URI_PARAMS_PARSE_RELAXED,
1545 1, { "", "%", NULL, },
1546 1, { "", "%", NULL, }},
1547 { "=", "&", G_URI_PARAMS_NONE,
1548 1, { "", "", NULL, },
1549 1, { "", "", NULL, }},
1550 { "foo", "&", G_URI_PARAMS_NONE,
1551 0, { NULL, },
1552 -1, { NULL, }},
1553 { "foo=bar+%26+baz&saisons=%C3%89t%C3%A9%2Bhiver", "&", G_URI_PARAMS_WWW_FORM,
1554 2, { "foo", "bar & baz", "saisons", "Été+hiver", NULL, },
1555 2, { "foo", "bar & baz", "saisons", "Été+hiver", NULL, }},
1556 { "foo=bar+%26+baz&saisons=%C3%89t%C3%A9%2Bhiver", "&", G_URI_PARAMS_NONE,
1557 2, { "foo", "bar+&+baz", "saisons", "Été+hiver", NULL, },
1558 2, { "foo", "bar+&+baz", "saisons", "Été+hiver", NULL, }},
1559 { "token=exp=123~acl=/QualityLevels(*~hmac=0cb", "&", G_URI_PARAMS_NONE,
1560 1, { "token", "exp=123~acl=/QualityLevels(*~hmac=0cb", NULL, },
1561 1, { "token", "exp=123~acl=/QualityLevels(*~hmac=0cb", NULL, }},
1562 };
1563
1564static void
1565test_uri_iter_params (gconstpointer test_data)
1566{
1567 GError *err = NULL;
1568 gboolean use_nul_terminated = GPOINTER_TO_INT (test_data);
1569 gsize i, n;
1570
1571 for (i = 0; i < G_N_ELEMENTS (params_tests); i++)
1572 {
1573 GUriParamsIter iter;
1574 gchar *uri, *attr, *value;
1575 gssize uri_len;
1576
1577 g_test_message (format: "URI %" G_GSIZE_FORMAT ": %s", i, params_tests[i].uri);
1578
1579 g_assert (params_tests[i].expected_n_params < 0 ||
1580 params_tests[i].expected_n_params <= (gssize) G_N_ELEMENTS (params_tests[i].expected_param_key_values) / 2);
1581
1582 /* The tests get run twice: once with the length unspecified, using a
1583 * nul-terminated string; and once with the length specified and a copy of
1584 * the string with the trailing nul explicitly removed (to help catch
1585 * buffer overflows). */
1586 if (use_nul_terminated)
1587 {
1588 uri_len = -1;
1589 uri = g_strdup (str: params_tests[i].uri);
1590 }
1591 else
1592 {
1593 uri_len = strlen (s: params_tests[i].uri); /* no trailing nul */
1594 uri = g_memdup2 (mem: params_tests[i].uri, byte_size: uri_len);
1595 }
1596
1597 /* Run once without extracting the attr or value, just to check the numbers. */
1598 n = 0;
1599 g_uri_params_iter_init (iter: &iter, params: params_tests[i].uri, length: -1, separators: params_tests[i].separators, flags: params_tests[i].flags);
1600 while (g_uri_params_iter_next (iter: &iter, NULL, NULL, error: &err))
1601 n++;
1602 g_assert_cmpint (n, ==, params_tests[i].expected_n_iter);
1603 if (err)
1604 {
1605 g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED);
1606 g_clear_error (err: &err);
1607 }
1608
1609 /* Run again and check the strings too. */
1610 n = 0;
1611 g_uri_params_iter_init (iter: &iter, params: params_tests[i].uri, length: -1, separators: params_tests[i].separators, flags: params_tests[i].flags);
1612 while (g_uri_params_iter_next (iter: &iter, attribute: &attr, value: &value, error: &err))
1613 {
1614 g_assert_cmpstr (attr, ==, params_tests[i].expected_iter_key_values[n * 2]);
1615 g_assert_cmpstr (value, ==, params_tests[i].expected_iter_key_values[n * 2 + 1]);
1616 n++;
1617 g_free (mem: attr);
1618 g_free (mem: value);
1619 }
1620 g_assert_cmpint (n, ==, params_tests[i].expected_n_iter);
1621 if (err)
1622 {
1623 g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED);
1624 g_clear_error (err: &err);
1625 }
1626
1627 g_free (mem: uri);
1628 }
1629}
1630
1631static void
1632test_uri_parse_params (gconstpointer test_data)
1633{
1634 GError *err = NULL;
1635 gboolean use_nul_terminated = GPOINTER_TO_INT (test_data);
1636 gsize i;
1637
1638 for (i = 0; i < G_N_ELEMENTS (params_tests); i++)
1639 {
1640 GHashTable *params;
1641 gchar *uri = NULL;
1642 gssize uri_len;
1643
1644 g_test_message (format: "URI %" G_GSIZE_FORMAT ": %s", i, params_tests[i].uri);
1645
1646 g_assert (params_tests[i].expected_n_params < 0 ||
1647 params_tests[i].expected_n_params <= (gssize) G_N_ELEMENTS (params_tests[i].expected_param_key_values) / 2);
1648
1649 /* The tests get run twice: once with the length unspecified, using a
1650 * nul-terminated string; and once with the length specified and a copy of
1651 * the string with the trailing nul explicitly removed (to help catch
1652 * buffer overflows). */
1653 if (use_nul_terminated)
1654 {
1655 uri_len = -1;
1656 uri = g_strdup (str: params_tests[i].uri);
1657 }
1658 else
1659 {
1660 uri_len = strlen (s: params_tests[i].uri); /* no trailing nul */
1661 uri = g_memdup2 (mem: params_tests[i].uri, byte_size: uri_len);
1662 }
1663
1664 params = g_uri_parse_params (params: uri, length: uri_len, separators: params_tests[i].separators, flags: params_tests[i].flags, error: &err);
1665
1666 if (params_tests[i].expected_n_params < 0)
1667 {
1668 g_assert_null (params);
1669 g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED);
1670 g_clear_error (err: &err);
1671 }
1672 else
1673 {
1674 gsize j;
1675
1676 g_assert_no_error (err);
1677 g_assert_cmpint (g_hash_table_size (params), ==, params_tests[i].expected_n_params);
1678
1679 for (j = 0; j < (gsize) params_tests[i].expected_n_params; j += 2)
1680 g_assert_cmpstr (g_hash_table_lookup (params, params_tests[i].expected_param_key_values[j]), ==,
1681 params_tests[i].expected_param_key_values[j + 1]);
1682 }
1683
1684 g_clear_pointer (&params, g_hash_table_unref);
1685 g_free (mem: uri);
1686 }
1687}
1688
1689static void
1690test_uri_join (void)
1691{
1692 gchar *uri = NULL;
1693
1694 uri = g_uri_join (flags: G_URI_FLAGS_NONE, scheme: "foo", userinfo: "some:user@info", host: "bar", port: -1, path: "", NULL, NULL);
1695 g_assert_cmpstr (uri, ==, "foo://some:user%40info@bar");
1696 g_free (mem: uri);
1697
1698 uri = g_uri_join (flags: G_URI_FLAGS_NONE, NULL, NULL, NULL, port: -1, path: "/foo", query: "abc", NULL);
1699 g_assert_cmpstr (uri, ==, "/foo?abc");
1700 g_free (mem: uri);
1701
1702 uri = g_uri_join (flags: G_URI_FLAGS_NONE, NULL, NULL, host: "hostname", port: -1, path: "/foo", query: "abc", NULL);
1703 g_assert_cmpstr (uri, ==, "//hostname/foo?abc");
1704 g_free (mem: uri);
1705
1706 uri = g_uri_join_with_user (flags: G_URI_FLAGS_NONE, scheme: "scheme", user: "user\001", password: "pass\002", auth_params: "authparams\003",
1707 host: "host", port: 9876, path: "/path", query: "query", fragment: "fragment");
1708 g_assert_cmpstr (uri, ==, "scheme://user%01:pass%02;authparams%03@host:9876/path?query#fragment");
1709 g_free (mem: uri);
1710
1711 uri = g_uri_join_with_user (flags: G_URI_FLAGS_NONE, scheme: "scheme", user: "user\001", password: "pass\002", auth_params: "authparams\003",
1712 host: "::192.9.5.5", port: 9876, path: "/path", query: "query", fragment: "fragment");
1713 g_assert_cmpstr (uri, ==, "scheme://user%01:pass%02;authparams%03@[::192.9.5.5]:9876/path?query#fragment");
1714 g_free (mem: uri);
1715
1716 uri = g_uri_join_with_user (flags: G_URI_FLAGS_ENCODED,
1717 scheme: "scheme", user: "user%01", password: "pass%02", auth_params: "authparams%03",
1718 host: "::192.9.5.5", port: 9876, path: "/path", query: "query", fragment: "fragment");
1719 g_assert_cmpstr (uri, ==,
1720 "scheme://user%01:pass%02;authparams%03@[::192.9.5.5]:9876/path?query#fragment");
1721 g_free (mem: uri);
1722
1723 uri = g_uri_join (flags: G_URI_FLAGS_NONE, scheme: "scheme", NULL, host: "foo:bar._webdav._tcp.local", port: -1, path: "", NULL, NULL);
1724 g_assert_cmpstr (uri, ==, "scheme://foo%3Abar._webdav._tcp.local");
1725 g_free (mem: uri);
1726}
1727
1728static void
1729test_uri_join_split_round_trip (void)
1730{
1731 GUriFlags flags = G_URI_FLAGS_HAS_PASSWORD | G_URI_FLAGS_HAS_AUTH_PARAMS;
1732 guint i;
1733
1734 g_test_summary (summary: "Test that joining different URI components survives a round trip");
1735
1736 /* Each bit in @i indicates whether the corresponding URI field should be set
1737 * or %NULL. */
1738 for (i = 0; i < (1 << 8); i++)
1739 {
1740 gchar *uri = NULL;
1741 const gchar *scheme, *user, *password, *auth_params, *host, *path, *query, *fragment;
1742 gint port;
1743 gchar *scheme_out = NULL, *user_out = NULL, *password_out = NULL;
1744 gchar *auth_params_out = NULL, *host_out = NULL, *path_out = NULL;
1745 gchar *query_out = NULL, *fragment_out = NULL;
1746 gint port_out = -1;
1747 gboolean split_success;
1748 GError *local_error = NULL;
1749
1750 g_test_message (format: "Combination %u", i);
1751
1752 scheme = (i & (1 << 8)) ? "scheme" : NULL;
1753 host = (i & (1 << 4)) ? "host" : NULL;
1754 user = (host != NULL && i & (1 << 7)) ? "user" : NULL; /* only supported if host is also set */
1755 password = (host != NULL && user != NULL && i & (1 << 6)) ? "password" : NULL; /* only supported if host and user are also set */
1756 auth_params = (host != NULL && user != NULL && i & (1 << 5)) ? "auth_params" : NULL; /* only supported if host and user are also set */
1757 port = (host != NULL && i & (1 << 3)) ? 123 : -1; /* only supported if host is also set */
1758 path = (i & (1 << 2)) ? "/path" : ""; /* the only mandatory component */
1759 query = (i & (1 << 1)) ? "query" : NULL;
1760 fragment = (i & (1 << 0)) ? "fragment" : NULL;
1761
1762 uri = g_uri_join_with_user (flags, scheme, user, password, auth_params,
1763 host, port, path, query, fragment);
1764 g_assert_nonnull (uri);
1765
1766 split_success = g_uri_split_with_user (uri_ref: uri, flags, scheme: &scheme_out, user: &user_out,
1767 password: &password_out, auth_params: &auth_params_out,
1768 host: &host_out, port: &port_out, path: &path_out,
1769 query: &query_out, fragment: &fragment_out,
1770 error: &local_error);
1771 g_assert_no_error (local_error);
1772 g_assert_true (split_success);
1773
1774 g_assert_cmpstr (scheme, ==, scheme_out);
1775 g_assert_cmpstr (user, ==, user_out);
1776 g_assert_cmpstr (password, ==, password_out);
1777 g_assert_cmpstr (auth_params, ==, auth_params_out);
1778 g_assert_cmpstr (host, ==, host_out);
1779 g_assert_cmpint (port, ==, port_out);
1780 g_assert_cmpstr (path, ==, path_out);
1781 g_assert_cmpstr (query, ==, query_out);
1782 g_assert_cmpstr (fragment, ==, fragment_out);
1783
1784 g_free (mem: uri);
1785 g_free (mem: scheme_out);
1786 g_free (mem: user_out);
1787 g_free (mem: password_out);
1788 g_free (mem: auth_params_out);
1789 g_free (mem: host_out);
1790 g_free (mem: path_out);
1791 g_free (mem: query_out);
1792 g_free (mem: fragment_out);
1793 }
1794}
1795
1796static const struct
1797{
1798 /* Inputs */
1799 const gchar *base;
1800 const gchar *uri;
1801 GUriFlags flags;
1802 /* Outputs */
1803 const gchar *uri_string;
1804 const gchar *path;
1805 int port;
1806} normalize_parse_tests[] =
1807 {
1808 { NULL, "http://foo/path with spaces", G_URI_FLAGS_ENCODED,
1809 "http://foo/path%20with%20spaces", "/path%20with%20spaces", -1 },
1810 { NULL, "http://foo/path with spaces 2", G_URI_FLAGS_ENCODED_PATH,
1811 "http://foo/path%20with%20spaces%202", "/path%20with%20spaces%202", -1 },
1812 { NULL, "http://foo/%aa", G_URI_FLAGS_ENCODED,
1813 "http://foo/%AA", "/%AA", -1 },
1814 { NULL, "http://foo/p\xc3\xa4th/", G_URI_FLAGS_ENCODED | G_URI_FLAGS_PARSE_RELAXED,
1815 "http://foo/p%C3%A4th/", "/p%C3%A4th/", -1 },
1816 { NULL, "http://foo", G_URI_FLAGS_NONE,
1817 "http://foo", "", -1 },
1818 { NULL, "http://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1819 "http://foo/", "/", 80 },
1820 { NULL, "nothttp://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1821 "nothttp://foo", "", -1 },
1822 { NULL, "http://foo:80", G_URI_FLAGS_NONE,
1823 "http://foo:80", "", 80 },
1824 { NULL, "http://foo:80", G_URI_FLAGS_SCHEME_NORMALIZE,
1825 "http://foo/", "/", 80 },
1826 { NULL, "http://foo:8080", G_URI_FLAGS_SCHEME_NORMALIZE,
1827 "http://foo:8080/", "/", 8080 },
1828 { NULL, "https://foo:443", G_URI_FLAGS_SCHEME_NORMALIZE,
1829 "https://foo/", "/", 443 },
1830 { NULL, "https://foo:943", G_URI_FLAGS_SCHEME_NORMALIZE,
1831 "https://foo:943/", "/", 943 },
1832 { NULL, "ws://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1833 "ws://foo/", "/", 80 },
1834 { NULL, "wss://foo:443", G_URI_FLAGS_SCHEME_NORMALIZE,
1835 "wss://foo/", "/", 443 },
1836 { NULL, "ftp://foo", G_URI_FLAGS_NONE,
1837 "ftp://foo", "", -1 },
1838 { NULL, "ftp://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1839 "ftp://foo", "", 21 },
1840 { NULL, "ftp://foo:21", G_URI_FLAGS_SCHEME_NORMALIZE,
1841 "ftp://foo", "", 21 },
1842 { NULL, "ftp://foo:2100", G_URI_FLAGS_SCHEME_NORMALIZE,
1843 "ftp://foo:2100", "", 2100 },
1844 { NULL, "nothttp://foo:80", G_URI_FLAGS_SCHEME_NORMALIZE,
1845 "nothttp://foo:80", "", 80 },
1846 { "http://foo", "//bar", G_URI_FLAGS_SCHEME_NORMALIZE,
1847 "http://bar/", "/", 80 },
1848 { "http://foo", "//bar:80", G_URI_FLAGS_SCHEME_NORMALIZE,
1849 "http://bar/", "/", 80 },
1850 { "nothttp://foo", "//bar:80", G_URI_FLAGS_SCHEME_NORMALIZE,
1851 "nothttp://bar:80", "", 80 },
1852 { "http://foo", "//bar", G_URI_FLAGS_NONE,
1853 "http://bar", "", -1 },
1854 { "ScHeMe://User:P%61ss@HOST.%63om:1234/path",
1855 "ScHeMe://User:P%61ss@HOST.%63om:1234/path/./from/../to%7d/item%2dobj?qu%65ry=something#fr%61gment",
1856 G_URI_FLAGS_SCHEME_NORMALIZE,
1857 "scheme://User:Pass@HOST.com:1234/path/to%7D/item-obj?query=something#fragment",
1858 "/path/to}/item-obj", 1234 },
1859 };
1860
1861static const struct
1862{
1863 /* Inputs */
1864 const gchar *uri;
1865 GUriFlags flags;
1866 /* Outputs */
1867 const char *scheme;
1868 const gchar *path;
1869 int port;
1870} normalize_split_tests[] =
1871 {
1872 { "HTTP://foo", G_URI_FLAGS_ENCODED,
1873 "http", "", -1 },
1874 { "HTTP://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1875 "http", "/", 80 },
1876 { "http://foo:80/", G_URI_FLAGS_SCHEME_NORMALIZE,
1877 "http", "/", 80 },
1878 { "http://foo:8080/bar", G_URI_FLAGS_SCHEME_NORMALIZE,
1879 "http", "/bar", 8080 },
1880 { "ws://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1881 "ws", "/", 80 },
1882 { "https://foo", G_URI_FLAGS_ENCODED,
1883 "https", "", -1 },
1884 { "https://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1885 "https", "/", 443 },
1886 { "https://foo:443/", G_URI_FLAGS_SCHEME_NORMALIZE,
1887 "https", "/", 443 },
1888 { "wss://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1889 "wss", "/", 443 },
1890 { "ftp://foo", G_URI_FLAGS_ENCODED,
1891 "ftp", "", -1 },
1892 { "ftp://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1893 "ftp", "", 21 },
1894 { "ftp://foo:21", G_URI_FLAGS_SCHEME_NORMALIZE,
1895 "ftp", "", 21 },
1896 { "scheme://foo", G_URI_FLAGS_SCHEME_NORMALIZE,
1897 "scheme", "", -1 },
1898 };
1899
1900static const struct
1901{
1902 /* Inputs */
1903 GUriFlags flags;
1904 const gchar *scheme;
1905 const gchar *host;
1906 int port;
1907 const gchar *path;
1908 /* Outputs */
1909 const gchar *uri;
1910} normalize_join_tests[] =
1911 {
1912 { G_URI_FLAGS_NONE, "http", "foo", -1, "",
1913 "http://foo" },
1914 { G_URI_FLAGS_SCHEME_NORMALIZE, "http", "foo", -1, "",
1915 "http://foo/" },
1916 { G_URI_FLAGS_SCHEME_NORMALIZE, "http", "foo", 80, "",
1917 "http://foo/" },
1918 { G_URI_FLAGS_SCHEME_NORMALIZE, "http", "foo", 8080, "",
1919 "http://foo:8080/" },
1920 { G_URI_FLAGS_NONE, "http", "foo", 80, "",
1921 "http://foo:80" },
1922 { G_URI_FLAGS_SCHEME_NORMALIZE, "ws", "foo", 80, "",
1923 "ws://foo/" },
1924 { G_URI_FLAGS_NONE, "https", "foo", -1, "",
1925 "https://foo" },
1926 { G_URI_FLAGS_SCHEME_NORMALIZE, "https", "foo", -1, "",
1927 "https://foo/" },
1928 { G_URI_FLAGS_SCHEME_NORMALIZE, "https", "foo", 443, "",
1929 "https://foo/" },
1930 { G_URI_FLAGS_SCHEME_NORMALIZE, "https", "foo", 943, "",
1931 "https://foo:943/" },
1932 { G_URI_FLAGS_NONE, "https", "foo", 443, "",
1933 "https://foo:443" },
1934 { G_URI_FLAGS_SCHEME_NORMALIZE, "wss", "foo", 443, "",
1935 "wss://foo/" },
1936 { G_URI_FLAGS_NONE, "ftp", "foo", -1, "",
1937 "ftp://foo" },
1938 { G_URI_FLAGS_SCHEME_NORMALIZE, "ftp", "foo", -1, "",
1939 "ftp://foo" },
1940 { G_URI_FLAGS_SCHEME_NORMALIZE, "ftp", "foo", 21, "",
1941 "ftp://foo" },
1942 { G_URI_FLAGS_SCHEME_NORMALIZE, "ftp", "foo", 2020, "",
1943 "ftp://foo:2020" },
1944 { G_URI_FLAGS_NONE, "ftp", "foo", 21, "",
1945 "ftp://foo:21" },
1946 { G_URI_FLAGS_SCHEME_NORMALIZE, "scheme", "foo", 80, "",
1947 "scheme://foo:80" },
1948 };
1949
1950static void
1951test_uri_normalize (void)
1952{
1953 gsize i;
1954 int port;
1955 char *path;
1956 char *uri_string;
1957
1958 for (i = 0; i < G_N_ELEMENTS (normalize_parse_tests); ++i)
1959 {
1960 GUri *uri, *base = NULL;
1961
1962 if (normalize_parse_tests[i].base)
1963 base = g_uri_parse (uri_string: normalize_parse_tests[i].base, flags: normalize_parse_tests[i].flags, NULL);
1964
1965 uri = g_uri_parse_relative (base_uri: base,
1966 uri_ref: normalize_parse_tests[i].uri,
1967 flags: normalize_parse_tests[i].flags,
1968 NULL);
1969 uri_string = g_uri_to_string (uri);
1970
1971 g_assert_nonnull (uri);
1972 g_assert_cmpstr (g_uri_get_path (uri), ==, normalize_parse_tests[i].path);
1973 g_assert_cmpint (g_uri_get_port (uri), ==, normalize_parse_tests[i].port);
1974 g_assert_cmpstr (uri_string, ==, normalize_parse_tests[i].uri_string);
1975
1976 g_free (mem: uri_string);
1977 g_uri_unref (uri);
1978 if (base)
1979 g_uri_unref (uri: base);
1980 }
1981
1982 for (i = 0; i < G_N_ELEMENTS (normalize_split_tests); ++i)
1983 {
1984 char *scheme;
1985
1986 /* Testing a codepath where scheme is NULL but internally we still normalize it. */
1987 g_assert_true (g_uri_split (normalize_split_tests[i].uri, normalize_split_tests[i].flags,
1988 NULL, NULL, NULL, &port, &path, NULL, NULL, NULL));
1989 g_assert_cmpstr (path, ==, normalize_split_tests[i].path);
1990 g_assert_cmpint (port, ==, normalize_split_tests[i].port);
1991 g_free (mem: path);
1992
1993 g_assert_true (g_uri_split (normalize_split_tests[i].uri, normalize_split_tests[i].flags,
1994 &scheme, NULL, NULL, &port, &path, NULL, NULL, NULL));
1995 g_assert_cmpstr (scheme, ==, normalize_split_tests[i].scheme);
1996 g_assert_cmpstr (path, ==, normalize_split_tests[i].path);
1997 g_assert_cmpint (port, ==, normalize_split_tests[i].port);
1998 g_free (mem: scheme);
1999 g_free (mem: path);
2000 }
2001
2002 for (i = 0; i < G_N_ELEMENTS (normalize_join_tests); ++i)
2003 {
2004 uri_string = g_uri_join (flags: normalize_join_tests[i].flags, scheme: normalize_join_tests[i].scheme, NULL,
2005 host: normalize_join_tests[i].host, port: normalize_join_tests[i].port,
2006 path: normalize_join_tests[i].path, NULL, NULL);
2007 g_assert_cmpstr (uri_string, ==, normalize_join_tests[i].uri);
2008 g_free (mem: uri_string);
2009 }
2010}
2011
2012int
2013main (int argc,
2014 char *argv[])
2015{
2016 g_test_init (argc: &argc, argv: &argv, NULL);
2017
2018 g_test_add_func (testpath: "/uri/file-to-uri", test_func: run_file_to_uri_tests);
2019 g_test_add_func (testpath: "/uri/file-from-uri", test_func: run_file_from_uri_tests);
2020 g_test_add_func (testpath: "/uri/file-roundtrip", test_func: run_file_roundtrip_tests);
2021 g_test_add_func (testpath: "/uri/list", test_func: run_uri_list_tests);
2022 g_test_add_func (testpath: "/uri/unescape-string", test_func: test_uri_unescape_string);
2023 g_test_add_data_func (testpath: "/uri/unescape-bytes/nul-terminated", GINT_TO_POINTER (TRUE), test_func: test_uri_unescape_bytes);
2024 g_test_add_data_func (testpath: "/uri/unescape-bytes/length", GINT_TO_POINTER (FALSE), test_func: test_uri_unescape_bytes);
2025 g_test_add_func (testpath: "/uri/unescape-segment", test_func: test_uri_unescape_segment);
2026 g_test_add_func (testpath: "/uri/escape-string", test_func: test_uri_escape_string);
2027 g_test_add_func (testpath: "/uri/escape-bytes", test_func: test_uri_escape_bytes);
2028 g_test_add_func (testpath: "/uri/scheme", test_func: test_uri_scheme);
2029 g_test_add_func (testpath: "/uri/parsing/absolute", test_func: test_uri_parsing_absolute);
2030 g_test_add_func (testpath: "/uri/parsing/relative", test_func: test_uri_parsing_relative);
2031 g_test_add_func (testpath: "/uri/build", test_func: test_uri_build);
2032 g_test_add_func (testpath: "/uri/split", test_func: test_uri_split);
2033 g_test_add_func (testpath: "/uri/is_valid", test_func: test_uri_is_valid);
2034 g_test_add_func (testpath: "/uri/to-string", test_func: test_uri_to_string);
2035 g_test_add_func (testpath: "/uri/join", test_func: test_uri_join);
2036 g_test_add_func (testpath: "/uri/join-split-round-trip", test_func: test_uri_join_split_round_trip);
2037 g_test_add_func (testpath: "/uri/normalize", test_func: test_uri_normalize);
2038 g_test_add_data_func (testpath: "/uri/iter-params/nul-terminated", GINT_TO_POINTER (TRUE), test_func: test_uri_iter_params);
2039 g_test_add_data_func (testpath: "/uri/iter-params/length", GINT_TO_POINTER (FALSE), test_func: test_uri_iter_params);
2040 g_test_add_data_func (testpath: "/uri/parse-params/nul-terminated", GINT_TO_POINTER (TRUE), test_func: test_uri_parse_params);
2041 g_test_add_data_func (testpath: "/uri/parse-params/length", GINT_TO_POINTER (FALSE), test_func: test_uri_parse_params);
2042
2043 return g_test_run ();
2044}
2045

source code of gtk/subprojects/glib/glib/tests/uri.c