Blame


1 5546fdd5 2022-12-23 op /*
2 5546fdd5 2022-12-23 op * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
3 5546fdd5 2022-12-23 op *
4 5546fdd5 2022-12-23 op * Permission to use, copy, modify, and distribute this software for any
5 5546fdd5 2022-12-23 op * purpose with or without fee is hereby granted, provided that the above
6 5546fdd5 2022-12-23 op * copyright notice and this permission notice appear in all copies.
7 5546fdd5 2022-12-23 op *
8 5546fdd5 2022-12-23 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 5546fdd5 2022-12-23 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 5546fdd5 2022-12-23 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 5546fdd5 2022-12-23 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 5546fdd5 2022-12-23 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 5546fdd5 2022-12-23 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 5546fdd5 2022-12-23 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 5546fdd5 2022-12-23 op */
16 5546fdd5 2022-12-23 op
17 5546fdd5 2022-12-23 op #include <ctype.h>
18 871b5bb7 2022-12-24 op #include <errno.h>
19 871b5bb7 2022-12-24 op #include <stddef.h>
20 5546fdd5 2022-12-23 op #include <stdint.h>
21 5546fdd5 2022-12-23 op #include <stdlib.h>
22 5546fdd5 2022-12-23 op #include <string.h>
23 5546fdd5 2022-12-23 op
24 5546fdd5 2022-12-23 op #include "iri.h"
25 5546fdd5 2022-12-23 op
26 5546fdd5 2022-12-23 op /* TODO: URI -> IRI. accept IRI but emit always URI */
27 5546fdd5 2022-12-23 op
28 5546fdd5 2022-12-23 op static inline int
29 5546fdd5 2022-12-23 op cpstr(const char *start, const char *till, char *buf, size_t len)
30 5546fdd5 2022-12-23 op {
31 5546fdd5 2022-12-23 op size_t slen = till - start;
32 5546fdd5 2022-12-23 op
33 5546fdd5 2022-12-23 op if (slen + 1 >= len)
34 5546fdd5 2022-12-23 op return (-1);
35 5546fdd5 2022-12-23 op memcpy(buf, start, slen);
36 5546fdd5 2022-12-23 op buf[slen] = '\0';
37 5546fdd5 2022-12-23 op return (0);
38 5546fdd5 2022-12-23 op }
39 5546fdd5 2022-12-23 op
40 5546fdd5 2022-12-23 op static inline int
41 5546fdd5 2022-12-23 op unreserved(int c)
42 5546fdd5 2022-12-23 op {
43 5546fdd5 2022-12-23 op return (isalnum((unsigned char)c) ||
44 5546fdd5 2022-12-23 op c == '-' ||
45 5546fdd5 2022-12-23 op c == '.' ||
46 5546fdd5 2022-12-23 op c == '_' ||
47 5546fdd5 2022-12-23 op c == '~');
48 5546fdd5 2022-12-23 op }
49 5546fdd5 2022-12-23 op
50 5546fdd5 2022-12-23 op static inline int
51 5546fdd5 2022-12-23 op pctenc(const char *s)
52 5546fdd5 2022-12-23 op {
53 5546fdd5 2022-12-23 op const char *t = s;
54 5546fdd5 2022-12-23 op
55 5546fdd5 2022-12-23 op return (t[0] == '%' &&
56 5546fdd5 2022-12-23 op isxdigit((unsigned char)t[1]) &&
57 5546fdd5 2022-12-23 op isxdigit((unsigned char)t[2]));
58 5546fdd5 2022-12-23 op }
59 5546fdd5 2022-12-23 op
60 5546fdd5 2022-12-23 op static inline int
61 5546fdd5 2022-12-23 op sub_delims(int c)
62 5546fdd5 2022-12-23 op {
63 5546fdd5 2022-12-23 op return (c == '!' || c == '$' || c == '&' || c == '\'' ||
64 5546fdd5 2022-12-23 op c == '(' || c == ')' || c == '*' || c == '+' || c == ',' ||
65 5546fdd5 2022-12-23 op c == ';' || c == '=');
66 5546fdd5 2022-12-23 op }
67 5546fdd5 2022-12-23 op
68 5546fdd5 2022-12-23 op static inline const char *
69 5546fdd5 2022-12-23 op advance_pchar(const char *s)
70 5546fdd5 2022-12-23 op {
71 5546fdd5 2022-12-23 op if (unreserved(*s) || sub_delims(*s) || *s == ':' || *s == '@')
72 5546fdd5 2022-12-23 op return (s + 1);
73 5546fdd5 2022-12-23 op if (pctenc(s))
74 5546fdd5 2022-12-23 op return (s + 3);
75 5546fdd5 2022-12-23 op return (NULL);
76 5546fdd5 2022-12-23 op }
77 5546fdd5 2022-12-23 op
78 5546fdd5 2022-12-23 op static inline const char *
79 5546fdd5 2022-12-23 op advance_segment(const char *s)
80 5546fdd5 2022-12-23 op {
81 5546fdd5 2022-12-23 op const char *t = s;
82 5546fdd5 2022-12-23 op
83 5546fdd5 2022-12-23 op while ((t = advance_pchar(s)) != NULL)
84 5546fdd5 2022-12-23 op s = t;
85 5546fdd5 2022-12-23 op return (s);
86 5546fdd5 2022-12-23 op }
87 5546fdd5 2022-12-23 op
88 5546fdd5 2022-12-23 op static inline const char *
89 5546fdd5 2022-12-23 op advance_segment_nz(const char *s)
90 5546fdd5 2022-12-23 op {
91 5546fdd5 2022-12-23 op const char *t;
92 5546fdd5 2022-12-23 op
93 5546fdd5 2022-12-23 op if ((t = advance_pchar(s)) == NULL)
94 5546fdd5 2022-12-23 op return (NULL);
95 5546fdd5 2022-12-23 op return (advance_segment(t));
96 5546fdd5 2022-12-23 op }
97 5546fdd5 2022-12-23 op
98 5546fdd5 2022-12-23 op static inline const char *
99 5546fdd5 2022-12-23 op advance_segment_nz_nc(const char *s)
100 5546fdd5 2022-12-23 op {
101 5546fdd5 2022-12-23 op const char *t = s;
102 5546fdd5 2022-12-23 op
103 5546fdd5 2022-12-23 op for (;;) {
104 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t) || *t == '@')
105 5546fdd5 2022-12-23 op t++;
106 5546fdd5 2022-12-23 op else if (pctenc(t))
107 5546fdd5 2022-12-23 op t += 3;
108 5546fdd5 2022-12-23 op else
109 5546fdd5 2022-12-23 op break;
110 5546fdd5 2022-12-23 op }
111 5546fdd5 2022-12-23 op
112 5546fdd5 2022-12-23 op return (t != s ? t : NULL);
113 5546fdd5 2022-12-23 op }
114 5546fdd5 2022-12-23 op
115 5546fdd5 2022-12-23 op static const char *
116 5546fdd5 2022-12-23 op parse_scheme(const char *s, struct iri *iri)
117 5546fdd5 2022-12-23 op {
118 5546fdd5 2022-12-23 op const char *t = s;
119 5546fdd5 2022-12-23 op
120 5546fdd5 2022-12-23 op if (!isalpha((unsigned char)*t))
121 5546fdd5 2022-12-23 op return (NULL);
122 5546fdd5 2022-12-23 op
123 5546fdd5 2022-12-23 op while (isalnum((unsigned char)*t) ||
124 5546fdd5 2022-12-23 op *t == '+' ||
125 5546fdd5 2022-12-23 op *t == '-' ||
126 5546fdd5 2022-12-23 op *t == '.')
127 5546fdd5 2022-12-23 op t++;
128 5546fdd5 2022-12-23 op
129 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_scheme, sizeof(iri->iri_scheme)) == -1)
130 5546fdd5 2022-12-23 op return (NULL);
131 5546fdd5 2022-12-23 op
132 5546fdd5 2022-12-23 op iri->iri_flags |= IH_SCHEME;
133 5546fdd5 2022-12-23 op return (t);
134 5546fdd5 2022-12-23 op }
135 5546fdd5 2022-12-23 op
136 5546fdd5 2022-12-23 op /* userinfo is always optional */
137 5546fdd5 2022-12-23 op static const char *
138 5546fdd5 2022-12-23 op parse_uinfo(const char *s, struct iri *iri)
139 5546fdd5 2022-12-23 op {
140 5546fdd5 2022-12-23 op const char *t = s;
141 5546fdd5 2022-12-23 op
142 5546fdd5 2022-12-23 op for (;;) {
143 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t) || *t == ':')
144 5546fdd5 2022-12-23 op t++;
145 5546fdd5 2022-12-23 op else if (pctenc(t))
146 5546fdd5 2022-12-23 op t += 3;
147 5546fdd5 2022-12-23 op else
148 5546fdd5 2022-12-23 op break;
149 5546fdd5 2022-12-23 op }
150 5546fdd5 2022-12-23 op
151 5546fdd5 2022-12-23 op if (*t != '@')
152 5546fdd5 2022-12-23 op return (s);
153 5546fdd5 2022-12-23 op
154 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_uinfo, sizeof(iri->iri_uinfo)) == -1)
155 5546fdd5 2022-12-23 op return (NULL);
156 5546fdd5 2022-12-23 op iri->iri_flags |= IH_UINFO;
157 5546fdd5 2022-12-23 op return (t + 1);
158 5546fdd5 2022-12-23 op }
159 5546fdd5 2022-12-23 op
160 5546fdd5 2022-12-23 op static const char *
161 5546fdd5 2022-12-23 op parse_host(const char *s, struct iri *iri)
162 5546fdd5 2022-12-23 op {
163 5546fdd5 2022-12-23 op const char *t = s;
164 5546fdd5 2022-12-23 op
165 5546fdd5 2022-12-23 op /*
166 5546fdd5 2022-12-23 op * cheating a bit by relaxing and merging the rule for
167 5546fdd5 2022-12-23 op * IPv6address and IPvFuture and by merging IPv4address and
168 5546fdd5 2022-12-23 op * reg-name.
169 5546fdd5 2022-12-23 op */
170 5546fdd5 2022-12-23 op
171 5546fdd5 2022-12-23 op if (*t == '[') {
172 5546fdd5 2022-12-23 op while (*t && *t != ']')
173 5546fdd5 2022-12-23 op ++t;
174 5546fdd5 2022-12-23 op if (*t == '\0')
175 5546fdd5 2022-12-23 op return (NULL);
176 5546fdd5 2022-12-23 op t++;
177 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_host, sizeof(iri->iri_host)) == -1)
178 5546fdd5 2022-12-23 op return (NULL);
179 5546fdd5 2022-12-23 op iri->iri_flags |= IH_HOST;
180 5546fdd5 2022-12-23 op return (t);
181 5546fdd5 2022-12-23 op }
182 5546fdd5 2022-12-23 op
183 5546fdd5 2022-12-23 op for (;;) {
184 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t))
185 5546fdd5 2022-12-23 op t++;
186 5546fdd5 2022-12-23 op else if (pctenc(t))
187 5546fdd5 2022-12-23 op t += 3;
188 5546fdd5 2022-12-23 op else
189 5546fdd5 2022-12-23 op break;
190 5546fdd5 2022-12-23 op }
191 5546fdd5 2022-12-23 op
192 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_host, sizeof(iri->iri_host)) == -1)
193 5546fdd5 2022-12-23 op return (NULL);
194 5546fdd5 2022-12-23 op iri->iri_flags |= IH_HOST;
195 5546fdd5 2022-12-23 op return (t);
196 5546fdd5 2022-12-23 op }
197 5546fdd5 2022-12-23 op
198 5546fdd5 2022-12-23 op static const char *
199 5546fdd5 2022-12-23 op parse_port(const char *s, struct iri *iri)
200 5546fdd5 2022-12-23 op {
201 5546fdd5 2022-12-23 op const char *t = s;
202 5546fdd5 2022-12-23 op const char *errstr;
203 5546fdd5 2022-12-23 op
204 5546fdd5 2022-12-23 op while (isdigit((unsigned char)*t))
205 5546fdd5 2022-12-23 op t++;
206 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_portstr, sizeof(iri->iri_portstr)) == -1)
207 5546fdd5 2022-12-23 op return (NULL);
208 5546fdd5 2022-12-23 op iri->iri_port = strtonum(iri->iri_portstr, 1, UINT16_MAX, &errstr);
209 5546fdd5 2022-12-23 op if (errstr)
210 5546fdd5 2022-12-23 op return (NULL);
211 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PORT;
212 5546fdd5 2022-12-23 op return (t);
213 5546fdd5 2022-12-23 op }
214 5546fdd5 2022-12-23 op
215 5546fdd5 2022-12-23 op static const char *
216 5546fdd5 2022-12-23 op parse_authority(const char *s, struct iri *iri)
217 5546fdd5 2022-12-23 op {
218 5546fdd5 2022-12-23 op const char *t;
219 5546fdd5 2022-12-23 op
220 5546fdd5 2022-12-23 op if ((t = parse_uinfo(s, iri)) == NULL)
221 5546fdd5 2022-12-23 op return (NULL);
222 5546fdd5 2022-12-23 op
223 5546fdd5 2022-12-23 op if ((t = parse_host(t, iri)) == NULL)
224 5546fdd5 2022-12-23 op return (NULL);
225 5546fdd5 2022-12-23 op
226 5546fdd5 2022-12-23 op if (*t == ':')
227 5546fdd5 2022-12-23 op return (parse_port(t, iri));
228 5546fdd5 2022-12-23 op
229 5546fdd5 2022-12-23 op return (t);
230 5546fdd5 2022-12-23 op }
231 5546fdd5 2022-12-23 op
232 5546fdd5 2022-12-23 op static const char *
233 5546fdd5 2022-12-23 op parse_path_abempty(const char *s, struct iri *iri)
234 5546fdd5 2022-12-23 op {
235 5546fdd5 2022-12-23 op const char *t = s;
236 5546fdd5 2022-12-23 op
237 5546fdd5 2022-12-23 op while (*t == '/')
238 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
239 5546fdd5 2022-12-23 op
240 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
241 5546fdd5 2022-12-23 op return (NULL);
242 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
243 5546fdd5 2022-12-23 op return (t);
244 5546fdd5 2022-12-23 op }
245 5546fdd5 2022-12-23 op
246 5546fdd5 2022-12-23 op static const char *
247 5546fdd5 2022-12-23 op parse_path_absolute(const char *s, struct iri *iri)
248 5546fdd5 2022-12-23 op {
249 5546fdd5 2022-12-23 op const char *t;
250 5546fdd5 2022-12-23 op
251 5546fdd5 2022-12-23 op if (*s != '/')
252 5546fdd5 2022-12-23 op return (NULL);
253 5546fdd5 2022-12-23 op
254 5546fdd5 2022-12-23 op if ((t = advance_segment_nz(s + 1)) == NULL)
255 5546fdd5 2022-12-23 op return (s + 1);
256 5546fdd5 2022-12-23 op
257 5546fdd5 2022-12-23 op while (*t == '/')
258 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
259 5546fdd5 2022-12-23 op
260 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
261 5546fdd5 2022-12-23 op return (NULL);
262 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
263 5546fdd5 2022-12-23 op return (t);
264 5546fdd5 2022-12-23 op }
265 5546fdd5 2022-12-23 op
266 5546fdd5 2022-12-23 op static const char *
267 5546fdd5 2022-12-23 op parse_path_rootless(const char *s, struct iri *iri)
268 5546fdd5 2022-12-23 op {
269 5546fdd5 2022-12-23 op const char *t;
270 5546fdd5 2022-12-23 op
271 5546fdd5 2022-12-23 op if ((t = advance_segment_nz(s)) == NULL)
272 5546fdd5 2022-12-23 op return (NULL);
273 5546fdd5 2022-12-23 op
274 5546fdd5 2022-12-23 op while (*t == '/')
275 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
276 5546fdd5 2022-12-23 op
277 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
278 5546fdd5 2022-12-23 op return (NULL);
279 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
280 5546fdd5 2022-12-23 op return (t);
281 5546fdd5 2022-12-23 op }
282 5546fdd5 2022-12-23 op
283 5546fdd5 2022-12-23 op static const char *
284 5546fdd5 2022-12-23 op parse_path_noscheme(const char *s, struct iri *iri)
285 5546fdd5 2022-12-23 op {
286 5546fdd5 2022-12-23 op const char *t;
287 5546fdd5 2022-12-23 op
288 5546fdd5 2022-12-23 op if ((t = advance_segment_nz_nc(s)) == NULL)
289 5546fdd5 2022-12-23 op return (NULL);
290 5546fdd5 2022-12-23 op
291 5546fdd5 2022-12-23 op while (*t == '/')
292 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
293 5546fdd5 2022-12-23 op
294 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
295 5546fdd5 2022-12-23 op return (NULL);
296 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
297 5546fdd5 2022-12-23 op return (t);
298 5546fdd5 2022-12-23 op }
299 5546fdd5 2022-12-23 op
300 5546fdd5 2022-12-23 op static const char *
301 5546fdd5 2022-12-23 op parse_path_empty(const char *s, struct iri *iri)
302 5546fdd5 2022-12-23 op {
303 5546fdd5 2022-12-23 op iri->iri_path[0] = '\0';
304 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
305 5546fdd5 2022-12-23 op return (s);
306 5546fdd5 2022-12-23 op }
307 5546fdd5 2022-12-23 op
308 5546fdd5 2022-12-23 op static const char *
309 5546fdd5 2022-12-23 op parse_hier(const char *s, struct iri *iri)
310 5546fdd5 2022-12-23 op {
311 5546fdd5 2022-12-23 op const char *t;
312 5546fdd5 2022-12-23 op
313 5546fdd5 2022-12-23 op if (!strncmp(s, "//", 2)) {
314 5546fdd5 2022-12-23 op if ((t = parse_authority(s + 2, iri)) == NULL)
315 5546fdd5 2022-12-23 op return (NULL);
316 5546fdd5 2022-12-23 op return (parse_path_abempty(t, iri));
317 5546fdd5 2022-12-23 op }
318 5546fdd5 2022-12-23 op
319 5546fdd5 2022-12-23 op if ((t = parse_path_absolute(s, iri)) != NULL)
320 5546fdd5 2022-12-23 op return (t);
321 5546fdd5 2022-12-23 op
322 5546fdd5 2022-12-23 op if ((t = parse_path_rootless(s, iri)) != NULL)
323 5546fdd5 2022-12-23 op return (t);
324 5546fdd5 2022-12-23 op
325 5546fdd5 2022-12-23 op return (parse_path_empty(s, iri));
326 5546fdd5 2022-12-23 op }
327 5546fdd5 2022-12-23 op
328 5546fdd5 2022-12-23 op static const char *
329 5546fdd5 2022-12-23 op parse_relative(const char *s, struct iri *iri)
330 5546fdd5 2022-12-23 op {
331 5546fdd5 2022-12-23 op const char *t = s;
332 5546fdd5 2022-12-23 op
333 5546fdd5 2022-12-23 op if (!strncmp(s, "//", 2)) {
334 5546fdd5 2022-12-23 op if ((t = parse_authority(s + 2, iri)) == NULL)
335 5546fdd5 2022-12-23 op return (NULL);
336 5546fdd5 2022-12-23 op return (parse_path_abempty(t, iri));
337 5546fdd5 2022-12-23 op }
338 5546fdd5 2022-12-23 op
339 5546fdd5 2022-12-23 op if ((t = parse_path_absolute(s, iri)) != NULL)
340 5546fdd5 2022-12-23 op return (t);
341 5546fdd5 2022-12-23 op
342 5546fdd5 2022-12-23 op if ((t = parse_path_noscheme(s, iri)) != NULL)
343 5546fdd5 2022-12-23 op return (t);
344 5546fdd5 2022-12-23 op
345 5546fdd5 2022-12-23 op return (parse_path_empty(s, iri));
346 5546fdd5 2022-12-23 op }
347 5546fdd5 2022-12-23 op
348 5546fdd5 2022-12-23 op static const char *
349 5546fdd5 2022-12-23 op parse_query(const char *s, struct iri *iri)
350 5546fdd5 2022-12-23 op {
351 5546fdd5 2022-12-23 op const char *n, *t = s;
352 5546fdd5 2022-12-23 op
353 5546fdd5 2022-12-23 op for (;;) {
354 5546fdd5 2022-12-23 op if ((n = advance_pchar(t)) != NULL)
355 5546fdd5 2022-12-23 op t = n;
356 5546fdd5 2022-12-23 op else if (*t == '/' || *t == '?')
357 5546fdd5 2022-12-23 op t++;
358 5546fdd5 2022-12-23 op else
359 5546fdd5 2022-12-23 op break;
360 5546fdd5 2022-12-23 op }
361 5546fdd5 2022-12-23 op
362 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_query, sizeof(iri->iri_query)) == -1)
363 5546fdd5 2022-12-23 op return (NULL);
364 5546fdd5 2022-12-23 op iri->iri_flags |= IH_QUERY;
365 5546fdd5 2022-12-23 op return (t);
366 5546fdd5 2022-12-23 op }
367 5546fdd5 2022-12-23 op
368 5546fdd5 2022-12-23 op static int
369 5546fdd5 2022-12-23 op parse_uri(const char *s, struct iri *iri)
370 5546fdd5 2022-12-23 op {
371 5546fdd5 2022-12-23 op if ((s = parse_scheme(s, iri)) == NULL)
372 5546fdd5 2022-12-23 op return (-1);
373 5546fdd5 2022-12-23 op
374 5546fdd5 2022-12-23 op if (*s != ':')
375 5546fdd5 2022-12-23 op return (-1);
376 5546fdd5 2022-12-23 op
377 5546fdd5 2022-12-23 op if ((s = parse_hier(s + 1, iri)) == NULL)
378 5546fdd5 2022-12-23 op return (-1);
379 5546fdd5 2022-12-23 op
380 5546fdd5 2022-12-23 op if (*s == '?' && (s = parse_query(s + 1, iri)) == NULL)
381 5546fdd5 2022-12-23 op return (-1);
382 5546fdd5 2022-12-23 op
383 5546fdd5 2022-12-23 op /* skip fragments */
384 5546fdd5 2022-12-23 op if (*s == '#' || *s == '\0')
385 5546fdd5 2022-12-23 op return (0);
386 5546fdd5 2022-12-23 op
387 5546fdd5 2022-12-23 op return (-1);
388 5546fdd5 2022-12-23 op }
389 5546fdd5 2022-12-23 op
390 5546fdd5 2022-12-23 op static int
391 5546fdd5 2022-12-23 op parse_relative_ref(const char *s, struct iri *iri)
392 5546fdd5 2022-12-23 op {
393 5546fdd5 2022-12-23 op if ((s = parse_relative(s, iri)) == NULL)
394 5546fdd5 2022-12-23 op return (-1);
395 5546fdd5 2022-12-23 op
396 5546fdd5 2022-12-23 op if (*s == '?' && (s = parse_query(s + 1, iri)) == NULL)
397 5546fdd5 2022-12-23 op return (-1);
398 5546fdd5 2022-12-23 op
399 5546fdd5 2022-12-23 op /* skip fragments */
400 5546fdd5 2022-12-23 op if (*s == '#' || *s == '\0')
401 5546fdd5 2022-12-23 op return (0);
402 5546fdd5 2022-12-23 op
403 5546fdd5 2022-12-23 op return (-1);
404 5546fdd5 2022-12-23 op }
405 5546fdd5 2022-12-23 op
406 5546fdd5 2022-12-23 op static int
407 5546fdd5 2022-12-23 op parse(const char *s, struct iri *iri)
408 5546fdd5 2022-12-23 op {
409 5546fdd5 2022-12-23 op iri->iri_flags = 0;
410 5546fdd5 2022-12-23 op
411 5546fdd5 2022-12-23 op if (s == NULL)
412 5546fdd5 2022-12-23 op return (0);
413 5546fdd5 2022-12-23 op
414 5546fdd5 2022-12-23 op if (parse_uri(s, iri) == -1) {
415 5546fdd5 2022-12-23 op iri->iri_flags = 0;
416 5546fdd5 2022-12-23 op if (parse_relative_ref(s, iri) == -1)
417 5546fdd5 2022-12-23 op return (-1);
418 5546fdd5 2022-12-23 op }
419 5546fdd5 2022-12-23 op
420 5546fdd5 2022-12-23 op return (0);
421 5546fdd5 2022-12-23 op }
422 5546fdd5 2022-12-23 op
423 51762770 2022-12-24 op static inline void
424 51762770 2022-12-24 op lowerify(char *s)
425 51762770 2022-12-24 op {
426 51762770 2022-12-24 op for (; *s; ++s)
427 51762770 2022-12-24 op *s = tolower((unsigned char)*s);
428 51762770 2022-12-24 op }
429 51762770 2022-12-24 op
430 5546fdd5 2022-12-23 op static void
431 5546fdd5 2022-12-23 op cpfields(struct iri *dest, const struct iri *src, int flags)
432 5546fdd5 2022-12-23 op {
433 5546fdd5 2022-12-23 op if (flags & IH_SCHEME) {
434 5546fdd5 2022-12-23 op dest->iri_flags |= IH_SCHEME;
435 5546fdd5 2022-12-23 op if (src->iri_flags & IH_SCHEME)
436 5546fdd5 2022-12-23 op memcpy(dest->iri_scheme, src->iri_scheme,
437 5546fdd5 2022-12-23 op sizeof(dest->iri_scheme));
438 51762770 2022-12-24 op lowerify(dest->iri_scheme);
439 5546fdd5 2022-12-23 op }
440 5546fdd5 2022-12-23 op if (flags & IH_UINFO) {
441 997b9cd0 2022-12-24 op if (src->iri_flags & IH_UINFO) {
442 5546fdd5 2022-12-23 op memcpy(dest->iri_uinfo, src->iri_uinfo,
443 5546fdd5 2022-12-23 op sizeof(dest->iri_uinfo));
444 997b9cd0 2022-12-24 op dest->iri_flags |= IH_UINFO;
445 997b9cd0 2022-12-24 op }
446 5546fdd5 2022-12-23 op }
447 5546fdd5 2022-12-23 op if (flags & IH_HOST) {
448 5546fdd5 2022-12-23 op dest->iri_flags |= IH_HOST;
449 5546fdd5 2022-12-23 op if (src->iri_flags & IH_HOST)
450 5546fdd5 2022-12-23 op memcpy(dest->iri_host, src->iri_host,
451 5546fdd5 2022-12-23 op sizeof(dest->iri_host));
452 51762770 2022-12-24 op lowerify(dest->iri_host);
453 5546fdd5 2022-12-23 op }
454 5546fdd5 2022-12-23 op if (flags & IH_PORT) {
455 997b9cd0 2022-12-24 op if (src->iri_flags & IH_PORT) {
456 5546fdd5 2022-12-23 op dest->iri_port = src->iri_port;
457 997b9cd0 2022-12-24 op dest->iri_flags |= IH_PORT;
458 997b9cd0 2022-12-24 op }
459 5546fdd5 2022-12-23 op }
460 5546fdd5 2022-12-23 op if (flags & IH_PATH) {
461 5546fdd5 2022-12-23 op dest->iri_flags |= IH_PATH;
462 5546fdd5 2022-12-23 op if (src->iri_flags & IH_PATH)
463 5546fdd5 2022-12-23 op memcpy(dest->iri_path, src->iri_path,
464 5546fdd5 2022-12-23 op sizeof(dest->iri_path));
465 5546fdd5 2022-12-23 op }
466 5546fdd5 2022-12-23 op if (flags & IH_QUERY) {
467 997b9cd0 2022-12-24 op if (src->iri_flags & IH_QUERY) {
468 997b9cd0 2022-12-24 op dest->iri_flags |= IH_QUERY;
469 5546fdd5 2022-12-23 op memcpy(dest->iri_query, src->iri_query,
470 5546fdd5 2022-12-23 op sizeof(dest->iri_query));
471 997b9cd0 2022-12-24 op }
472 5546fdd5 2022-12-23 op }
473 5546fdd5 2022-12-23 op }
474 5546fdd5 2022-12-23 op
475 871b5bb7 2022-12-24 op static inline int
476 5546fdd5 2022-12-23 op remove_dot_segments(struct iri *iri)
477 5546fdd5 2022-12-23 op {
478 245a86c3 2022-12-24 op char *p, *q, *buf, *s;
479 871b5bb7 2022-12-24 op ptrdiff_t bufsize;
480 5546fdd5 2022-12-23 op
481 871b5bb7 2022-12-24 op buf = p = q = iri->iri_path;
482 871b5bb7 2022-12-24 op bufsize = sizeof(iri->iri_path);
483 871b5bb7 2022-12-24 op
484 871b5bb7 2022-12-24 op while (*p && (q - buf < bufsize)) {
485 871b5bb7 2022-12-24 op /* A */
486 871b5bb7 2022-12-24 op if (!strncmp(p, "../", 3)) {
487 871b5bb7 2022-12-24 op p += 3;
488 871b5bb7 2022-12-24 op continue;
489 871b5bb7 2022-12-24 op }
490 871b5bb7 2022-12-24 op if (!strncmp(p, "./", 3)) {
491 871b5bb7 2022-12-24 op p += 2;
492 871b5bb7 2022-12-24 op continue;
493 871b5bb7 2022-12-24 op }
494 871b5bb7 2022-12-24 op /* B */
495 871b5bb7 2022-12-24 op if (!strncmp(p, "/./", 3)) {
496 871b5bb7 2022-12-24 op *q++ = '/';
497 871b5bb7 2022-12-24 op p += 3;
498 871b5bb7 2022-12-24 op continue;
499 871b5bb7 2022-12-24 op }
500 871b5bb7 2022-12-24 op if (!strcmp(p, "/.")) {
501 871b5bb7 2022-12-24 op p += 2;
502 871b5bb7 2022-12-24 op break;
503 871b5bb7 2022-12-24 op }
504 871b5bb7 2022-12-24 op /* C */
505 871b5bb7 2022-12-24 op if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
506 871b5bb7 2022-12-24 op (p[3] == '/' || p[3] == '\0')) {
507 871b5bb7 2022-12-24 op p += 3;
508 871b5bb7 2022-12-24 op while (q != buf && *--q != '/')
509 871b5bb7 2022-12-24 op continue;
510 871b5bb7 2022-12-24 op continue;
511 871b5bb7 2022-12-24 op }
512 871b5bb7 2022-12-24 op /* D */
513 871b5bb7 2022-12-24 op if (!strcmp(p, ".")) {
514 871b5bb7 2022-12-24 op p++;
515 871b5bb7 2022-12-24 op break;
516 871b5bb7 2022-12-24 op }
517 871b5bb7 2022-12-24 op if (!strcmp(p, "..")) {
518 871b5bb7 2022-12-24 op p += 2;
519 871b5bb7 2022-12-24 op break;
520 871b5bb7 2022-12-24 op }
521 871b5bb7 2022-12-24 op /* E */
522 245a86c3 2022-12-24 op s = strchr(p + 1, '/');
523 245a86c3 2022-12-24 op while (*p && p != s && (q - buf < bufsize))
524 871b5bb7 2022-12-24 op *q++ = *p++;
525 871b5bb7 2022-12-24 op }
526 871b5bb7 2022-12-24 op
527 871b5bb7 2022-12-24 op if (*p == '\0' && (q - buf < bufsize)) {
528 871b5bb7 2022-12-24 op *q = '\0';
529 871b5bb7 2022-12-24 op return (0);
530 871b5bb7 2022-12-24 op }
531 871b5bb7 2022-12-24 op
532 871b5bb7 2022-12-24 op errno = ENAMETOOLONG;
533 871b5bb7 2022-12-24 op return (-1);
534 871b5bb7 2022-12-24 op }
535 871b5bb7 2022-12-24 op
536 871b5bb7 2022-12-24 op static inline int
537 871b5bb7 2022-12-24 op mergepath(struct iri *i, struct iri *base, struct iri *r)
538 5546fdd5 2022-12-23 op {
539 871b5bb7 2022-12-24 op const char *bpath, *rpath, *s;
540 871b5bb7 2022-12-24 op
541 871b5bb7 2022-12-24 op bpath = (base->iri_flags & IH_PATH) ? base->iri_path : "/";
542 871b5bb7 2022-12-24 op rpath = (r->iri_flags & IH_PATH) ? r->iri_path : "/";
543 871b5bb7 2022-12-24 op
544 871b5bb7 2022-12-24 op i->iri_flags |= IH_PATH;
545 871b5bb7 2022-12-24 op i->iri_path[0] = '\0';
546 871b5bb7 2022-12-24 op
547 871b5bb7 2022-12-24 op if ((base->iri_flags & IH_AUTHORITY) &&
548 871b5bb7 2022-12-24 op (*bpath == '\0' || !strcmp(bpath, "/"))) {
549 871b5bb7 2022-12-24 op if (*rpath == '/')
550 871b5bb7 2022-12-24 op rpath++;
551 871b5bb7 2022-12-24 op strlcpy(i->iri_path, "/", sizeof(i->iri_path));
552 871b5bb7 2022-12-24 op strlcat(i->iri_path, rpath, sizeof(i->iri_path));
553 871b5bb7 2022-12-24 op return (0);
554 871b5bb7 2022-12-24 op }
555 871b5bb7 2022-12-24 op
556 871b5bb7 2022-12-24 op if ((s = strrchr(bpath, '/')) != NULL) {
557 871b5bb7 2022-12-24 op cpstr(bpath, s + 1, i->iri_path, sizeof(i->iri_path));
558 871b5bb7 2022-12-24 op if (*rpath == '/')
559 871b5bb7 2022-12-24 op rpath++;
560 871b5bb7 2022-12-24 op }
561 871b5bb7 2022-12-24 op if (strlcat(i->iri_path, rpath, sizeof(i->iri_path)) >=
562 871b5bb7 2022-12-24 op sizeof(i->iri_path)) {
563 871b5bb7 2022-12-24 op errno = ENAMETOOLONG;
564 871b5bb7 2022-12-24 op return (-1);
565 871b5bb7 2022-12-24 op }
566 871b5bb7 2022-12-24 op
567 871b5bb7 2022-12-24 op return (0);
568 5546fdd5 2022-12-23 op }
569 5546fdd5 2022-12-23 op
570 5546fdd5 2022-12-23 op int
571 5546fdd5 2022-12-23 op iri_parse(const char *base, const char *str, struct iri *iri)
572 5546fdd5 2022-12-23 op {
573 5546fdd5 2022-12-23 op static struct iri ibase, iparsed;
574 5546fdd5 2022-12-23 op
575 5546fdd5 2022-12-23 op memset(iri, 0, sizeof(*iri));
576 5546fdd5 2022-12-23 op
577 5546fdd5 2022-12-23 op if (base == NULL) {
578 5546fdd5 2022-12-23 op ibase.iri_flags = 0;
579 f5bc8482 2022-12-24 op if (parse_uri(str, &iparsed) == -1) {
580 f5bc8482 2022-12-24 op errno = EINVAL;
581 5546fdd5 2022-12-23 op return (-1);
582 f5bc8482 2022-12-24 op }
583 5546fdd5 2022-12-23 op } else {
584 f5bc8482 2022-12-24 op if (parse_uri(base, &ibase) == -1 ||
585 f5bc8482 2022-12-24 op parse(str, &iparsed) == -1) {
586 f5bc8482 2022-12-24 op errno = EINVAL;
587 5546fdd5 2022-12-23 op return (-1);
588 f5bc8482 2022-12-24 op }
589 5546fdd5 2022-12-23 op }
590 5546fdd5 2022-12-23 op
591 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_SCHEME) {
592 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, iparsed.iri_flags);
593 5546fdd5 2022-12-23 op remove_dot_segments(iri);
594 5546fdd5 2022-12-23 op return (0);
595 5546fdd5 2022-12-23 op }
596 5546fdd5 2022-12-23 op
597 5546fdd5 2022-12-23 op /* if fragments are supported, copy iparsed fragment to iri */
598 5546fdd5 2022-12-23 op
599 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_SCHEME);
600 5546fdd5 2022-12-23 op
601 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_HOST) {
602 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_AUTHORITY|IH_PATH|IH_QUERY);
603 5546fdd5 2022-12-23 op remove_dot_segments(iri);
604 5546fdd5 2022-12-23 op return (0);
605 5546fdd5 2022-12-23 op }
606 5546fdd5 2022-12-23 op
607 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_AUTHORITY);
608 5546fdd5 2022-12-23 op
609 5546fdd5 2022-12-23 op if ((iparsed.iri_flags & IH_PATH) && *iparsed.iri_path == '\0') {
610 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_PATH);
611 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_QUERY)
612 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_QUERY);
613 5546fdd5 2022-12-23 op else
614 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_QUERY);
615 5546fdd5 2022-12-23 op return (0);
616 5546fdd5 2022-12-23 op }
617 5546fdd5 2022-12-23 op
618 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_QUERY);
619 5546fdd5 2022-12-23 op if ((iparsed.iri_flags & IH_PATH) && !strcmp(iparsed.iri_path, "/"))
620 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_PATH);
621 5546fdd5 2022-12-23 op else {
622 5546fdd5 2022-12-23 op if (!(ibase.iri_flags & IH_PATH))
623 5546fdd5 2022-12-23 op ibase.iri_path[0] = '\0';
624 5546fdd5 2022-12-23 op if (!(iparsed.iri_flags & IH_PATH))
625 5546fdd5 2022-12-23 op iparsed.iri_path[0] = '\0';
626 f5bc8482 2022-12-24 op if (mergepath(iri, &ibase, &iparsed) == -1)
627 f5bc8482 2022-12-24 op return (-1);
628 5546fdd5 2022-12-23 op }
629 f5bc8482 2022-12-24 op if (remove_dot_segments(iri) == -1)
630 f5bc8482 2022-12-24 op return (-1);
631 5546fdd5 2022-12-23 op return (0);
632 5546fdd5 2022-12-23 op }
633 5546fdd5 2022-12-23 op
634 5546fdd5 2022-12-23 op int
635 d59fad58 2022-12-24 op iri_unparse(const struct iri *i, char *buf, size_t buflen)
636 5546fdd5 2022-12-23 op {
637 d59fad58 2022-12-24 op if (buflen == 0)
638 d59fad58 2022-12-24 op goto err;
639 d59fad58 2022-12-24 op
640 d59fad58 2022-12-24 op /* TODO: should %enc octets if needed */
641 d59fad58 2022-12-24 op
642 d59fad58 2022-12-24 op buf[0] = '\0';
643 d59fad58 2022-12-24 op
644 d59fad58 2022-12-24 op if (i->iri_flags & IH_SCHEME) {
645 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_scheme, buflen) >= buflen ||
646 d59fad58 2022-12-24 op strlcat(buf, ":", buflen) >= buflen)
647 d59fad58 2022-12-24 op goto err;
648 d59fad58 2022-12-24 op }
649 d59fad58 2022-12-24 op
650 d59fad58 2022-12-24 op if (i->iri_flags & IH_AUTHORITY) {
651 d59fad58 2022-12-24 op if (strlcat(buf, "//", buflen) >= buflen)
652 d59fad58 2022-12-24 op goto err;
653 d59fad58 2022-12-24 op }
654 d59fad58 2022-12-24 op
655 d59fad58 2022-12-24 op if (i->iri_flags & IH_UINFO) {
656 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_uinfo, buflen) >= buflen ||
657 d59fad58 2022-12-24 op strlcat(buf, "@", buflen) >= buflen)
658 d59fad58 2022-12-24 op goto err;
659 d59fad58 2022-12-24 op }
660 d59fad58 2022-12-24 op if (i->iri_flags & IH_HOST) {
661 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_host, buflen) >= buflen)
662 d59fad58 2022-12-24 op goto err;
663 d59fad58 2022-12-24 op }
664 d59fad58 2022-12-24 op if (i->iri_flags & IH_PORT) {
665 d59fad58 2022-12-24 op if (strlcat(buf, ":", buflen) >= buflen ||
666 d59fad58 2022-12-24 op strlcat(buf, i->iri_portstr, buflen) >= buflen)
667 d59fad58 2022-12-24 op goto err;
668 d59fad58 2022-12-24 op }
669 d59fad58 2022-12-24 op
670 d59fad58 2022-12-24 op if (i->iri_flags & IH_PATH) {
671 a655e85a 2022-12-24 op if (i->iri_flags & IH_AUTHORITY &&
672 d59fad58 2022-12-24 op i->iri_path[0] != '/' &&
673 d59fad58 2022-12-24 op strlcat(buf, "/", buflen) >= buflen)
674 d59fad58 2022-12-24 op goto err;
675 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_path, buflen) >= buflen)
676 d59fad58 2022-12-24 op goto err;
677 d59fad58 2022-12-24 op }
678 d59fad58 2022-12-24 op
679 d59fad58 2022-12-24 op if (i->iri_flags & IH_QUERY) {
680 d59fad58 2022-12-24 op if (strlcat(buf, "?", buflen) >= buflen ||
681 d59fad58 2022-12-24 op strlcat(buf, i->iri_query, buflen) >= buflen)
682 d59fad58 2022-12-24 op goto err;
683 d59fad58 2022-12-24 op }
684 d59fad58 2022-12-24 op
685 d59fad58 2022-12-24 op return (0);
686 d59fad58 2022-12-24 op
687 d59fad58 2022-12-24 op err:
688 d59fad58 2022-12-24 op errno = ENOBUFS;
689 5546fdd5 2022-12-23 op return (-1);
690 5546fdd5 2022-12-23 op }
691 5546fdd5 2022-12-23 op
692 5546fdd5 2022-12-23 op int
693 5546fdd5 2022-12-23 op iri_human(const struct iri *iri, char *buf, size_t buflen)
694 5546fdd5 2022-12-23 op {
695 5546fdd5 2022-12-23 op memset(buf, 0, buflen);
696 5546fdd5 2022-12-23 op return (-1);
697 5546fdd5 2022-12-23 op }
698 5546fdd5 2022-12-23 op
699 5546fdd5 2022-12-23 op int
700 5546fdd5 2022-12-23 op iri_setquery(struct iri *iri, const char *text)
701 5546fdd5 2022-12-23 op {
702 5546fdd5 2022-12-23 op return (-1);
703 5546fdd5 2022-12-23 op }