Blame


1 92e07b23 2022-12-25 op /*
2 92e07b23 2022-12-25 op * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
3 92e07b23 2022-12-25 op *
4 92e07b23 2022-12-25 op * Permission to use, copy, modify, and distribute this software for any
5 92e07b23 2022-12-25 op * purpose with or without fee is hereby granted, provided that the above
6 92e07b23 2022-12-25 op * copyright notice and this permission notice appear in all copies.
7 92e07b23 2022-12-25 op *
8 92e07b23 2022-12-25 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 92e07b23 2022-12-25 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 92e07b23 2022-12-25 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 92e07b23 2022-12-25 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 92e07b23 2022-12-25 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 92e07b23 2022-12-25 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 92e07b23 2022-12-25 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 92e07b23 2022-12-25 op */
16 92e07b23 2022-12-25 op
17 92e07b23 2022-12-25 op #include <err.h>
18 92e07b23 2022-12-25 op #include <errno.h>
19 9179d12e 2024-02-22 op #include <stdint.h>
20 92e07b23 2022-12-25 op #include <stdio.h>
21 92e07b23 2022-12-25 op #include <string.h>
22 92e07b23 2022-12-25 op
23 92e07b23 2022-12-25 op #include "iri.h"
24 92e07b23 2022-12-25 op
25 92e07b23 2022-12-25 op static int
26 5cc70f14 2022-12-26 op resolve(const char *base, const char *ref, const char *expected)
27 92e07b23 2022-12-25 op {
28 92e07b23 2022-12-25 op static struct iri i;
29 92e07b23 2022-12-25 op char buf[512];
30 92e07b23 2022-12-25 op
31 92e07b23 2022-12-25 op if (iri_parse(base, ref, &i) == -1) {
32 3f2ab305 2022-12-26 op fprintf(stderr, "FAIL resolve(\"%s\", \"%s\") %s\n", base, ref,
33 92e07b23 2022-12-25 op strerror(errno));
34 92e07b23 2022-12-25 op return (1);
35 92e07b23 2022-12-25 op }
36 92e07b23 2022-12-25 op
37 92e07b23 2022-12-25 op if (iri_unparse(&i, buf, sizeof(buf)) == -1) {
38 3f2ab305 2022-12-26 op fprintf(stderr, "FAIL resolve(\"%s\", \"%s\") %s\n", base, ref,
39 92e07b23 2022-12-25 op strerror(errno));
40 92e07b23 2022-12-25 op return (1);
41 92e07b23 2022-12-25 op }
42 92e07b23 2022-12-25 op
43 92e07b23 2022-12-25 op if (strcmp(buf, expected) != 0) {
44 3f2ab305 2022-12-26 op fprintf(stderr, "FAIL resolve(\"%s\", \"%s\")\n", base, ref);
45 92e07b23 2022-12-25 op fprintf(stderr, "got:\t%s\n", buf);
46 92e07b23 2022-12-25 op fprintf(stderr, "want:\t%s\n", expected);
47 92e07b23 2022-12-25 op return (1);
48 92e07b23 2022-12-25 op }
49 92e07b23 2022-12-25 op
50 3f2ab305 2022-12-26 op fprintf(stderr, "OK resolve(\"%s\", \"%s\") -> %s\n", base, ref,
51 3f2ab305 2022-12-26 op expected);
52 92e07b23 2022-12-25 op return (0);
53 92e07b23 2022-12-25 op }
54 92e07b23 2022-12-25 op
55 9987c6fb 2022-12-26 op static int
56 9987c6fb 2022-12-26 op setquery(const char *iri, const char *query, const char *expected)
57 9987c6fb 2022-12-26 op {
58 9987c6fb 2022-12-26 op static struct iri i;
59 9987c6fb 2022-12-26 op char buf[512];
60 9987c6fb 2022-12-26 op
61 9987c6fb 2022-12-26 op if (iri_parse(NULL, iri, &i) == -1) {
62 9987c6fb 2022-12-26 op fprintf(stderr, "FAIL can't parse <%s>: %s\n", iri,
63 9987c6fb 2022-12-26 op strerror(errno));
64 9987c6fb 2022-12-26 op return (1);
65 9987c6fb 2022-12-26 op }
66 9987c6fb 2022-12-26 op
67 9987c6fb 2022-12-26 op if (iri_setquery(&i, query) == -1) {
68 9987c6fb 2022-12-26 op fprintf(stderr, "FAIL setting query \"%s\": %s\n", query,
69 9987c6fb 2022-12-26 op strerror(errno));
70 9987c6fb 2022-12-26 op return (1);
71 9987c6fb 2022-12-26 op }
72 9987c6fb 2022-12-26 op
73 9987c6fb 2022-12-26 op if (iri_unparse(&i, buf, sizeof(buf)) == -1) {
74 9987c6fb 2022-12-26 op fprintf(stderr, "FAIL unparsing <%s> with query %s\n",
75 9987c6fb 2022-12-26 op iri, query);
76 9987c6fb 2022-12-26 op return (1);
77 9987c6fb 2022-12-26 op }
78 9987c6fb 2022-12-26 op
79 9987c6fb 2022-12-26 op if (strcmp(buf, expected) != 0) {
80 9987c6fb 2022-12-26 op fprintf(stderr, "FAIL setquery(\"%s\", \"%s\")\n", iri, query);
81 9987c6fb 2022-12-26 op fprintf(stderr, "got:\t%s\n", buf);
82 9987c6fb 2022-12-26 op fprintf(stderr, "want:\t%s\n", expected);
83 9987c6fb 2022-12-26 op return (1);
84 9987c6fb 2022-12-26 op }
85 9987c6fb 2022-12-26 op
86 9987c6fb 2022-12-26 op fprintf(stderr, "OK setquery(\"%s\", \"%s\") -> %s\n", iri, query,
87 9987c6fb 2022-12-26 op expected);
88 9987c6fb 2022-12-26 op return (0);
89 9987c6fb 2022-12-26 op }
90 9987c6fb 2022-12-26 op
91 0f578996 2024-02-22 op static int
92 0f578996 2024-02-22 op urlencode(const char *str, const char *exp)
93 0f578996 2024-02-22 op {
94 0f578996 2024-02-22 op char enc[512];
95 0f578996 2024-02-22 op char dec[512];
96 0f578996 2024-02-22 op
97 0f578996 2024-02-22 op if (iri_urlescape(str, enc, sizeof(enc)) == -1) {
98 0f578996 2024-02-22 op fprintf(stderr, "FAIL can't percent encode %s\n", str);
99 0f578996 2024-02-22 op return (1);
100 0f578996 2024-02-22 op }
101 0f578996 2024-02-22 op
102 0f578996 2024-02-22 op if (strcmp(enc, exp) != 0) {
103 0f578996 2024-02-22 op fprintf(stderr, "FAIL %%enc: expecting <%s>; got <%s>\n",
104 0f578996 2024-02-22 op exp, enc);
105 0f578996 2024-02-22 op return (1);
106 0f578996 2024-02-22 op }
107 0f578996 2024-02-22 op
108 0f578996 2024-02-22 op if (iri_urlunescape(enc, dec, sizeof(dec)) == -1) {
109 0f578996 2024-02-22 op fprintf(stderr, "FAIL can't %%decode %s\n", enc);
110 0f578996 2024-02-22 op return (1);
111 0f578996 2024-02-22 op }
112 0f578996 2024-02-22 op
113 0f578996 2024-02-22 op if (strcmp(str, dec) != 0) {
114 0f578996 2024-02-22 op fprintf(stderr,
115 0f578996 2024-02-22 op "FAIL urlencode/decode not identity: <%s> vs <%s>\n",
116 0f578996 2024-02-22 op str, dec);
117 0f578996 2024-02-22 op return (1);
118 0f578996 2024-02-22 op }
119 0f578996 2024-02-22 op
120 0f578996 2024-02-22 op if (strcmp(enc, exp) != 0) {
121 0f578996 2024-02-22 op fprintf(stderr, "FAIL %%enc: expecting <%s>; got <%s>\n",
122 0f578996 2024-02-22 op exp, enc);
123 0f578996 2024-02-22 op return (1);
124 0f578996 2024-02-22 op }
125 0f578996 2024-02-22 op
126 0f578996 2024-02-22 op fprintf(stderr, "OK urlencode(\"%s\") -> %s\n", str, enc);
127 0f578996 2024-02-22 op return (0);
128 0f578996 2024-02-22 op }
129 0f578996 2024-02-22 op
130 92e07b23 2022-12-25 op int
131 92e07b23 2022-12-25 op main(void)
132 92e07b23 2022-12-25 op {
133 9987c6fb 2022-12-26 op const char *base;
134 92e07b23 2022-12-25 op int ret = 0;
135 92e07b23 2022-12-25 op
136 9987c6fb 2022-12-26 op /* RFC 3986 tests */
137 9987c6fb 2022-12-26 op
138 9987c6fb 2022-12-26 op base = "http://a/b/c/d;p?q";
139 9987c6fb 2022-12-26 op
140 5cc70f14 2022-12-26 op ret |= resolve(base, "g:h", "g:h");
141 5cc70f14 2022-12-26 op ret |= resolve(base, "g", "http://a/b/c/g");
142 5cc70f14 2022-12-26 op ret |= resolve(base, "./g", "http://a/b/c/g");
143 5cc70f14 2022-12-26 op ret |= resolve(base, "g/", "http://a/b/c/g/");
144 5cc70f14 2022-12-26 op ret |= resolve(base, "/g", "http://a/g");
145 92e07b23 2022-12-25 op
146 92e07b23 2022-12-25 op /*
147 92e07b23 2022-12-25 op * the RFC says "http://g" but we always normalize an
148 92e07b23 2022-12-25 op * empty path to "/" if there is an authority.
149 92e07b23 2022-12-25 op */
150 5cc70f14 2022-12-26 op ret |= resolve(base, "//g", "http://g/");
151 92e07b23 2022-12-25 op
152 5cc70f14 2022-12-26 op ret |= resolve(base, "?y", "http://a/b/c/d;p?y");
153 5cc70f14 2022-12-26 op ret |= resolve(base, "g?y", "http://a/b/c/g?y");
154 5cc70f14 2022-12-26 op ret |= resolve(base, "#s", "http://a/b/c/d;p?q#s");
155 5cc70f14 2022-12-26 op ret |= resolve(base, "g#s", "http://a/b/c/g#s");
156 5cc70f14 2022-12-26 op ret |= resolve(base, "g?y#s", "http://a/b/c/g?y#s");
157 5cc70f14 2022-12-26 op ret |= resolve(base, ";x", "http://a/b/c/;x");
158 5cc70f14 2022-12-26 op ret |= resolve(base, "g;x", "http://a/b/c/g;x");
159 5cc70f14 2022-12-26 op ret |= resolve(base, "g;x?y#s", "http://a/b/c/g;x?y#s");
160 5cc70f14 2022-12-26 op ret |= resolve(base, "", "http://a/b/c/d;p?q");
161 5cc70f14 2022-12-26 op ret |= resolve(base, ".", "http://a/b/c/");
162 5cc70f14 2022-12-26 op ret |= resolve(base, "./", "http://a/b/c/");
163 5cc70f14 2022-12-26 op ret |= resolve(base, "..", "http://a/b/");
164 5cc70f14 2022-12-26 op ret |= resolve(base, "../", "http://a/b/");
165 5cc70f14 2022-12-26 op ret |= resolve(base, "../g", "http://a/b/g");
166 5cc70f14 2022-12-26 op ret |= resolve(base, "../..", "http://a/");
167 5cc70f14 2022-12-26 op ret |= resolve(base, "../../", "http://a/");
168 5cc70f14 2022-12-26 op ret |= resolve(base, "../../g", "http://a/g");
169 92e07b23 2022-12-25 op
170 5cc70f14 2022-12-26 op ret |= resolve(base, "../../../g", "http://a/g");
171 5cc70f14 2022-12-26 op ret |= resolve(base, "../../../../g", "http://a/g");
172 5cc70f14 2022-12-26 op ret |= resolve(base, "/./g", "http://a/g");
173 5cc70f14 2022-12-26 op ret |= resolve(base, "/../g", "http://a/g");
174 5cc70f14 2022-12-26 op ret |= resolve(base, "g.", "http://a/b/c/g.");
175 5cc70f14 2022-12-26 op ret |= resolve(base, ".g", "http://a/b/c/.g");
176 5cc70f14 2022-12-26 op ret |= resolve(base, "g..", "http://a/b/c/g..");
177 5cc70f14 2022-12-26 op ret |= resolve(base, "..g", "http://a/b/c/..g");
178 92e07b23 2022-12-25 op
179 5cc70f14 2022-12-26 op ret |= resolve(base, "./../g", "http://a/b/g");
180 5cc70f14 2022-12-26 op ret |= resolve(base, "./g/.", "http://a/b/c/g/");
181 5cc70f14 2022-12-26 op ret |= resolve(base, "g/./h", "http://a/b/c/g/h");
182 5cc70f14 2022-12-26 op ret |= resolve(base, "g/../h", "http://a/b/c/h");
183 5cc70f14 2022-12-26 op ret |= resolve(base, "g;x=1/./y", "http://a/b/c/g;x=1/y");
184 5cc70f14 2022-12-26 op ret |= resolve(base, "g;x=1/../y", "http://a/b/c/y");
185 92e07b23 2022-12-25 op
186 5cc70f14 2022-12-26 op ret |= resolve(base, "g?y/./x", "http://a/b/c/g?y/./x");
187 5cc70f14 2022-12-26 op ret |= resolve(base, "g?y/../x", "http://a/b/c/g?y/../x");
188 5cc70f14 2022-12-26 op ret |= resolve(base, "g#s/./x", "http://a/b/c/g#s/./x");
189 5cc70f14 2022-12-26 op ret |= resolve(base, "g#s/../x", "http://a/b/c/g#s/../x");
190 92e07b23 2022-12-25 op
191 5cc70f14 2022-12-26 op ret |= resolve(base, "http:g", "http:g");
192 92e07b23 2022-12-25 op
193 9987c6fb 2022-12-26 op /* extra tests */
194 9987c6fb 2022-12-26 op
195 e681c648 2022-12-26 op ret |= resolve(base, "gopher://b:70", "gopher://b:70/");
196 bbf98297 2024-01-16 op ret |= resolve(base, "gopher://b:70/1/foo", "gopher://b:70/1/foo");
197 9987c6fb 2022-12-26 op
198 208bc7e8 2024-01-16 op base = "gopher://b:70/1/bar/foo/quux";
199 208bc7e8 2024-01-16 op ret |= resolve(base, "/", "gopher://b:70/");
200 208bc7e8 2024-01-16 op ret |= resolve(base, "..", "gopher://b:70/1/bar/");
201 208bc7e8 2024-01-16 op
202 e681c648 2022-12-26 op base = "gemini://a/b/c";
203 9987c6fb 2022-12-26 op ret |= setquery(base, "hw", "gemini://a/b/c?hw");
204 9987c6fb 2022-12-26 op ret |= setquery(base, "h w", "gemini://a/b/c?h%20w");
205 9987c6fb 2022-12-26 op ret |= setquery(base, "100%", "gemini://a/b/c?100%25");
206 9987c6fb 2022-12-26 op ret |= setquery(base, "%20", "gemini://a/b/c?%2520");
207 9987c6fb 2022-12-26 op
208 e681c648 2022-12-26 op base = "gemini://a/?foo+bar";
209 e681c648 2022-12-26 op ret |= setquery(base, "foo", "gemini://a/?foo");
210 e681c648 2022-12-26 op ret |= setquery(base, "%20", "gemini://a/?%2520");
211 e681c648 2022-12-26 op ret |= setquery(base, "%20%20%20", "gemini://a/?%2520%2520%2520");
212 e681c648 2022-12-26 op
213 e2089110 2024-02-21 op ret |= resolve(base, "file:///tmp/foo", "file:///tmp/foo");
214 e2089110 2024-02-21 op ret |= resolve(base, "file:/tmp/foo", "file:///tmp/foo");
215 e2089110 2024-02-21 op
216 0f578996 2024-02-22 op ret |= urlencode("foobar", "foobar");
217 0f578996 2024-02-22 op ret |= urlencode("foo/bar", "foo/bar");
218 0f578996 2024-02-22 op ret |= urlencode("foo bar", "foo%20bar");
219 0f578996 2024-02-22 op ret |= urlencode("/Teloschistes flavicans",
220 0f578996 2024-02-22 op "/Teloschistes%20flavicans");
221 0f578996 2024-02-22 op
222 92e07b23 2022-12-25 op return (ret);
223 92e07b23 2022-12-25 op }