uri-tests.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. URI handling tests
  3. Copyright (C) 2001-2006, Joe Orton <[email protected]>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "config.h"
  17. #ifdef HAVE_STDLIB_H
  18. #include <stdlib.h>
  19. #endif
  20. #ifdef HAVE_STRING_H
  21. #include <string.h>
  22. #endif
  23. #include "ne_uri.h"
  24. #include "ne_alloc.h"
  25. #include "tests.h"
  26. static int simple(void)
  27. {
  28. ne_uri p = {0};
  29. ON(ne_uri_parse("http://www.webdav.org/foo", &p));
  30. ON(strcmp(p.host, "www.webdav.org"));
  31. ON(strcmp(p.path, "/foo"));
  32. ON(strcmp(p.scheme, "http"));
  33. ON(p.port);
  34. ON(p.userinfo != NULL);
  35. ne_uri_free(&p);
  36. return 0;
  37. }
  38. static int simple_ssl(void)
  39. {
  40. ne_uri p = {0};
  41. ON(ne_uri_parse("https://webdav.org/", &p));
  42. ON(strcmp(p.scheme, "https"));
  43. ON(p.port);
  44. ne_uri_free(&p);
  45. return OK;
  46. }
  47. static int no_path(void)
  48. {
  49. ne_uri p = {0};
  50. ON(ne_uri_parse("https://webdav.org", &p));
  51. ON(strcmp(p.path, "/"));
  52. ne_uri_free(&p);
  53. return OK;
  54. }
  55. static int escapes(void)
  56. {
  57. static const struct {
  58. const char *plain, *escaped;
  59. unsigned int flags;
  60. } paths[] = {
  61. { "/foo%", "/foo%25", 0 },
  62. { "/foo bar", "/foo%20bar", 0, },
  63. { "/foo_bar", "/foo_bar", 0 },
  64. { "/foobar", "/foobar", 0 },
  65. { "/a\xb9\xb2\xb3\xbc\xbd/", "/a%b9%b2%b3%bc%bd/", 0 },
  66. { "/foo%20\xb9\xb2\xb3\xbc\xbd/", "/foo%20%b9%b2%b3%bc%bd/", NE_PATH_NONURI },
  67. { "/foo bar/", "/foo%20bar/", NE_PATH_NONURI },
  68. { NULL, NULL}
  69. };
  70. size_t n;
  71. for (n = 0; paths[n].plain; n++) {
  72. char *esc;
  73. if (paths[n].flags)
  74. esc = ne_path_escapef(paths[n].plain, paths[n].flags);
  75. else
  76. esc = ne_path_escape(paths[n].plain);
  77. ONCMP(paths[n].escaped, esc, paths[n].plain, "escape");
  78. if (!paths[n].flags) {
  79. char *un = ne_path_unescape(esc);
  80. ONCMP(paths[n].plain, un, paths[n].plain, "unescape");
  81. ne_free(un);
  82. }
  83. ne_free(esc);
  84. }
  85. ONN("unescape accepted invalid URI",
  86. ne_path_unescape("/foo%zzbar") != NULL);
  87. ONN("unescape accepted invalid URI",
  88. ne_path_unescape("/foo%1zbar") != NULL);
  89. return OK;
  90. }
  91. static int parents(void)
  92. {
  93. static const struct {
  94. const char *path, *parent;
  95. } ps[] = {
  96. { "/a/b/c", "/a/b/" },
  97. { "/a/b/c/", "/a/b/" },
  98. { "/alpha/beta", "/alpha/" },
  99. { "/foo", "/" },
  100. { "norman", NULL },
  101. { "/", NULL },
  102. { "", NULL },
  103. { NULL, NULL }
  104. };
  105. int n;
  106. for (n = 0; ps[n].path != NULL; n++) {
  107. char *p = ne_path_parent(ps[n].path);
  108. if (ps[n].parent == NULL) {
  109. ONV(p != NULL, ("parent of `%s' was `%s' not NULL",
  110. ps[n].path, p));
  111. } else {
  112. ONV(p == NULL, ("parent of `%s' was NULL", ps[n].path));
  113. ONV(strcmp(p, ps[n].parent),
  114. ("parent of `%s' was `%s' not `%s'",
  115. ps[n].path, p, ps[n].parent));
  116. ne_free(p);
  117. }
  118. }
  119. return OK;
  120. }
  121. static int compares(void)
  122. {
  123. const char *alpha = "/alpha";
  124. ON(ne_path_compare("/a", "/a/") != 0);
  125. ON(ne_path_compare("/a/", "/a") != 0);
  126. ON(ne_path_compare("/ab", "/a/") == 0);
  127. ON(ne_path_compare("/a/", "/ab") == 0);
  128. ON(ne_path_compare("/a/", "/a/") != 0);
  129. ON(ne_path_compare("/alpha/", "/beta/") == 0);
  130. ON(ne_path_compare("/alpha", "/b") == 0);
  131. ON(ne_path_compare("/alpha/", "/alphash") == 0);
  132. ON(ne_path_compare("/fish/", "/food") == 0);
  133. ON(ne_path_compare(alpha, alpha) != 0);
  134. ON(ne_path_compare("/a/b/c/d", "/a/b/c/") == 0);
  135. return OK;
  136. }
  137. static int cmp(void)
  138. {
  139. static const struct {
  140. const char *left, *right;
  141. } eq[] = {
  142. { "http://example.com/alpha", "http://example.com/alpha" },
  143. { "//example.com/alpha", "//example.com/alpha" },
  144. { "http://example.com/alpha#foo", "http://example.com/alpha#foo" },
  145. { "http://example.com/alpha?bar", "http://example.com/alpha?bar" },
  146. { "http://[email protected]/alpha", "http://[email protected]/alpha" },
  147. { "HTTP://example.com/alpha", "http://example.com/alpha" },
  148. { "http://example.com/", "http://example.com" },
  149. { "http://Example.Com/", "http://example.com" },
  150. { NULL, NULL}
  151. }, diff[] = {
  152. { "http://example.com/alpha", "http://example.com/beta" },
  153. { "http://example.com/alpha", "https://example.com/alpha" },
  154. { "http://example.com/alpha", "http://www.example.com/alpha" },
  155. { "http://example.com:443/alpha", "http://example.com:8080/alpha" },
  156. { "http://example.com/alpha", "http://[email protected]/alpha" },
  157. { "http://[email protected]/alpha", "http://[email protected]/alpha" },
  158. { "http://example.com/alpha", "http://example.com/alpha?fish" },
  159. { "http://example.com/alpha?fish", "http://example.com/alpha?food" },
  160. { "http://example.com/alpha", "http://example.com/alpha#foo" },
  161. { "http://example.com/alpha#bar", "http://example.com/alpha#foo" },
  162. { "http://example.com/alpha", "//example.com/alpha" },
  163. { "http://example.com/alpha", "///alpha" },
  164. { NULL, NULL}
  165. };
  166. size_t n;
  167. for (n = 0; eq[n].left; n++) {
  168. ne_uri alpha, beta;
  169. int r1, r2;
  170. ONV(ne_uri_parse(eq[n].left, &alpha),
  171. ("could not parse left URI '%s'", eq[n].left));
  172. ONV(ne_uri_parse(eq[n].right, &beta),
  173. ("could not parse right URI '%s'", eq[n].right));
  174. r1 = ne_uri_cmp(&alpha, &beta);
  175. r2 = ne_uri_cmp(&beta, &alpha);
  176. ONV(r1 != 0,
  177. ("cmp('%s', '%s') = %d not zero",
  178. eq[n].left, eq[n].right, r1));
  179. ONV(r2 != 0,
  180. ("cmp('%s', '%s') = %d not zero",
  181. eq[n].right, eq[n].left, r2));
  182. ne_uri_free(&alpha);
  183. ne_uri_free(&beta);
  184. }
  185. for (n = 0; diff[n].left; n++) {
  186. ne_uri alpha, beta;
  187. int r1, r2;
  188. ONV(ne_uri_parse(diff[n].left, &alpha),
  189. ("could not parse left URI '%s'", diff[n].left));
  190. ONV(ne_uri_parse(diff[n].right, &beta),
  191. ("could not parse right URI '%s'", diff[n].right));
  192. r1 = ne_uri_cmp(&alpha, &beta);
  193. r2 = ne_uri_cmp(&beta, &alpha);
  194. ONV(r1 == 0,
  195. ("'%s' and '%s' did not compare as different",
  196. diff[n].left, diff[n].right));
  197. ONV(((r1 > 0) != (r2 < 0) || (r1 < 0) != (r2 > 0)),
  198. ("'%s' and '%s' did not compare reflexively (%d vs %d)",
  199. diff[n].left, diff[n].right, r1, r2));
  200. ne_uri_free(&alpha);
  201. ne_uri_free(&beta);
  202. }
  203. return OK;
  204. }
  205. static int children(void)
  206. {
  207. ON(ne_path_childof("/a", "/a/b") == 0);
  208. ON(ne_path_childof("/a/", "/a/b") == 0);
  209. ON(ne_path_childof("/aa/b/c", "/a/b/c/d/e") != 0);
  210. ON(ne_path_childof("////", "/a") != 0);
  211. return OK;
  212. }
  213. static int slash(void)
  214. {
  215. ON(ne_path_has_trailing_slash("/a/") == 0);
  216. ON(ne_path_has_trailing_slash("/a") != 0);
  217. {
  218. /* check the uri == "" case. */
  219. char *foo = "/";
  220. ON(ne_path_has_trailing_slash(&foo[1]));
  221. }
  222. return OK;
  223. }
  224. static int default_port(void)
  225. {
  226. ONN("default http: port incorrect", ne_uri_defaultport("http") != 80);
  227. ONN("default https: port incorrect", ne_uri_defaultport("https") != 443);
  228. ONN("unspecified scheme: port incorrect", ne_uri_defaultport("ldap") != 0);
  229. return OK;
  230. }
  231. static int parse(void)
  232. {
  233. static const struct test_uri {
  234. const char *uri, *scheme, *host;
  235. unsigned int port;
  236. const char *path, *userinfo, *query, *fragment;
  237. } uritests[] = {
  238. { "http://webdav.org/norman", "http", "webdav.org", 0, "/norman", NULL, NULL, NULL },
  239. { "http://webdav.org:/norman", "http", "webdav.org", 0, "/norman", NULL, NULL, NULL },
  240. { "https://webdav.org/foo", "https", "webdav.org", 0, "/foo", NULL, NULL, NULL },
  241. { "http://webdav.org:8080/bar", "http", "webdav.org", 8080, "/bar", NULL, NULL, NULL },
  242. { "http://a/b", "http", "a", 0, "/b", NULL, NULL, NULL },
  243. { "http://webdav.org/bar:fish", "http", "webdav.org", 0, "/bar:fish", NULL, NULL, NULL },
  244. { "http://webdav.org", "http", "webdav.org", 0, "/", NULL, NULL, NULL },
  245. { "http://webdav.org/fish@food", "http", "webdav.org", 0, "/fish@food", NULL, NULL, NULL },
  246. /* query/fragments */
  247. { "http://foo/bar?alpha", "http", "foo", 0, "/bar", NULL, "alpha", NULL },
  248. { "http://foo/bar?alpha#beta", "http", "foo", 0, "/bar", NULL, "alpha", "beta" },
  249. { "http://foo/bar#alpha?beta", "http", "foo", 0, "/bar", NULL, NULL, "alpha?beta" },
  250. { "http://foo/bar#beta", "http", "foo", 0, "/bar", NULL, NULL, "beta" },
  251. { "http://foo/bar?#beta", "http", "foo", 0, "/bar", NULL, "", "beta" },
  252. { "http://foo/bar?alpha?beta", "http", "foo", 0, "/bar", NULL, "alpha?beta", NULL },
  253. { "http://foo?alpha", "http", "foo", 0, "/", NULL, "alpha", NULL },
  254. { "http://foo#beta", "http", "foo", 0, "/", NULL, NULL, "beta" },
  255. /* Examples from RFC3986§1.1.2: */
  256. { "ftp://ftp.is.co.za/rfc/rfc1808.txt", "ftp", "ftp.is.co.za", 0, "/rfc/rfc1808.txt", NULL, NULL, NULL },
  257. { "http://www.ietf.org/rfc/rfc2396.txt", "http", "www.ietf.org", 0, "/rfc/rfc2396.txt", NULL, NULL, NULL },
  258. { "ldap://[2001:db8::7]/c=GB?objectClass?one", "ldap", "[2001:db8::7]", 0, "/c=GB", NULL, "objectClass?one", NULL },
  259. { "mailto:[email protected]", "mailto", NULL, 0, "[email protected]", NULL, NULL, NULL },
  260. { "news:comp.infosystems.www.servers.unix", "news", NULL, 0, "comp.infosystems.www.servers.unix", NULL, NULL, NULL },
  261. { "tel:+1-816-555-1212", "tel", NULL, 0, "+1-816-555-1212", NULL, NULL, NULL },
  262. { "telnet://192.0.2.16:80/", "telnet", "192.0.2.16", 80, "/", NULL, NULL, NULL },
  263. { "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "urn", NULL, 0,
  264. "oasis:names:specification:docbook:dtd:xml:4.1.2", NULL},
  265. /* userinfo */
  266. { "ftp://jim:[email protected]", "ftp", "jim.com", 0, "/", "jim:bob", NULL, NULL },
  267. { "ldap://fred:[email protected]/foobar", "ldap", "fish.com", 0,
  268. "/foobar", "fred:bloggs", NULL, NULL },
  269. /* IPv6 literals: */
  270. { "http://[::1]/foo", "http", "[::1]", 0, "/foo", NULL, NULL, NULL },
  271. { "http://[a:a:a:a::0]/foo", "http", "[a:a:a:a::0]", 0, "/foo", NULL, NULL, NULL },
  272. { "http://[::1]:8080/bar", "http", "[::1]", 8080, "/bar", NULL, NULL, NULL },
  273. { "ftp://[feed::cafe]:555", "ftp", "[feed::cafe]", 555, "/", NULL, NULL, NULL },
  274. /* Test RFC 6874 syntax, an extension of RFC 3987. */
  275. { "http://[fe80::cafe%25eth0]:555", "http", "[fe80::cafe%25eth0]", 555, "/", NULL, NULL, NULL },
  276. { "http://[fe80::cafe%251]:555", "http", "[fe80::cafe%251]", 555, "/", NULL, NULL, NULL },
  277. { "DAV:", "DAV", NULL, 0, "", NULL, NULL, NULL },
  278. /* Some odd cases: heir-part and relative-ref will both match
  279. * with a zero-length expansion of "authority" (since *
  280. * reg-name can be zero-length); so a triple-slash URI-ref
  281. * will be matched as "//" followed by a zero-length authority
  282. * followed by a path of "/". */
  283. { "foo:///", "foo", "", 0, "/", NULL, NULL, NULL },
  284. { "///", NULL, "", 0, "/", NULL, NULL, NULL },
  285. /* port grammar is "*DIGIT" so may be empty: */
  286. { "ftp://[feed::cafe]:", "ftp", "[feed::cafe]", 0, "/", NULL, NULL, NULL },
  287. { "ftp://[feed::cafe]:/", "ftp", "[feed::cafe]", 0, "/", NULL, NULL, NULL },
  288. { "http://foo:/", "http", "foo", 0, "/", NULL, NULL, NULL },
  289. /* URI-references: */
  290. { "//foo.com/bar", NULL, "foo.com", 0, "/bar", NULL, NULL, NULL },
  291. { "//foo.com", NULL, "foo.com", 0, "/", NULL, NULL, NULL },
  292. { "//[::1]/foo", NULL, "[::1]", 0, "/foo", NULL, NULL, NULL },
  293. { "/bar", NULL, NULL, 0, "/bar", NULL, NULL, NULL }, /* path-absolute */
  294. { "foo/bar", NULL, NULL, 0, "foo/bar", NULL, NULL, NULL }, /* path-noscheme */
  295. { "", NULL, NULL, 0, "", NULL, NULL, NULL }, /* path-empty */
  296. /* CVE-2007-0157: buffer under-read in 0.26.[012]. */
  297. { "http://webdav.org\xFF", "http", "webdav.org\xFF", 0, "/", NULL, NULL, NULL },
  298. { NULL }
  299. };
  300. int n;
  301. for (n = 0; uritests[n].uri != NULL; n++) {
  302. ne_uri res;
  303. const struct test_uri *e = &uritests[n];
  304. ONV(ne_uri_parse(e->uri, &res) != 0,
  305. ("'%s': parse failed", e->uri));
  306. ONV(res.port != e->port,
  307. ("'%s': parsed port was %d not %d", e->uri, res.port, e->port));
  308. ONCMP(e->scheme, res.scheme, e->uri, "scheme");
  309. ONCMP(e->host, res.host, e->uri, "host");
  310. ONV(strcmp(res.path, e->path),
  311. ("'%s': parsed path was '%s' not '%s'", e->uri, res.path, e->path));
  312. ONCMP(e->userinfo, res.userinfo, e->uri, "userinfo");
  313. ONCMP(e->query, res.query, e->uri, "query");
  314. ONCMP(e->fragment, res.fragment, e->uri, "fragment");
  315. ne_uri_free(&res);
  316. }
  317. return OK;
  318. }
  319. static int failparse(void)
  320. {
  321. static const char *uris[] = {
  322. "http://[::1/",
  323. "http://[::1]f:80/",
  324. "http://[::1]]:80/",
  325. "http://foo/bar asda",
  326. "http://fish/[foo]/bar",
  327. "http://foo:80bar",
  328. "http://foo:80:80/bar",
  329. "http://foo:8000000000000000000000000000000000000000000000000/bar",
  330. "http://foo:65536/bar",
  331. NULL
  332. };
  333. int n;
  334. for (n = 0; uris[n] != NULL; n++) {
  335. ne_uri p;
  336. ONV(ne_uri_parse(uris[n], &p) == 0,
  337. ("`%s' did not fail to parse", uris[n]));
  338. ne_uri_free(&p);
  339. }
  340. return 0;
  341. }
  342. static int unparse(void)
  343. {
  344. const char *uris[] = {
  345. "http://foo.com/bar",
  346. "https://bar.com/foo/wishbone",
  347. "http://www.random.com:8000/",
  348. "http://[::1]:8080/",
  349. "ftp://ftp.foo.bar/abc/def",
  350. "ftp://[email protected]/abc/def",
  351. "http://a/b?c#d",
  352. "http://a/b?c",
  353. "http://a/b#d",
  354. "mailto:[email protected]",
  355. "//foo.com/bar",
  356. "//foo.com:8080/bar",
  357. NULL
  358. };
  359. int n;
  360. for (n = 0; uris[n] != NULL; n++) {
  361. ne_uri parsed;
  362. char *unp;
  363. ONV(ne_uri_parse(uris[n], &parsed),
  364. ("failed to parse %s", uris[n]));
  365. if (parsed.port == 0 && parsed.scheme)
  366. parsed.port = ne_uri_defaultport(parsed.scheme);
  367. unp = ne_uri_unparse(&parsed);
  368. ONV(strcmp(unp, uris[n]),
  369. ("unparse got %s from %s", unp, uris[n]));
  370. ne_uri_free(&parsed);
  371. ne_free(unp);
  372. }
  373. return OK;
  374. }
  375. #define BASE "http://a/b/c/d;p?q"
  376. static int resolve(void)
  377. {
  378. static const struct {
  379. const char *base, *relative, *expected;
  380. } ts[] = {
  381. /* Examples from RFC3986§5.4: */
  382. { BASE, "g:h", "g:h" },
  383. { BASE, "g", "http://a/b/c/g" },
  384. { BASE, "./g", "http://a/b/c/g" },
  385. { BASE, "g/", "http://a/b/c/g/" },
  386. { BASE, "/g", "http://a/g" },
  387. { BASE, "//g", "http://g/" }, /* NOTE: modified to mandate non-empty path */
  388. { BASE, "?y", "http://a/b/c/d;p?y" },
  389. { BASE, "g?y", "http://a/b/c/g?y" },
  390. { BASE, "#s", "http://a/b/c/d;p?q#s" },
  391. { BASE, "g#s", "http://a/b/c/g#s" },
  392. { BASE, "g?y#s", "http://a/b/c/g?y#s" },
  393. { BASE, ";x", "http://a/b/c/;x" },
  394. { BASE, "g;x", "http://a/b/c/g;x" },
  395. { BASE, "g;x?y#s", "http://a/b/c/g;x?y#s" },
  396. { BASE, "", "http://a/b/c/d;p?q" },
  397. { BASE, ".", "http://a/b/c/" },
  398. { BASE, "./", "http://a/b/c/" },
  399. { BASE, "..", "http://a/b/" },
  400. { BASE, "../", "http://a/b/" },
  401. { BASE, "../g", "http://a/b/g" },
  402. { BASE, "../..", "http://a/" },
  403. { BASE, "../../", "http://a/" },
  404. { BASE, "../../g", "http://a/g" },
  405. { BASE, "../../../g", "http://a/g" },
  406. { BASE, "../../../../g", "http://a/g" },
  407. { BASE, "/./g", "http://a/g" },
  408. { BASE, "/../g", "http://a/g" },
  409. { BASE, "g.", "http://a/b/c/g." },
  410. { BASE, ".g", "http://a/b/c/.g" },
  411. { BASE, "g..", "http://a/b/c/g.." },
  412. { BASE, "..g", "http://a/b/c/..g" },
  413. { BASE, "./../g", "http://a/b/g" },
  414. { BASE, "./g/.", "http://a/b/c/g/" },
  415. { BASE, "g/./h", "http://a/b/c/g/h" },
  416. { BASE, "g/../h", "http://a/b/c/h" },
  417. { BASE, "g;x=1/./y", "http://a/b/c/g;x=1/y" },
  418. { BASE, "g;x=1/../y", "http://a/b/c/y" },
  419. { BASE, "g?y/./x", "http://a/b/c/g?y/./x" },
  420. { BASE, "g?y/../x", "http://a/b/c/g?y/../x" },
  421. { BASE, "g#s/./x", "http://a/b/c/g#s/./x" },
  422. { BASE, "g#s/../x", "http://a/b/c/g#s/../x" },
  423. { BASE, "http:g", "http:g" },
  424. /* Additional examples: */
  425. { BASE, ".", "http://a/b/c/" },
  426. { "http://foo.com/alpha/beta", "../gamma", "http://foo.com/gamma" },
  427. { "http://foo.com/alpha//beta", "../gamma", "http://foo.com/alpha/gamma" },
  428. { "http://foo.com", "../gamma", "http://foo.com/gamma" },
  429. { "", "zzz:.", "zzz:" },
  430. { "", "zzz:./foo", "zzz:foo" },
  431. { "", "zzz:../foo", "zzz:foo" },
  432. { "", "zzz:/./foo", "zzz:/foo" },
  433. { "", "zzz:/.", "zzz:/" },
  434. { "", "zzz:/../", "zzz:/" },
  435. { "", "zzz:.", "zzz:" },
  436. { "", "zzz:..", "zzz:" },
  437. { "", "zzz://foo@bar/", "zzz://foo@bar/" },
  438. { "", "zzz://foo/?bar", "zzz://foo/?bar" },
  439. { "zzz://foo/?bar", "//baz/?jam", "zzz://baz/?jam" },
  440. { "zzz://foo/baz?biz", "", "zzz://foo/baz?biz" },
  441. { "zzz://foo/baz", "", "zzz://foo/baz" },
  442. { "//foo/baz", "", "//foo/baz" },
  443. { NULL, NULL, NULL }
  444. };
  445. size_t n;
  446. for (n = 0; ts[n].base; n++) {
  447. ne_uri base, relative, resolved;
  448. char *actual;
  449. ONV(ne_uri_parse(ts[n].base, &base),
  450. ("could not parse base URI '%s'", ts[n].base));
  451. ONV(ne_uri_parse(ts[n].relative, &relative),
  452. ("could not parse input URI '%s'", ts[n].relative));
  453. ONN("bad pointer was returned",
  454. ne_uri_resolve(&base, &relative, &resolved) != &resolved);
  455. ONN("NULL path after resolve", resolved.path == NULL);
  456. actual = ne_uri_unparse(&resolved);
  457. ONCMP(ts[n].expected, actual, ts[n].relative, "output mismatch");
  458. ne_uri_free(&relative);
  459. ne_uri_free(&resolved);
  460. ne_uri_free(&base);
  461. ne_free(actual);
  462. }
  463. return OK;
  464. }
  465. static int copy(void)
  466. {
  467. static const char *ts[] = {
  468. "http://[email protected]:8080/bar?baz#bee",
  469. "",
  470. NULL,
  471. };
  472. size_t n;
  473. for (n = 0; ts[n]; n++) {
  474. ne_uri parsed, parsed2;
  475. char *actual;
  476. ONV(ne_uri_parse(ts[n], &parsed), ("could not parse URI '%s'", ts[n]));
  477. ONN("ne_uri_copy returned wrong pointer",
  478. ne_uri_copy(&parsed2, &parsed) != &parsed2);
  479. actual = ne_uri_unparse(&parsed2);
  480. ONCMP(ts[n], actual, "copied URI", "unparsed URI");
  481. ne_uri_free(&parsed2);
  482. ne_uri_free(&parsed);
  483. ne_free(actual);
  484. }
  485. return OK;
  486. }
  487. ne_test tests[] = {
  488. T(simple),
  489. T(simple_ssl),
  490. T(no_path),
  491. T(escapes),
  492. T(parents),
  493. T(compares),
  494. T(cmp),
  495. T(children),
  496. T(slash),
  497. T(default_port),
  498. T(parse),
  499. T(failparse),
  500. T(unparse),
  501. T(resolve),
  502. T(copy),
  503. T(NULL)
  504. };