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