Blame


1 bfa33dbe 2021-04-22 op /*
2 bfa33dbe 2021-04-22 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 bfa33dbe 2021-04-22 op *
4 bfa33dbe 2021-04-22 op * Permission to use, copy, modify, and distribute this software for any
5 bfa33dbe 2021-04-22 op * purpose with or without fee is hereby granted, provided that the above
6 bfa33dbe 2021-04-22 op * copyright notice and this permission notice appear in all copies.
7 bfa33dbe 2021-04-22 op *
8 bfa33dbe 2021-04-22 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 bfa33dbe 2021-04-22 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 bfa33dbe 2021-04-22 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 bfa33dbe 2021-04-22 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 bfa33dbe 2021-04-22 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 bfa33dbe 2021-04-22 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 bfa33dbe 2021-04-22 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 bfa33dbe 2021-04-22 op */
16 bfa33dbe 2021-04-22 op
17 bfa33dbe 2021-04-22 op /*
18 bfa33dbe 2021-04-22 op * TODOs:
19 bfa33dbe 2021-04-22 op * - distinguish between an empty component and a undefined one
20 bfa33dbe 2021-04-22 op * - ...
21 bfa33dbe 2021-04-22 op */
22 bfa33dbe 2021-04-22 op
23 bfa33dbe 2021-04-22 op #include <assert.h>
24 bfa33dbe 2021-04-22 op
25 bfa33dbe 2021-04-22 op #include "compat.h"
26 bfa33dbe 2021-04-22 op
27 bfa33dbe 2021-04-22 op #include "phos.h"
28 bfa33dbe 2021-04-22 op
29 bfa33dbe 2021-04-22 op #include <ctype.h>
30 bfa33dbe 2021-04-22 op #include <stdint.h>
31 4190a5c2 2021-04-24 op #include <stdio.h>
32 bfa33dbe 2021-04-22 op #include <stdlib.h>
33 bfa33dbe 2021-04-22 op #include <string.h>
34 bfa33dbe 2021-04-22 op
35 bfa33dbe 2021-04-22 op static const char *sub_ip_literal(const char*);
36 bfa33dbe 2021-04-22 op static const char *sub_host_dummy(const char*);
37 bfa33dbe 2021-04-22 op static const char *sub_pchar(const char*);
38 4190a5c2 2021-04-24 op
39 bfa33dbe 2021-04-22 op static const char *sub_segment(const char*);
40 bfa33dbe 2021-04-22 op static const char *sub_segment_nz(const char*);
41 bfa33dbe 2021-04-22 op static const char *sub_segment_nz_nc(const char*);
42 bfa33dbe 2021-04-22 op static const char *sub_path_common(const char*);
43 bfa33dbe 2021-04-22 op
44 bfa33dbe 2021-04-22 op static const char *parse_scheme(const char*, struct phos_uri*);
45 bfa33dbe 2021-04-22 op static const char *parse_host(const char*, struct phos_uri*);
46 bfa33dbe 2021-04-22 op static const char *parse_port(const char*, struct phos_uri*);
47 bfa33dbe 2021-04-22 op static const char *parse_authority(const char*, struct phos_uri*);
48 bfa33dbe 2021-04-22 op static const char *parse_path_abempty(const char*, struct phos_uri*);
49 bfa33dbe 2021-04-22 op static const char *parse_path_absolute(const char*, struct phos_uri*);
50 bfa33dbe 2021-04-22 op static const char *parse_path_noscheme(const char*, struct phos_uri*);
51 bfa33dbe 2021-04-22 op static const char *parse_path_rootless(const char*, struct phos_uri*);
52 bfa33dbe 2021-04-22 op static const char *parse_path_empty(const char*, struct phos_uri*);
53 bfa33dbe 2021-04-22 op static const char *parse_hier_part(const char*, struct phos_uri*);
54 bfa33dbe 2021-04-22 op static const char *parse_query(const char*, struct phos_uri*);
55 bfa33dbe 2021-04-22 op static const char *parse_fragment(const char*, struct phos_uri*);
56 bfa33dbe 2021-04-22 op static const char *parse_uri(const char*, struct phos_uri*);
57 bfa33dbe 2021-04-22 op static const char *parse_relative_part(const char*, struct phos_uri*);
58 bfa33dbe 2021-04-22 op static const char *parse_relative_ref(const char*, struct phos_uri*);
59 bfa33dbe 2021-04-22 op static const char *parse_uri_reference(const char*, struct phos_uri*);
60 bfa33dbe 2021-04-22 op
61 bfa33dbe 2021-04-22 op static int hasprefix(const char*, const char*);
62 bfa33dbe 2021-04-22 op static char *dotdot(char*, char*);
63 bfa33dbe 2021-04-22 op static void path_clean(struct phos_uri*);
64 bfa33dbe 2021-04-22 op static int merge_path(struct phos_uri*, const struct phos_uri*, const struct phos_uri*);
65 bfa33dbe 2021-04-22 op
66 bfa33dbe 2021-04-22 op static int phos_resolve_uri_from(const struct phos_uri*, const struct phos_uri*, struct phos_uri*);
67 bfa33dbe 2021-04-22 op
68 bfa33dbe 2021-04-22 op
69 bfa33dbe 2021-04-22 op /* common defs */
70 bfa33dbe 2021-04-22 op
71 bfa33dbe 2021-04-22 op static inline int
72 bfa33dbe 2021-04-22 op gen_delims(int c)
73 bfa33dbe 2021-04-22 op {
74 bfa33dbe 2021-04-22 op return c == ':'
75 bfa33dbe 2021-04-22 op || c == '/'
76 bfa33dbe 2021-04-22 op || c == '?'
77 bfa33dbe 2021-04-22 op || c == '#'
78 bfa33dbe 2021-04-22 op || c == '['
79 bfa33dbe 2021-04-22 op || c == ']'
80 bfa33dbe 2021-04-22 op || c == '@';
81 bfa33dbe 2021-04-22 op }
82 bfa33dbe 2021-04-22 op
83 bfa33dbe 2021-04-22 op static inline int
84 bfa33dbe 2021-04-22 op sub_delims(int c)
85 bfa33dbe 2021-04-22 op {
86 bfa33dbe 2021-04-22 op return c == '!'
87 bfa33dbe 2021-04-22 op || c == '$'
88 bfa33dbe 2021-04-22 op || c == '&'
89 bfa33dbe 2021-04-22 op || c == '\''
90 bfa33dbe 2021-04-22 op || c == '('
91 bfa33dbe 2021-04-22 op || c == ')'
92 bfa33dbe 2021-04-22 op || c == '*'
93 bfa33dbe 2021-04-22 op || c == '+'
94 bfa33dbe 2021-04-22 op || c == ','
95 bfa33dbe 2021-04-22 op || c == ';'
96 bfa33dbe 2021-04-22 op || c == '=';
97 bfa33dbe 2021-04-22 op }
98 bfa33dbe 2021-04-22 op
99 bfa33dbe 2021-04-22 op static inline int
100 bfa33dbe 2021-04-22 op reserved(int c)
101 bfa33dbe 2021-04-22 op {
102 bfa33dbe 2021-04-22 op return gen_delims(c) || sub_delims(c);
103 bfa33dbe 2021-04-22 op }
104 bfa33dbe 2021-04-22 op
105 bfa33dbe 2021-04-22 op static inline int
106 bfa33dbe 2021-04-22 op unreserved(int c)
107 bfa33dbe 2021-04-22 op {
108 bfa33dbe 2021-04-22 op return isalpha(c)
109 bfa33dbe 2021-04-22 op || isdigit(c)
110 bfa33dbe 2021-04-22 op || c == '-'
111 bfa33dbe 2021-04-22 op || c == '.'
112 bfa33dbe 2021-04-22 op || c == '_'
113 bfa33dbe 2021-04-22 op || c == '~';
114 bfa33dbe 2021-04-22 op }
115 bfa33dbe 2021-04-22 op
116 bfa33dbe 2021-04-22 op
117 bfa33dbe 2021-04-22 op /* subs */
118 bfa33dbe 2021-04-22 op
119 bfa33dbe 2021-04-22 op /*
120 bfa33dbe 2021-04-22 op * IP-literal = "[" ( IPv6address / IPvFuture ) "]"
121 bfa33dbe 2021-04-22 op *
122 bfa33dbe 2021-04-22 op * in reality, we parse [.*]
123 bfa33dbe 2021-04-22 op */
124 bfa33dbe 2021-04-22 op static const char *
125 bfa33dbe 2021-04-22 op sub_ip_literal(const char *s)
126 bfa33dbe 2021-04-22 op {
127 bfa33dbe 2021-04-22 op if (*s != '[')
128 bfa33dbe 2021-04-22 op return NULL;
129 bfa33dbe 2021-04-22 op
130 bfa33dbe 2021-04-22 op while (*s != '\0' && *s != ']')
131 bfa33dbe 2021-04-22 op s++;
132 bfa33dbe 2021-04-22 op
133 bfa33dbe 2021-04-22 op if (*s == '\0')
134 bfa33dbe 2021-04-22 op return NULL;
135 bfa33dbe 2021-04-22 op return ++s;
136 bfa33dbe 2021-04-22 op }
137 bfa33dbe 2021-04-22 op
138 bfa33dbe 2021-04-22 op /*
139 bfa33dbe 2021-04-22 op * parse everything until : or / (or \0).
140 bfa33dbe 2021-04-22 op * NB: empty hosts are technically valid!
141 bfa33dbe 2021-04-22 op */
142 bfa33dbe 2021-04-22 op static const char *
143 bfa33dbe 2021-04-22 op sub_host_dummy(const char *s)
144 bfa33dbe 2021-04-22 op {
145 bfa33dbe 2021-04-22 op while (*s != '\0' && *s != ':' && *s != '/')
146 bfa33dbe 2021-04-22 op s++;
147 bfa33dbe 2021-04-22 op return s;
148 bfa33dbe 2021-04-22 op }
149 bfa33dbe 2021-04-22 op
150 bfa33dbe 2021-04-22 op /*
151 bfa33dbe 2021-04-22 op * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
152 bfa33dbe 2021-04-22 op */
153 bfa33dbe 2021-04-22 op static const char *
154 bfa33dbe 2021-04-22 op sub_pchar(const char *s)
155 bfa33dbe 2021-04-22 op {
156 bfa33dbe 2021-04-22 op if (*s == '\0')
157 bfa33dbe 2021-04-22 op return NULL;
158 bfa33dbe 2021-04-22 op
159 bfa33dbe 2021-04-22 op if (unreserved(*s))
160 bfa33dbe 2021-04-22 op return ++s;
161 bfa33dbe 2021-04-22 op
162 bfa33dbe 2021-04-22 op if (*s == '%') {
163 bfa33dbe 2021-04-22 op if (isxdigit(s[1]) && isxdigit(s[2]))
164 bfa33dbe 2021-04-22 op return s + 3;
165 bfa33dbe 2021-04-22 op }
166 bfa33dbe 2021-04-22 op
167 bfa33dbe 2021-04-22 op if (sub_delims(*s))
168 bfa33dbe 2021-04-22 op return ++s;
169 bfa33dbe 2021-04-22 op
170 bfa33dbe 2021-04-22 op if (*s == ':' || *s == '@')
171 bfa33dbe 2021-04-22 op return ++s;
172 bfa33dbe 2021-04-22 op
173 bfa33dbe 2021-04-22 op return NULL;
174 bfa33dbe 2021-04-22 op }
175 bfa33dbe 2021-04-22 op
176 bfa33dbe 2021-04-22 op /*
177 bfa33dbe 2021-04-22 op * segment = *pchar
178 bfa33dbe 2021-04-22 op */
179 bfa33dbe 2021-04-22 op static const char *
180 bfa33dbe 2021-04-22 op sub_segment(const char *s)
181 bfa33dbe 2021-04-22 op {
182 bfa33dbe 2021-04-22 op const char *t;
183 bfa33dbe 2021-04-22 op
184 bfa33dbe 2021-04-22 op while ((t = sub_pchar(s)) != NULL)
185 bfa33dbe 2021-04-22 op s = t;
186 bfa33dbe 2021-04-22 op return s;
187 bfa33dbe 2021-04-22 op }
188 bfa33dbe 2021-04-22 op
189 bfa33dbe 2021-04-22 op /* segment-nz = 1*pchar */
190 bfa33dbe 2021-04-22 op static const char *
191 bfa33dbe 2021-04-22 op sub_segment_nz(const char *s)
192 bfa33dbe 2021-04-22 op {
193 bfa33dbe 2021-04-22 op if ((s = sub_pchar(s)) == NULL)
194 bfa33dbe 2021-04-22 op return NULL;
195 bfa33dbe 2021-04-22 op return sub_segment(s);
196 bfa33dbe 2021-04-22 op }
197 bfa33dbe 2021-04-22 op
198 bfa33dbe 2021-04-22 op /*
199 bfa33dbe 2021-04-22 op * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
200 bfa33dbe 2021-04-22 op *
201 bfa33dbe 2021-04-22 op * so, 1*pchar excluding ":"
202 bfa33dbe 2021-04-22 op */
203 bfa33dbe 2021-04-22 op static const char *
204 bfa33dbe 2021-04-22 op sub_segment_nz_nc(const char *s)
205 bfa33dbe 2021-04-22 op {
206 bfa33dbe 2021-04-22 op const char *t;
207 bfa33dbe 2021-04-22 op
208 bfa33dbe 2021-04-22 op if (*s == ':')
209 bfa33dbe 2021-04-22 op return NULL;
210 bfa33dbe 2021-04-22 op
211 bfa33dbe 2021-04-22 op while (*s != ':' && (t = sub_pchar(s)) != NULL)
212 bfa33dbe 2021-04-22 op s = t;
213 bfa33dbe 2021-04-22 op return s;
214 bfa33dbe 2021-04-22 op }
215 bfa33dbe 2021-04-22 op
216 bfa33dbe 2021-04-22 op /* *( "/" segment ) */
217 bfa33dbe 2021-04-22 op static const char *
218 bfa33dbe 2021-04-22 op sub_path_common(const char *s)
219 bfa33dbe 2021-04-22 op {
220 bfa33dbe 2021-04-22 op for (;;) {
221 bfa33dbe 2021-04-22 op if (*s != '/')
222 bfa33dbe 2021-04-22 op return s;
223 bfa33dbe 2021-04-22 op s++;
224 bfa33dbe 2021-04-22 op s = sub_segment(s);
225 bfa33dbe 2021-04-22 op }
226 bfa33dbe 2021-04-22 op }
227 bfa33dbe 2021-04-22 op
228 bfa33dbe 2021-04-22 op
229 bfa33dbe 2021-04-22 op /* parse fns */
230 bfa33dbe 2021-04-22 op
231 bfa33dbe 2021-04-22 op /*
232 bfa33dbe 2021-04-22 op * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
233 bfa33dbe 2021-04-22 op */
234 bfa33dbe 2021-04-22 op static const char *
235 bfa33dbe 2021-04-22 op parse_scheme(const char *s, struct phos_uri *parsed)
236 bfa33dbe 2021-04-22 op {
237 bfa33dbe 2021-04-22 op const char *start = s;
238 bfa33dbe 2021-04-22 op size_t len;
239 bfa33dbe 2021-04-22 op
240 bfa33dbe 2021-04-22 op if (!isalpha(*s))
241 bfa33dbe 2021-04-22 op return NULL;
242 bfa33dbe 2021-04-22 op
243 bfa33dbe 2021-04-22 op while (*s != '\0') {
244 bfa33dbe 2021-04-22 op if (isalpha(*s) ||
245 bfa33dbe 2021-04-22 op isdigit(*s) ||
246 bfa33dbe 2021-04-22 op *s == '+' ||
247 bfa33dbe 2021-04-22 op *s == '-' ||
248 bfa33dbe 2021-04-22 op *s == '.')
249 bfa33dbe 2021-04-22 op s++;
250 bfa33dbe 2021-04-22 op else
251 bfa33dbe 2021-04-22 op break;
252 bfa33dbe 2021-04-22 op }
253 bfa33dbe 2021-04-22 op
254 bfa33dbe 2021-04-22 op if (*s == '\0')
255 bfa33dbe 2021-04-22 op return NULL;
256 bfa33dbe 2021-04-22 op
257 bfa33dbe 2021-04-22 op len = s - start;
258 bfa33dbe 2021-04-22 op if (len >= sizeof(parsed->scheme))
259 bfa33dbe 2021-04-22 op return NULL;
260 bfa33dbe 2021-04-22 op
261 bfa33dbe 2021-04-22 op memcpy(parsed->scheme, start, len);
262 bfa33dbe 2021-04-22 op return s;
263 bfa33dbe 2021-04-22 op }
264 bfa33dbe 2021-04-22 op
265 bfa33dbe 2021-04-22 op /*
266 bfa33dbe 2021-04-22 op * host = IP-literal / IPv4address / reg-name
267 bfa33dbe 2021-04-22 op *
268 bfa33dbe 2021-04-22 op * rules IPv4address and reg-name are relaxed into parse_host_dummy.
269 bfa33dbe 2021-04-22 op */
270 bfa33dbe 2021-04-22 op static const char *
271 bfa33dbe 2021-04-22 op parse_host(const char *s, struct phos_uri *parsed)
272 bfa33dbe 2021-04-22 op {
273 bfa33dbe 2021-04-22 op const char *t;
274 bfa33dbe 2021-04-22 op size_t len;
275 bfa33dbe 2021-04-22 op
276 bfa33dbe 2021-04-22 op if ((t = sub_ip_literal(s)) != NULL ||
277 bfa33dbe 2021-04-22 op (t = sub_host_dummy(s)) != NULL) {
278 bfa33dbe 2021-04-22 op len = t - s;
279 bfa33dbe 2021-04-22 op if (len >= sizeof(parsed->scheme))
280 bfa33dbe 2021-04-22 op return NULL;
281 bfa33dbe 2021-04-22 op memcpy(parsed->host, s, len);
282 bfa33dbe 2021-04-22 op return t;
283 bfa33dbe 2021-04-22 op }
284 bfa33dbe 2021-04-22 op
285 bfa33dbe 2021-04-22 op return NULL;
286 bfa33dbe 2021-04-22 op }
287 bfa33dbe 2021-04-22 op
288 bfa33dbe 2021-04-22 op /*
289 bfa33dbe 2021-04-22 op * port = *digit
290 bfa33dbe 2021-04-22 op */
291 bfa33dbe 2021-04-22 op static const char *
292 bfa33dbe 2021-04-22 op parse_port(const char *s, struct phos_uri *parsed)
293 bfa33dbe 2021-04-22 op {
294 bfa33dbe 2021-04-22 op const char *errstr, *start = s;
295 bfa33dbe 2021-04-22 op size_t len;
296 bfa33dbe 2021-04-22 op
297 bfa33dbe 2021-04-22 op while (isdigit(*s))
298 bfa33dbe 2021-04-22 op s++;
299 bfa33dbe 2021-04-22 op
300 bfa33dbe 2021-04-22 op if (s == start)
301 bfa33dbe 2021-04-22 op return NULL;
302 bfa33dbe 2021-04-22 op
303 bfa33dbe 2021-04-22 op len = s - start;
304 bfa33dbe 2021-04-22 op if (len >= sizeof(parsed->port))
305 bfa33dbe 2021-04-22 op return NULL;
306 bfa33dbe 2021-04-22 op
307 bfa33dbe 2021-04-22 op memcpy(parsed->port, start, len);
308 bfa33dbe 2021-04-22 op
309 bfa33dbe 2021-04-22 op parsed->dec_port = strtonum(parsed->port, 0, 65535, &errstr);
310 bfa33dbe 2021-04-22 op if (errstr != NULL)
311 bfa33dbe 2021-04-22 op return NULL;
312 bfa33dbe 2021-04-22 op
313 bfa33dbe 2021-04-22 op return s;
314 bfa33dbe 2021-04-22 op }
315 bfa33dbe 2021-04-22 op
316 bfa33dbe 2021-04-22 op /*
317 bfa33dbe 2021-04-22 op * authority = host [ ":" port ]
318 bfa33dbe 2021-04-22 op * (yep, blatantly ignore the userinfo stuff -- not relevant for Gemini)
319 bfa33dbe 2021-04-22 op */
320 bfa33dbe 2021-04-22 op static const char *
321 bfa33dbe 2021-04-22 op parse_authority(const char *s, struct phos_uri *parsed)
322 bfa33dbe 2021-04-22 op {
323 bfa33dbe 2021-04-22 op if ((s = parse_host(s, parsed)) == NULL)
324 bfa33dbe 2021-04-22 op return NULL;
325 bfa33dbe 2021-04-22 op
326 bfa33dbe 2021-04-22 op if (*s == ':') {
327 bfa33dbe 2021-04-22 op s++;
328 bfa33dbe 2021-04-22 op return parse_port(s, parsed);
329 bfa33dbe 2021-04-22 op }
330 bfa33dbe 2021-04-22 op
331 bfa33dbe 2021-04-22 op return s;
332 bfa33dbe 2021-04-22 op }
333 bfa33dbe 2021-04-22 op
334 bfa33dbe 2021-04-22 op static inline const char *
335 bfa33dbe 2021-04-22 op set_path(const char *start, const char *end, struct phos_uri *parsed)
336 bfa33dbe 2021-04-22 op {
337 bfa33dbe 2021-04-22 op size_t len;
338 bfa33dbe 2021-04-22 op
339 bfa33dbe 2021-04-22 op if (end == NULL)
340 bfa33dbe 2021-04-22 op return NULL;
341 bfa33dbe 2021-04-22 op
342 bfa33dbe 2021-04-22 op len = end - start;
343 bfa33dbe 2021-04-22 op if (len >= sizeof(parsed->path))
344 bfa33dbe 2021-04-22 op return NULL;
345 bfa33dbe 2021-04-22 op memcpy(parsed->path, start, len);
346 bfa33dbe 2021-04-22 op return end;
347 bfa33dbe 2021-04-22 op }
348 bfa33dbe 2021-04-22 op
349 bfa33dbe 2021-04-22 op /*
350 bfa33dbe 2021-04-22 op * path-abempty = *( "/" segment )
351 bfa33dbe 2021-04-22 op */
352 bfa33dbe 2021-04-22 op static const char *
353 bfa33dbe 2021-04-22 op parse_path_abempty(const char *s, struct phos_uri *parsed)
354 bfa33dbe 2021-04-22 op {
355 bfa33dbe 2021-04-22 op const char *t;
356 bfa33dbe 2021-04-22 op
357 bfa33dbe 2021-04-22 op t = sub_path_common(s);
358 bfa33dbe 2021-04-22 op return set_path(s, t, parsed);
359 bfa33dbe 2021-04-22 op }
360 bfa33dbe 2021-04-22 op
361 bfa33dbe 2021-04-22 op /*
362 bfa33dbe 2021-04-22 op * path-absolute = "/" [ segment-nz *( "/" segment ) ]
363 bfa33dbe 2021-04-22 op */
364 bfa33dbe 2021-04-22 op static const char *
365 bfa33dbe 2021-04-22 op parse_path_absolute(const char *s, struct phos_uri *parsed)
366 bfa33dbe 2021-04-22 op {
367 bfa33dbe 2021-04-22 op const char *t, *start = s;
368 bfa33dbe 2021-04-22 op
369 bfa33dbe 2021-04-22 op if (*s != '/')
370 bfa33dbe 2021-04-22 op return NULL;
371 bfa33dbe 2021-04-22 op
372 bfa33dbe 2021-04-22 op s++;
373 bfa33dbe 2021-04-22 op if ((t = sub_segment_nz(s)) == NULL)
374 bfa33dbe 2021-04-22 op return set_path(start, s, parsed);
375 bfa33dbe 2021-04-22 op
376 bfa33dbe 2021-04-22 op s = sub_path_common(t);
377 bfa33dbe 2021-04-22 op return set_path(start, s, parsed);
378 bfa33dbe 2021-04-22 op }
379 bfa33dbe 2021-04-22 op
380 bfa33dbe 2021-04-22 op /*
381 bfa33dbe 2021-04-22 op * path-noscheme = segment-nz-nc *( "/" segment )
382 bfa33dbe 2021-04-22 op */
383 bfa33dbe 2021-04-22 op static const char *
384 bfa33dbe 2021-04-22 op parse_path_noscheme(const char *s, struct phos_uri *parsed)
385 bfa33dbe 2021-04-22 op {
386 bfa33dbe 2021-04-22 op const char *start = s;
387 bfa33dbe 2021-04-22 op
388 bfa33dbe 2021-04-22 op if ((s = sub_segment_nz_nc(s)) == NULL)
389 bfa33dbe 2021-04-22 op return NULL;
390 bfa33dbe 2021-04-22 op s = sub_path_common(s);
391 bfa33dbe 2021-04-22 op return set_path(start, s, parsed);
392 bfa33dbe 2021-04-22 op }
393 bfa33dbe 2021-04-22 op
394 bfa33dbe 2021-04-22 op /*
395 bfa33dbe 2021-04-22 op * path-rootless = segment-nz *( "/" segment )
396 bfa33dbe 2021-04-22 op */
397 bfa33dbe 2021-04-22 op static const char *
398 bfa33dbe 2021-04-22 op parse_path_rootless(const char *s, struct phos_uri *parsed)
399 bfa33dbe 2021-04-22 op {
400 bfa33dbe 2021-04-22 op const char *start = s;
401 bfa33dbe 2021-04-22 op
402 bfa33dbe 2021-04-22 op if ((s = sub_segment_nz(s)) == NULL)
403 bfa33dbe 2021-04-22 op return NULL;
404 bfa33dbe 2021-04-22 op s = sub_path_common(s);
405 bfa33dbe 2021-04-22 op return set_path(start, s, parsed);
406 bfa33dbe 2021-04-22 op }
407 bfa33dbe 2021-04-22 op
408 bfa33dbe 2021-04-22 op /*
409 bfa33dbe 2021-04-22 op * path-empty = 0<pchar>
410 bfa33dbe 2021-04-22 op */
411 bfa33dbe 2021-04-22 op static const char *
412 bfa33dbe 2021-04-22 op parse_path_empty(const char *s, struct phos_uri *parsed)
413 bfa33dbe 2021-04-22 op {
414 bfa33dbe 2021-04-22 op return s;
415 bfa33dbe 2021-04-22 op }
416 bfa33dbe 2021-04-22 op
417 bfa33dbe 2021-04-22 op /*
418 bfa33dbe 2021-04-22 op * hier-part = "//" authority path-abempty
419 bfa33dbe 2021-04-22 op * / path-absolute
420 bfa33dbe 2021-04-22 op * / path-rootless
421 bfa33dbe 2021-04-22 op * / path-empty
422 bfa33dbe 2021-04-22 op */
423 bfa33dbe 2021-04-22 op static const char *
424 bfa33dbe 2021-04-22 op parse_hier_part(const char *s, struct phos_uri *parsed)
425 bfa33dbe 2021-04-22 op {
426 bfa33dbe 2021-04-22 op const char *t;
427 bfa33dbe 2021-04-22 op
428 bfa33dbe 2021-04-22 op if (s[0] == '/' && s[1] == '/') {
429 bfa33dbe 2021-04-22 op s += 2;
430 bfa33dbe 2021-04-22 op if ((s = parse_authority(s, parsed)) == NULL)
431 bfa33dbe 2021-04-22 op return NULL;
432 bfa33dbe 2021-04-22 op return parse_path_abempty(s, parsed);
433 bfa33dbe 2021-04-22 op }
434 bfa33dbe 2021-04-22 op
435 bfa33dbe 2021-04-22 op if ((t = parse_path_absolute(s, parsed)) != NULL)
436 bfa33dbe 2021-04-22 op return t;
437 bfa33dbe 2021-04-22 op
438 bfa33dbe 2021-04-22 op if ((t = parse_path_rootless(s, parsed)) != NULL)
439 bfa33dbe 2021-04-22 op return t;
440 bfa33dbe 2021-04-22 op
441 bfa33dbe 2021-04-22 op return parse_path_empty(s, parsed);
442 bfa33dbe 2021-04-22 op }
443 bfa33dbe 2021-04-22 op
444 bfa33dbe 2021-04-22 op /*
445 bfa33dbe 2021-04-22 op * query = *( pchar / "/" / "?" )
446 bfa33dbe 2021-04-22 op */
447 bfa33dbe 2021-04-22 op static const char *
448 bfa33dbe 2021-04-22 op parse_query(const char *s, struct phos_uri *parsed)
449 bfa33dbe 2021-04-22 op {
450 bfa33dbe 2021-04-22 op const char *t, *start = s;
451 bfa33dbe 2021-04-22 op size_t len;
452 bfa33dbe 2021-04-22 op
453 bfa33dbe 2021-04-22 op while (*s != '\0') {
454 bfa33dbe 2021-04-22 op if (*s == '/' || *s == '?') {
455 bfa33dbe 2021-04-22 op s++;
456 bfa33dbe 2021-04-22 op continue;
457 bfa33dbe 2021-04-22 op }
458 bfa33dbe 2021-04-22 op
459 bfa33dbe 2021-04-22 op if ((t = sub_pchar(s)) == NULL)
460 bfa33dbe 2021-04-22 op break;
461 bfa33dbe 2021-04-22 op s = t;
462 bfa33dbe 2021-04-22 op }
463 bfa33dbe 2021-04-22 op
464 bfa33dbe 2021-04-22 op len = s - start;
465 bfa33dbe 2021-04-22 op if (len >= sizeof(parsed->query))
466 bfa33dbe 2021-04-22 op return NULL;
467 bfa33dbe 2021-04-22 op
468 bfa33dbe 2021-04-22 op memcpy(parsed->query, start, len);
469 bfa33dbe 2021-04-22 op return s;
470 bfa33dbe 2021-04-22 op }
471 bfa33dbe 2021-04-22 op
472 bfa33dbe 2021-04-22 op /*
473 bfa33dbe 2021-04-22 op * fragment = *( pchar / "/" / "?" )
474 bfa33dbe 2021-04-22 op */
475 bfa33dbe 2021-04-22 op static const char *
476 bfa33dbe 2021-04-22 op parse_fragment(const char *s, struct phos_uri *parsed)
477 bfa33dbe 2021-04-22 op {
478 bfa33dbe 2021-04-22 op const char *start = s;
479 bfa33dbe 2021-04-22 op size_t len;
480 bfa33dbe 2021-04-22 op
481 bfa33dbe 2021-04-22 op for (;;) {
482 bfa33dbe 2021-04-22 op if (*s == '\0')
483 bfa33dbe 2021-04-22 op break;
484 bfa33dbe 2021-04-22 op
485 bfa33dbe 2021-04-22 op if (*s == '/' || *s == '?') {
486 bfa33dbe 2021-04-22 op s++;
487 bfa33dbe 2021-04-22 op continue;
488 bfa33dbe 2021-04-22 op }
489 bfa33dbe 2021-04-22 op
490 bfa33dbe 2021-04-22 op if ((s = sub_pchar(s)) == NULL)
491 bfa33dbe 2021-04-22 op return NULL;
492 bfa33dbe 2021-04-22 op }
493 bfa33dbe 2021-04-22 op
494 bfa33dbe 2021-04-22 op len = s - start;
495 bfa33dbe 2021-04-22 op if (len >= sizeof(parsed->fragment))
496 bfa33dbe 2021-04-22 op return NULL;
497 bfa33dbe 2021-04-22 op
498 bfa33dbe 2021-04-22 op memcpy(parsed->fragment, start, len);
499 bfa33dbe 2021-04-22 op return s;
500 bfa33dbe 2021-04-22 op }
501 bfa33dbe 2021-04-22 op
502 bfa33dbe 2021-04-22 op /*
503 bfa33dbe 2021-04-22 op * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
504 bfa33dbe 2021-04-22 op */
505 bfa33dbe 2021-04-22 op static const char *
506 bfa33dbe 2021-04-22 op parse_uri(const char *s, struct phos_uri *parsed)
507 bfa33dbe 2021-04-22 op {
508 bfa33dbe 2021-04-22 op if ((s = parse_scheme(s, parsed)) == NULL)
509 bfa33dbe 2021-04-22 op return NULL;
510 bfa33dbe 2021-04-22 op
511 bfa33dbe 2021-04-22 op if (*s != ':')
512 bfa33dbe 2021-04-22 op return NULL;
513 bfa33dbe 2021-04-22 op
514 bfa33dbe 2021-04-22 op s++;
515 bfa33dbe 2021-04-22 op if ((s = parse_hier_part(s, parsed)) == NULL)
516 bfa33dbe 2021-04-22 op return NULL;
517 bfa33dbe 2021-04-22 op
518 bfa33dbe 2021-04-22 op if (*s == '?') {
519 bfa33dbe 2021-04-22 op s++;
520 bfa33dbe 2021-04-22 op if ((s = parse_query(s, parsed)) == NULL)
521 bfa33dbe 2021-04-22 op return NULL;
522 bfa33dbe 2021-04-22 op }
523 bfa33dbe 2021-04-22 op
524 bfa33dbe 2021-04-22 op if (*s == '#') {
525 bfa33dbe 2021-04-22 op s++;
526 bfa33dbe 2021-04-22 op if ((s = parse_fragment(s, parsed)) == NULL)
527 bfa33dbe 2021-04-22 op return NULL;
528 bfa33dbe 2021-04-22 op }
529 bfa33dbe 2021-04-22 op
530 bfa33dbe 2021-04-22 op return s;
531 bfa33dbe 2021-04-22 op }
532 bfa33dbe 2021-04-22 op
533 bfa33dbe 2021-04-22 op /*
534 bfa33dbe 2021-04-22 op * relative-part = "//" authority path-abempty
535 bfa33dbe 2021-04-22 op * / path-absolute
536 bfa33dbe 2021-04-22 op * / path-noscheme
537 bfa33dbe 2021-04-22 op * / path-empty
538 bfa33dbe 2021-04-22 op */
539 bfa33dbe 2021-04-22 op static const char *
540 bfa33dbe 2021-04-22 op parse_relative_part(const char *s, struct phos_uri *parsed)
541 bfa33dbe 2021-04-22 op {
542 bfa33dbe 2021-04-22 op const char *t;
543 bfa33dbe 2021-04-22 op
544 bfa33dbe 2021-04-22 op if (s[0] == '/' && s[1] == '/') {
545 bfa33dbe 2021-04-22 op s += 2;
546 bfa33dbe 2021-04-22 op if ((s = parse_authority(s, parsed)) == NULL)
547 bfa33dbe 2021-04-22 op return NULL;
548 bfa33dbe 2021-04-22 op return parse_path_abempty(s, parsed);
549 bfa33dbe 2021-04-22 op }
550 bfa33dbe 2021-04-22 op
551 bfa33dbe 2021-04-22 op if ((t = parse_path_absolute(s, parsed)) != NULL)
552 bfa33dbe 2021-04-22 op return t;
553 bfa33dbe 2021-04-22 op
554 bfa33dbe 2021-04-22 op if ((t = parse_path_noscheme(s, parsed)) != NULL)
555 bfa33dbe 2021-04-22 op return t;
556 bfa33dbe 2021-04-22 op
557 bfa33dbe 2021-04-22 op return parse_path_empty(s, parsed);
558 bfa33dbe 2021-04-22 op }
559 bfa33dbe 2021-04-22 op
560 bfa33dbe 2021-04-22 op /*
561 bfa33dbe 2021-04-22 op * relative-ref = relative-part [ "?" query ] [ "#" fragment ]
562 bfa33dbe 2021-04-22 op */
563 bfa33dbe 2021-04-22 op static const char *
564 bfa33dbe 2021-04-22 op parse_relative_ref(const char *s, struct phos_uri *parsed)
565 bfa33dbe 2021-04-22 op {
566 bfa33dbe 2021-04-22 op if ((s = parse_relative_part(s, parsed)) == NULL)
567 bfa33dbe 2021-04-22 op return NULL;
568 bfa33dbe 2021-04-22 op
569 bfa33dbe 2021-04-22 op if (*s == '?') {
570 bfa33dbe 2021-04-22 op s++;
571 bfa33dbe 2021-04-22 op if ((s = parse_query(s, parsed)) == NULL)
572 bfa33dbe 2021-04-22 op return NULL;
573 bfa33dbe 2021-04-22 op }
574 bfa33dbe 2021-04-22 op
575 bfa33dbe 2021-04-22 op if (*s == '#') {
576 bfa33dbe 2021-04-22 op s++;
577 bfa33dbe 2021-04-22 op if ((s = parse_fragment(s, parsed)) == NULL)
578 bfa33dbe 2021-04-22 op return NULL;
579 bfa33dbe 2021-04-22 op }
580 bfa33dbe 2021-04-22 op
581 bfa33dbe 2021-04-22 op return s;
582 bfa33dbe 2021-04-22 op }
583 bfa33dbe 2021-04-22 op
584 bfa33dbe 2021-04-22 op /*
585 bfa33dbe 2021-04-22 op * URI-reference = URI / relative-ref
586 bfa33dbe 2021-04-22 op */
587 bfa33dbe 2021-04-22 op static const char *
588 bfa33dbe 2021-04-22 op parse_uri_reference(const char *s, struct phos_uri *parsed)
589 bfa33dbe 2021-04-22 op {
590 bfa33dbe 2021-04-22 op const char *t;
591 bfa33dbe 2021-04-22 op
592 bfa33dbe 2021-04-22 op if ((t = parse_uri(s, parsed)) != NULL)
593 bfa33dbe 2021-04-22 op return t;
594 bfa33dbe 2021-04-22 op memset(parsed, 0, sizeof(*parsed));
595 bfa33dbe 2021-04-22 op return parse_relative_ref(s, parsed);
596 bfa33dbe 2021-04-22 op }
597 bfa33dbe 2021-04-22 op
598 bfa33dbe 2021-04-22 op
599 bfa33dbe 2021-04-22 op /*
600 bfa33dbe 2021-04-22 op * absolute-URI = scheme ":" hier-part [ "?" query ]
601 bfa33dbe 2021-04-22 op */
602 bfa33dbe 2021-04-22 op static const char *
603 bfa33dbe 2021-04-22 op parse_absolute_uri(const char *s, struct phos_uri *parsed)
604 bfa33dbe 2021-04-22 op {
605 bfa33dbe 2021-04-22 op if ((s = parse_scheme(s, parsed)) == NULL)
606 bfa33dbe 2021-04-22 op return NULL;
607 bfa33dbe 2021-04-22 op
608 bfa33dbe 2021-04-22 op if (*s != ':')
609 bfa33dbe 2021-04-22 op return NULL;
610 bfa33dbe 2021-04-22 op
611 bfa33dbe 2021-04-22 op s++;
612 bfa33dbe 2021-04-22 op if ((s = parse_hier_part(s, parsed)) == NULL)
613 bfa33dbe 2021-04-22 op return NULL;
614 bfa33dbe 2021-04-22 op
615 bfa33dbe 2021-04-22 op if (*s == '?') {
616 bfa33dbe 2021-04-22 op s++;
617 bfa33dbe 2021-04-22 op if ((s = parse_query(s, parsed)) == NULL)
618 bfa33dbe 2021-04-22 op return NULL;
619 bfa33dbe 2021-04-22 op }
620 bfa33dbe 2021-04-22 op
621 bfa33dbe 2021-04-22 op return s;
622 bfa33dbe 2021-04-22 op }
623 bfa33dbe 2021-04-22 op
624 bfa33dbe 2021-04-22 op
625 bfa33dbe 2021-04-22 op /* normalizing fns */
626 bfa33dbe 2021-04-22 op
627 bfa33dbe 2021-04-22 op static int
628 bfa33dbe 2021-04-22 op hasprefix(const char *str, const char *prfx)
629 bfa33dbe 2021-04-22 op {
630 bfa33dbe 2021-04-22 op for (; *str == *prfx && *prfx != '\0'; str++, prfx++)
631 bfa33dbe 2021-04-22 op ;
632 bfa33dbe 2021-04-22 op
633 bfa33dbe 2021-04-22 op return *prfx == '\0';
634 bfa33dbe 2021-04-22 op }
635 bfa33dbe 2021-04-22 op
636 bfa33dbe 2021-04-22 op static char *
637 bfa33dbe 2021-04-22 op dotdot(char *point, char *start)
638 bfa33dbe 2021-04-22 op {
639 bfa33dbe 2021-04-22 op char *t;
640 bfa33dbe 2021-04-22 op
641 bfa33dbe 2021-04-22 op for (t = point-1; t > start; --t) {
642 bfa33dbe 2021-04-22 op if (*t == '/')
643 bfa33dbe 2021-04-22 op break;
644 bfa33dbe 2021-04-22 op }
645 bfa33dbe 2021-04-22 op if (t < start)
646 bfa33dbe 2021-04-22 op t = start;
647 bfa33dbe 2021-04-22 op
648 bfa33dbe 2021-04-22 op memmove(t, point, strlen(point)+1);
649 bfa33dbe 2021-04-22 op return t;
650 bfa33dbe 2021-04-22 op }
651 bfa33dbe 2021-04-22 op
652 bfa33dbe 2021-04-22 op /*
653 bfa33dbe 2021-04-22 op * This is the "Remove Dot Segments" straight outta RFC3986, section
654 bfa33dbe 2021-04-22 op * 5.2.4
655 bfa33dbe 2021-04-22 op */
656 bfa33dbe 2021-04-22 op static void
657 bfa33dbe 2021-04-22 op path_clean(struct phos_uri *uri)
658 bfa33dbe 2021-04-22 op {
659 bfa33dbe 2021-04-22 op char *in = uri->path;
660 bfa33dbe 2021-04-22 op
661 bfa33dbe 2021-04-22 op while (in != NULL && *in != '\0') {
662 bfa33dbe 2021-04-22 op assert(in >= uri->path);
663 bfa33dbe 2021-04-22 op
664 bfa33dbe 2021-04-22 op /* A) drop leading ../ or ./ */
665 bfa33dbe 2021-04-22 op if (hasprefix(in, "../"))
666 bfa33dbe 2021-04-22 op memmove(in, &in[3], strlen(&in[3])+1);
667 bfa33dbe 2021-04-22 op else if (hasprefix(in, "./"))
668 bfa33dbe 2021-04-22 op memmove(in, &in[2], strlen(&in[2])+1);
669 bfa33dbe 2021-04-22 op
670 bfa33dbe 2021-04-22 op /* B) replace /./ or /. with / */
671 bfa33dbe 2021-04-22 op else if (hasprefix(in, "/./"))
672 bfa33dbe 2021-04-22 op memmove(&in[1], &in[3], strlen(&in[3])+1);
673 bfa33dbe 2021-04-22 op else if (!strcmp(in, "/."))
674 bfa33dbe 2021-04-22 op in[1] = '\0';
675 bfa33dbe 2021-04-22 op
676 bfa33dbe 2021-04-22 op /* C) resolve dot-dot */
677 bfa33dbe 2021-04-22 op else if (hasprefix(in, "/../")) {
678 bfa33dbe 2021-04-22 op in = dotdot(in, uri->path);
679 bfa33dbe 2021-04-22 op memmove(&in[1], &in[4], strlen(&in[4])+1);
680 bfa33dbe 2021-04-22 op } else if (!strcmp(in, "/..")) {
681 bfa33dbe 2021-04-22 op in = dotdot(in, uri->path);
682 bfa33dbe 2021-04-22 op in[1] = '\0';
683 bfa33dbe 2021-04-22 op break;
684 bfa33dbe 2021-04-22 op }
685 bfa33dbe 2021-04-22 op
686 bfa33dbe 2021-04-22 op /* D */
687 bfa33dbe 2021-04-22 op else if (!strcmp(in, "."))
688 bfa33dbe 2021-04-22 op *in = '\0';
689 bfa33dbe 2021-04-22 op else if (!strcmp(in, ".."))
690 bfa33dbe 2021-04-22 op *in = '\0';
691 bfa33dbe 2021-04-22 op
692 bfa33dbe 2021-04-22 op /* E */
693 bfa33dbe 2021-04-22 op else
694 bfa33dbe 2021-04-22 op in = strchr(in+1, '/');
695 bfa33dbe 2021-04-22 op }
696 bfa33dbe 2021-04-22 op }
697 bfa33dbe 2021-04-22 op
698 bfa33dbe 2021-04-22 op /*
699 bfa33dbe 2021-04-22 op * see RFC3986 5.3.3 "Merge Paths".
700 bfa33dbe 2021-04-22 op */
701 bfa33dbe 2021-04-22 op static int
702 bfa33dbe 2021-04-22 op merge_path(struct phos_uri *ret, const struct phos_uri *base,
703 bfa33dbe 2021-04-22 op const struct phos_uri *ref)
704 bfa33dbe 2021-04-22 op {
705 bfa33dbe 2021-04-22 op const char *s;
706 bfa33dbe 2021-04-22 op size_t len;
707 bfa33dbe 2021-04-22 op
708 bfa33dbe 2021-04-22 op len = sizeof(ret->path);
709 bfa33dbe 2021-04-22 op
710 bfa33dbe 2021-04-22 op s = strrchr(base->path, '/');
711 bfa33dbe 2021-04-22 op if ((*base->host != '\0' && *base->path == '\0') || s == NULL) {
712 bfa33dbe 2021-04-22 op strlcpy(ret->path, "/", len);
713 bfa33dbe 2021-04-22 op } else {
714 bfa33dbe 2021-04-22 op /* copy the / too */
715 bfa33dbe 2021-04-22 op memcpy(ret->path, base->path, s - base->path + 1);
716 bfa33dbe 2021-04-22 op }
717 bfa33dbe 2021-04-22 op
718 bfa33dbe 2021-04-22 op return strlcat(ret->path, ref->path, len) < len;
719 bfa33dbe 2021-04-22 op }
720 bfa33dbe 2021-04-22 op
721 bfa33dbe 2021-04-22 op
722 bfa33dbe 2021-04-22 op /* public interface */
723 bfa33dbe 2021-04-22 op
724 bfa33dbe 2021-04-22 op int
725 bfa33dbe 2021-04-22 op phos_parse_absolute_uri(const char *s, struct phos_uri *uri)
726 bfa33dbe 2021-04-22 op {
727 bfa33dbe 2021-04-22 op memset(uri, 0, sizeof(*uri));
728 bfa33dbe 2021-04-22 op
729 bfa33dbe 2021-04-22 op if ((s = parse_absolute_uri(s, uri)) == NULL)
730 bfa33dbe 2021-04-22 op return 0;
731 bfa33dbe 2021-04-22 op if (*s != '\0')
732 bfa33dbe 2021-04-22 op return 0;
733 bfa33dbe 2021-04-22 op path_clean(uri);
734 bfa33dbe 2021-04-22 op return 1;
735 bfa33dbe 2021-04-22 op }
736 bfa33dbe 2021-04-22 op
737 bfa33dbe 2021-04-22 op int
738 bfa33dbe 2021-04-22 op phos_parse_uri_reference(const char *s, struct phos_uri *uri)
739 bfa33dbe 2021-04-22 op {
740 bfa33dbe 2021-04-22 op memset(uri, 0, sizeof(*uri));
741 bfa33dbe 2021-04-22 op
742 bfa33dbe 2021-04-22 op if ((s = parse_uri_reference(s, uri)) == NULL)
743 bfa33dbe 2021-04-22 op return 0;
744 bfa33dbe 2021-04-22 op if (*s != '\0')
745 bfa33dbe 2021-04-22 op return 0;
746 bfa33dbe 2021-04-22 op path_clean(uri);
747 bfa33dbe 2021-04-22 op return 1;
748 bfa33dbe 2021-04-22 op }
749 bfa33dbe 2021-04-22 op
750 bfa33dbe 2021-04-22 op /*
751 bfa33dbe 2021-04-22 op * Implementation of the "transform references" algorithm from
752 bfa33dbe 2021-04-22 op * RFC3986, see 5.2.2.
753 bfa33dbe 2021-04-22 op *
754 bfa33dbe 2021-04-22 op * We expect base and ref to be URIs constructed by this library
755 bfa33dbe 2021-04-22 op * (because we emit only normalized URIs).
756 bfa33dbe 2021-04-22 op *
757 bfa33dbe 2021-04-22 op * ATM this is marked as private because:
758 bfa33dbe 2021-04-22 op * - let's say the URI is "."
759 bfa33dbe 2021-04-22 op * - one calls phos_parse_uri_references
760 bfa33dbe 2021-04-22 op * - it exists with success, but the path becomes ""
761 bfa33dbe 2021-04-22 op * - this routine does the right thing, but the outcome is not what expected.
762 bfa33dbe 2021-04-22 op *
763 bfa33dbe 2021-04-22 op * so users for now have to user resolve_uri_from_str, which parses
764 bfa33dbe 2021-04-22 op * the URI but not normalize it, and then call into us.
765 bfa33dbe 2021-04-22 op */
766 bfa33dbe 2021-04-22 op static int
767 bfa33dbe 2021-04-22 op phos_resolve_uri_from(const struct phos_uri *base, const struct phos_uri *ref,
768 bfa33dbe 2021-04-22 op struct phos_uri *ret)
769 bfa33dbe 2021-04-22 op {
770 bfa33dbe 2021-04-22 op memset(ret, 0, sizeof(*ret));
771 bfa33dbe 2021-04-22 op
772 bfa33dbe 2021-04-22 op if (*ref->scheme != '\0') {
773 bfa33dbe 2021-04-22 op strlcpy(ret->scheme, ref->scheme, sizeof(ret->scheme));
774 bfa33dbe 2021-04-22 op strlcpy(ret->host, ref->host, sizeof(ret->host));
775 bfa33dbe 2021-04-22 op strlcpy(ret->port, ref->port, sizeof(ret->port));
776 bfa33dbe 2021-04-22 op ret->dec_port = ret->dec_port;
777 bfa33dbe 2021-04-22 op strlcpy(ret->path, ref->path, sizeof(ret->path));
778 bfa33dbe 2021-04-22 op strlcpy(ret->query, ref->query, sizeof(ret->query));
779 bfa33dbe 2021-04-22 op } else {
780 bfa33dbe 2021-04-22 op if (*ref->host != '\0') {
781 bfa33dbe 2021-04-22 op strlcpy(ret->host, ref->host, sizeof(ret->host));
782 bfa33dbe 2021-04-22 op strlcpy(ret->port, ref->port, sizeof(ret->port));
783 bfa33dbe 2021-04-22 op ret->dec_port = ret->dec_port;
784 bfa33dbe 2021-04-22 op strlcpy(ret->path, ref->path, sizeof(ret->path));
785 bfa33dbe 2021-04-22 op strlcpy(ret->query, ref->query, sizeof(ret->query));
786 bfa33dbe 2021-04-22 op } else {
787 bfa33dbe 2021-04-22 op if (*ref->path == '\0') {
788 bfa33dbe 2021-04-22 op strlcpy(ret->path, base->path, sizeof(ret->path));
789 bfa33dbe 2021-04-22 op if (*ref->query != '\0')
790 bfa33dbe 2021-04-22 op strlcpy(ret->query, ref->query, sizeof(ret->query));
791 bfa33dbe 2021-04-22 op else
792 bfa33dbe 2021-04-22 op strlcpy(ret->query, base->query, sizeof(ret->query));
793 bfa33dbe 2021-04-22 op } else {
794 bfa33dbe 2021-04-22 op if (*ref->path == '/')
795 bfa33dbe 2021-04-22 op strlcpy(ret->path, ref->path, sizeof(ret->path));
796 bfa33dbe 2021-04-22 op else {
797 bfa33dbe 2021-04-22 op if (!merge_path(ret, base, ref))
798 bfa33dbe 2021-04-22 op return 0;
799 bfa33dbe 2021-04-22 op }
800 bfa33dbe 2021-04-22 op path_clean(ret);
801 bfa33dbe 2021-04-22 op
802 bfa33dbe 2021-04-22 op strlcpy(ret->query, ref->query, sizeof(ret->query));
803 bfa33dbe 2021-04-22 op }
804 bfa33dbe 2021-04-22 op
805 bfa33dbe 2021-04-22 op strlcpy(ret->host, base->host, sizeof(ret->host));
806 bfa33dbe 2021-04-22 op strlcpy(ret->port, base->port, sizeof(ret->port));
807 bfa33dbe 2021-04-22 op ret->dec_port = base->dec_port;
808 bfa33dbe 2021-04-22 op }
809 bfa33dbe 2021-04-22 op
810 bfa33dbe 2021-04-22 op strlcpy(ret->scheme, base->scheme, sizeof(ret->scheme));
811 bfa33dbe 2021-04-22 op }
812 bfa33dbe 2021-04-22 op
813 bfa33dbe 2021-04-22 op strlcpy(ret->fragment, ref->fragment, sizeof(ret->fragment));
814 bfa33dbe 2021-04-22 op
815 bfa33dbe 2021-04-22 op return 1;
816 bfa33dbe 2021-04-22 op }
817 bfa33dbe 2021-04-22 op
818 bfa33dbe 2021-04-22 op int
819 bfa33dbe 2021-04-22 op phos_resolve_uri_from_str(const struct phos_uri *base, const char *refstr,
820 bfa33dbe 2021-04-22 op struct phos_uri *ret)
821 bfa33dbe 2021-04-22 op {
822 bfa33dbe 2021-04-22 op struct phos_uri ref;
823 bfa33dbe 2021-04-22 op
824 bfa33dbe 2021-04-22 op memset(&ref, 0, sizeof(ref));
825 bfa33dbe 2021-04-22 op
826 bfa33dbe 2021-04-22 op if ((refstr = parse_uri_reference(refstr, &ref)) == NULL)
827 bfa33dbe 2021-04-22 op return 0;
828 bfa33dbe 2021-04-22 op
829 bfa33dbe 2021-04-22 op if (*refstr != '\0')
830 bfa33dbe 2021-04-22 op return 0;
831 bfa33dbe 2021-04-22 op
832 bfa33dbe 2021-04-22 op return phos_resolve_uri_from(base, &ref, ret);
833 bfa33dbe 2021-04-22 op }
834 bfa33dbe 2021-04-22 op
835 bfa33dbe 2021-04-22 op void
836 bfa33dbe 2021-04-22 op phos_uri_drop_empty_segments(struct phos_uri *uri)
837 bfa33dbe 2021-04-22 op {
838 bfa33dbe 2021-04-22 op char *i;
839 bfa33dbe 2021-04-22 op
840 bfa33dbe 2021-04-22 op for (i = uri->path; *i; ++i) {
841 bfa33dbe 2021-04-22 op if (*i == '/' && *(i+1) == '/') {
842 bfa33dbe 2021-04-22 op memmove(i, i+1, strlen(i)); /* move also the \0 */
843 bfa33dbe 2021-04-22 op i--;
844 4190a5c2 2021-04-24 op }
845 4190a5c2 2021-04-24 op }
846 4190a5c2 2021-04-24 op }
847 4190a5c2 2021-04-24 op
848 4190a5c2 2021-04-24 op int
849 4190a5c2 2021-04-24 op phos_uri_set_query(struct phos_uri *uri, const char *query)
850 4190a5c2 2021-04-24 op {
851 4190a5c2 2021-04-24 op char *out;
852 4190a5c2 2021-04-24 op int t;
853 4190a5c2 2021-04-24 op size_t len;
854 4190a5c2 2021-04-24 op
855 4190a5c2 2021-04-24 op len = sizeof(uri->query);
856 4190a5c2 2021-04-24 op out = uri->query;
857 4190a5c2 2021-04-24 op memset(uri->query, 0, len);
858 4190a5c2 2021-04-24 op
859 4190a5c2 2021-04-24 op for (; *query != '\0' && len > 0; ++query) {
860 4190a5c2 2021-04-24 op if (*query == '/' ||
861 4190a5c2 2021-04-24 op *query == '?' ||
862 4190a5c2 2021-04-24 op *query == ':' ||
863 4190a5c2 2021-04-24 op *query == '@' ||
864 4190a5c2 2021-04-24 op unreserved(*query) ||
865 4190a5c2 2021-04-24 op sub_delims(*query)) {
866 4190a5c2 2021-04-24 op *out++ = *query;
867 4190a5c2 2021-04-24 op len--;
868 4190a5c2 2021-04-24 op } else {
869 4190a5c2 2021-04-24 op if (len <= 4)
870 4190a5c2 2021-04-24 op break;
871 4190a5c2 2021-04-24 op len -= 3;
872 4190a5c2 2021-04-24 op *out++ = '%';
873 4190a5c2 2021-04-24 op t = *query;
874 4190a5c2 2021-04-24 op sprintf(out, "%02X", t);
875 4190a5c2 2021-04-24 op out += 2;
876 bfa33dbe 2021-04-22 op }
877 bfa33dbe 2021-04-22 op }
878 4190a5c2 2021-04-24 op
879 4190a5c2 2021-04-24 op return *query == '\0';
880 bfa33dbe 2021-04-22 op }
881 bfa33dbe 2021-04-22 op
882 bfa33dbe 2021-04-22 op int
883 bfa33dbe 2021-04-22 op phos_serialize_uri(const struct phos_uri *uri, char *buf, size_t len)
884 bfa33dbe 2021-04-22 op {
885 bfa33dbe 2021-04-22 op #define CAT(s) \
886 bfa33dbe 2021-04-22 op if (strlcat(buf, s, len) >= len) \
887 bfa33dbe 2021-04-22 op return 0;
888 bfa33dbe 2021-04-22 op
889 bfa33dbe 2021-04-22 op strlcpy(buf, "", len);
890 bfa33dbe 2021-04-22 op
891 bfa33dbe 2021-04-22 op if (*uri->scheme != '\0') {
892 bfa33dbe 2021-04-22 op CAT(uri->scheme);
893 bfa33dbe 2021-04-22 op CAT(":");
894 bfa33dbe 2021-04-22 op }
895 bfa33dbe 2021-04-22 op
896 29c139d5 2021-08-13 op if (*uri->host != '\0' || strcmp(uri->scheme, "file") == 0) {
897 29c139d5 2021-08-13 op /*
898 29c139d5 2021-08-13 op * The file URI scheme has a quirk that even if a
899 29c139d5 2021-08-13 op * hostname is not present, we still have to append
900 29c139d5 2021-08-13 op * the two slashes. This is why we have
901 29c139d5 2021-08-13 op * file:///etc/hosts and not file:/etc/hosts
902 29c139d5 2021-08-13 op */
903 bfa33dbe 2021-04-22 op CAT("//");
904 bfa33dbe 2021-04-22 op CAT(uri->host);
905 bfa33dbe 2021-04-22 op }
906 bfa33dbe 2021-04-22 op
907 81d1e61a 2021-04-25 op if (*uri->port != '\0' && strcmp(uri->port, "1965")) {
908 81d1e61a 2021-04-25 op CAT(":");
909 81d1e61a 2021-04-25 op CAT(uri->port);
910 81d1e61a 2021-04-25 op }
911 81d1e61a 2021-04-25 op
912 bfa33dbe 2021-04-22 op CAT(uri->path);
913 bfa33dbe 2021-04-22 op
914 bfa33dbe 2021-04-22 op if (*uri->query != '\0') {
915 bfa33dbe 2021-04-22 op CAT("?");
916 bfa33dbe 2021-04-22 op CAT(uri->query);
917 bfa33dbe 2021-04-22 op }
918 bfa33dbe 2021-04-22 op
919 bfa33dbe 2021-04-22 op if (*uri->fragment) {
920 bfa33dbe 2021-04-22 op CAT("#");
921 bfa33dbe 2021-04-22 op CAT(uri->fragment);
922 bfa33dbe 2021-04-22 op }
923 bfa33dbe 2021-04-22 op
924 bfa33dbe 2021-04-22 op return 1;
925 bfa33dbe 2021-04-22 op
926 bfa33dbe 2021-04-22 op #undef CAT
927 bfa33dbe 2021-04-22 op }