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