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