1 /**
2 * @file uri.c Uniform Resource Identifier (URI) module
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_fmt.h>
9 #include <re_mem.h>
10 #include <re_list.h>
11 #include <re_sa.h>
12 #include <re_uri.h>
13
14
15 /**
16 * Encode a URI object
17 *
18 * @param pf Print function to encode into
19 * @param uri URI object
20 *
21 * @return 0 if success, otherwise errorcode
22 */
uri_encode(struct re_printf * pf,const struct uri * uri)23 int uri_encode(struct re_printf *pf, const struct uri *uri)
24 {
25 int err;
26
27 if (!uri)
28 return 0;
29
30 if (!pl_isset(&uri->scheme) || !pl_isset(&uri->host))
31 return EINVAL;
32
33 err = re_hprintf(pf, "%r:", &uri->scheme);
34 if (err)
35 return err;
36
37 if (pl_isset(&uri->user)) {
38 err = re_hprintf(pf, "%r", &uri->user);
39
40 if (pl_isset(&uri->password))
41 err |= re_hprintf(pf, ":%r", &uri->password);
42
43 err |= pf->vph("@", 1, pf->arg);
44
45 if (err)
46 return err;
47 }
48
49 /* The IPv6 address is delimited by '[' and ']' */
50 switch (uri->af) {
51
52 #ifdef HAVE_INET6
53 case AF_INET6:
54 err = re_hprintf(pf, "[%r]", &uri->host);
55 break;
56 #endif
57
58 default:
59 err = re_hprintf(pf, "%r", &uri->host);
60 break;
61 }
62 if (err)
63 return err;
64
65 if (uri->port)
66 err = re_hprintf(pf, ":%u", uri->port);
67
68 err |= re_hprintf(pf, "%r%r", &uri->params, &uri->headers);
69
70 return err;
71 }
72
73
74 /**
75 * Decode host-port portion of a URI (if present)
76 *
77 * @return 0 if success, otherwise errorcode
78 */
decode_hostport(const struct pl * hostport,struct pl * host,struct pl * port)79 static int decode_hostport(const struct pl *hostport, struct pl *host,
80 struct pl *port)
81 {
82 /* Try IPv6 first */
83 if (!re_regex(hostport->p, hostport->l, "\\[[0-9a-f:]+\\][:]*[0-9]*",
84 host, NULL, port))
85 return 0;
86
87 /* Then non-IPv6 host */
88 return re_regex(hostport->p, hostport->l, "[^:]+[:]*[0-9]*",
89 host, NULL, port);
90 }
91
92
93 /**
94 * Decode a pointer-length object into a URI object
95 *
96 * @param uri URI object
97 * @param pl Pointer-length object to decode from
98 *
99 * @return 0 if success, otherwise errorcode
100 */
uri_decode(struct uri * uri,const struct pl * pl)101 int uri_decode(struct uri *uri, const struct pl *pl)
102 {
103 struct sa addr;
104 struct pl port = PL_INIT;
105 struct pl hostport;
106 int err;
107
108 if (!uri || !pl)
109 return EINVAL;
110
111 memset(uri, 0, sizeof(*uri));
112 if (0 == re_regex(pl->p, pl->l,
113 "[^:]+:[^@:]*[:]*[^@]*@[^;? ]+[^?]*[^]*",
114 &uri->scheme, &uri->user, NULL, &uri->password,
115 &hostport, &uri->params, &uri->headers)) {
116
117 if (0 == decode_hostport(&hostport, &uri->host, &port))
118 goto out;
119 }
120
121 memset(uri, 0, sizeof(*uri));
122 err = re_regex(pl->p, pl->l, "[^:]+:[^;? ]+[^?]*[^]*",
123 &uri->scheme, &hostport, &uri->params, &uri->headers);
124 if (0 == err) {
125 err = decode_hostport(&hostport, &uri->host, &port);
126 if (0 == err)
127 goto out;
128 }
129
130 return err;
131
132 out:
133 /* Cache host address family */
134 if (0 == sa_set(&addr, &uri->host, 0))
135 uri->af = sa_af(&addr);
136 else
137 uri->af = AF_UNSPEC;
138
139 if (pl_isset(&port))
140 uri->port = (uint16_t)pl_u32(&port);
141
142 return 0;
143 }
144
145
146 /**
147 * Get a URI parameter and possibly the value of it
148 *
149 * @param pl Pointer-length string containing parameters
150 * @param pname URI Parameter name
151 * @param pvalue Returned URI Parameter value
152 *
153 * @return 0 if success, otherwise errorcode
154 */
uri_param_get(const struct pl * pl,const struct pl * pname,struct pl * pvalue)155 int uri_param_get(const struct pl *pl, const struct pl *pname,
156 struct pl *pvalue)
157 {
158 char expr[128];
159
160 if (!pl || !pname || !pvalue)
161 return EINVAL;
162
163 (void)re_snprintf(expr, sizeof(expr), ";%r[=]*[^;]*", pname);
164
165 return re_regex(pl->p, pl->l, expr, NULL, pvalue);
166 }
167
168
169 /**
170 * Call the apply handler for each URI Parameter
171 *
172 * @param pl Pointer-length string containing parameters
173 * @param ah Apply handler
174 * @param arg Handler argument
175 *
176 * @return 0 if success, otherwise errorcode (returned from handler)
177 */
uri_params_apply(const struct pl * pl,uri_apply_h * ah,void * arg)178 int uri_params_apply(const struct pl *pl, uri_apply_h *ah, void *arg)
179 {
180 struct pl plr, pname, eq, pvalue;
181 int err = 0;
182
183 if (!pl || !ah)
184 return EINVAL;
185
186 plr = *pl;
187
188 while (plr.l > 0) {
189
190 err = re_regex(plr.p, plr.l, ";[^;=]+[=]*[^;]*",
191 &pname, &eq, &pvalue);
192 if (err)
193 break;
194
195 pl_advance(&plr, 1 + pname.l + eq.l + pvalue.l);
196
197 err = ah(&pname, &pvalue, arg);
198 if (err)
199 break;
200 }
201
202 return err;
203 }
204
205
206 /**
207 * Get a URI header and possibly the value of it
208 *
209 * @param pl Pointer-length string containing URI Headers
210 * @param hname URI Header name
211 * @param hvalue Returned URI Header value
212 *
213 * @return 0 if success, otherwise errorcode
214 */
uri_header_get(const struct pl * pl,const struct pl * hname,struct pl * hvalue)215 int uri_header_get(const struct pl *pl, const struct pl *hname,
216 struct pl *hvalue)
217 {
218 char expr[128];
219
220 if (!pl || !hname || !hvalue)
221 return EINVAL;
222
223 (void)re_snprintf(expr, sizeof(expr), "[?&]1%r=[^&]+", hname);
224
225 return re_regex(pl->p, pl->l, expr, NULL, hvalue);
226 }
227
228
229 /**
230 * Call the apply handler for each URI Header
231 *
232 * @param pl Pointer-length string containing URI Headers
233 * @param ah Apply handler
234 * @param arg Handler argument
235 *
236 * @return 0 if success, otherwise errorcode (returned from handler)
237 */
uri_headers_apply(const struct pl * pl,uri_apply_h * ah,void * arg)238 int uri_headers_apply(const struct pl *pl, uri_apply_h *ah, void *arg)
239 {
240 struct pl plr, sep, hname, hvalue;
241 int err = 0;
242
243 if (!pl || !ah)
244 return EINVAL;
245
246 plr = *pl;
247
248 while (plr.l > 0) {
249
250 err = re_regex(plr.p, plr.l, "[?&]1[^=]+=[^&]+",
251 &sep, &hname, &hvalue);
252 if (err)
253 break;
254
255 pl_advance(&plr, sep.l + hname.l + 1 + hvalue.l);
256
257 err = ah(&hname, &hvalue, arg);
258 if (err)
259 break;
260 }
261
262 return err;
263 }
264