Asterisk - The Open Source Telephony Project GIT-master-a358458
uri.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2014, Digium, Inc.
5 *
6 * Kevin Harwell <kharwell@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19#include "asterisk.h"
20
21#include "asterisk/astobj2.h"
22#include "asterisk/strings.h"
23#include "asterisk/uri.h"
24
25#ifdef HAVE_URIPARSER
26#include <uriparser/Uri.h>
27#endif
28
29/*! \brief Stores parsed uri information */
30struct ast_uri {
31 /*! scheme (e.g. http, https, ws, wss, etc...) */
32 char *scheme;
33 /*! username:password */
34 char *user_info;
35 /*! host name or address */
36 char *host;
37 /*! associated port */
38 char *port;
39 /*! path info following host[:port] */
40 char *path;
41 /*! query information */
42 char *query;
43 /*! storage for uri string */
44 char uri[0];
45};
46
47/*!
48 * \brief Construct a uri object with the given values.
49 *
50 * \note The size parameters [should] include room for the string terminator
51 * (strlen(<param>) + 1). For instance, if a scheme of 'http' is given
52 * then the 'scheme_size' should be equal to 5.
53 */
54static struct ast_uri *ast_uri_create_(
55 const char *scheme, unsigned int scheme_size,
56 const char *user_info, unsigned int user_info_size,
57 const char *host, unsigned int host_size,
58 const char *port, unsigned int port_size,
59 const char *path, unsigned int path_size,
60 const char *query, unsigned int query_size)
61{
62#define SET_VALUE(param, field, size) \
63 do { if (param) { \
64 ast_copy_string(p, param, size); \
65 field = p; \
66 p += size; } } while (0)
67
68 char *p;
69 struct ast_uri *res = ao2_alloc(
70 sizeof(*res) + scheme_size + user_info_size + host_size +
71 port_size + path_size + query_size, NULL);
72
73 if (!res) {
74 ast_log(LOG_ERROR, "Unable to create URI object\n");
75 return NULL;
76 }
77
78 p = res->uri;
79 SET_VALUE(scheme, res->scheme, scheme_size);
80 SET_VALUE(user_info, res->user_info, user_info_size);
81 SET_VALUE(host, res->host, host_size);
82 SET_VALUE(port, res->port, port_size);
83 SET_VALUE(path, res->path, path_size);
84 SET_VALUE(query, res->query, query_size);
85 return res;
86}
87
88struct ast_uri *ast_uri_create(const char *scheme, const char *user_info,
89 const char *host, const char *port,
90 const char *path, const char *query)
91{
92 return ast_uri_create_(
93 scheme, scheme ? strlen(scheme) + 1 : 0,
94 user_info, user_info ? strlen(user_info) + 1 : 0,
95 host, host ? strlen(host) + 1 : 0,
96 port, port ? strlen(port) + 1 : 0,
97 path, path ? strlen(path) + 1 : 0,
98 query, query ? strlen(query) + 1 : 0);
99}
100
101struct ast_uri *ast_uri_copy_replace(const struct ast_uri *uri, const char *scheme,
102 const char *user_info, const char *host,
103 const char *port, const char *path,
104 const char *query)
105{
106 return ast_uri_create(
107 scheme ? scheme : uri->scheme,
108 user_info ? user_info : uri->user_info,
109 host ? host : uri->host,
110 port ? port : uri->port,
111 path ? path : uri->path,
112 query ? query : uri->query);
113}
114
115const char *ast_uri_scheme(const struct ast_uri *uri)
116{
117 return uri->scheme;
118}
119
120const char *ast_uri_user_info(const struct ast_uri *uri)
121{
122 return uri->user_info;
123}
124
125const char *ast_uri_host(const struct ast_uri *uri)
126{
127 return uri->host;
128}
129
130const char *ast_uri_port(const struct ast_uri *uri)
131{
132 return uri->port;
133}
134
135const char *ast_uri_path(const struct ast_uri *uri)
136{
137 return uri->path;
138}
139
140const char *ast_uri_query(const struct ast_uri *uri)
141{
142 return uri->query;
143}
144
145int ast_uri_is_secure(const struct ast_uri *uri)
146{
147 return ast_strlen_zero(uri->scheme) ? 0 :
148 *(uri->scheme + strlen(uri->scheme) - 1) == 's';
149}
150
151#ifdef HAVE_URIPARSER
152struct ast_uri *ast_uri_parse(const char *uri)
153{
154 UriParserStateA state;
155 UriUriA uria;
156 struct ast_uri *res;
157 unsigned int scheme_size, user_info_size, host_size;
158 unsigned int port_size, path_size, query_size;
159 const char *path_start, *path_end;
160
161 state.uri = &uria;
162 if (uriParseUriA(&state, uri) != URI_SUCCESS) {
163 ast_log(LOG_ERROR, "Unable to parse URI %s\n", uri);
164 uriFreeUriMembersA(&uria);
165 return NULL;
166 }
167
168 scheme_size = uria.scheme.first ?
169 uria.scheme.afterLast - uria.scheme.first + 1 : 0;
170 user_info_size = uria.userInfo.first ?
171 uria.userInfo.afterLast - uria.userInfo.first + 1 : 0;
172 host_size = uria.hostText.first ?
173 uria.hostText.afterLast - uria.hostText.first + 1 : 0;
174 port_size = uria.portText.first ?
175 uria.portText.afterLast - uria.portText.first + 1 : 0;
176
177 path_start = uria.pathHead && uria.pathHead->text.first ?
178 uria.pathHead->text.first : NULL;
179 path_end = path_start ? uria.pathTail->text.afterLast : NULL;
180 path_size = path_end ? path_end - path_start + 1 : 0;
181
182 query_size = uria.query.first ?
183 uria.query.afterLast - uria.query.first + 1 : 0;
184
185 res = ast_uri_create_(uria.scheme.first, scheme_size,
186 uria.userInfo.first, user_info_size,
187 uria.hostText.first, host_size,
188 uria.portText.first, port_size,
189 path_start, path_size,
190 uria.query.first, query_size);
191 uriFreeUriMembersA(&uria);
192 return res;
193}
194#else
195struct ast_uri *ast_uri_parse(const char *uri)
196{
197#define SET_VALUES(value) \
198 value = uri; \
199 size_##value = p - uri + 1; \
200 uri = p + 1;
201
202 const char *p, *scheme = NULL, *user_info = NULL, *host = NULL;
203 const char *port = NULL, *path = NULL, *query = NULL;
204 unsigned int size_scheme = 0, size_user_info = 0, size_host = 0;
205 unsigned int size_port = 0, size_path = 0, size_query = 0;
206
207 if ((p = strstr(uri, "://"))) {
208 scheme = uri;
209 size_scheme = p - uri + 1;
210 uri = p + 3;
211 }
212
213 if ((p = strchr(uri, '@'))) {
215 }
216
217 if ((p = strchr(uri, ':'))) {
219 }
220
221 if ((p = strchr(uri, '/'))) {
222 if (!host) {
224 } else {
226 }
227 }
228
229 if ((p = strchr(uri, '?'))) {
230 query = p + 1;
231 size_query = strlen(query) + 1;
232 } else {
233 p = uri + strlen(uri);
234 }
235
236 if (!host) {
238 } else if (*(uri - 1) == ':') {
240 } else if (*(uri - 1) == '/') {
242 }
243
244 return ast_uri_create_(scheme, size_scheme,
245 user_info, size_user_info,
246 host, size_host,
247 port, size_port,
248 path, size_path,
249 query, size_query);
250}
251#endif
252
253static struct ast_uri *uri_parse_and_default(const char *uri, const char *scheme,
254 const char *port, const char *secure_port)
255{
256 struct ast_uri *res;
257 int len = strlen(scheme);
258
259 if (!strncmp(uri, scheme, len)) {
260 res = ast_uri_parse(uri);
261 } else {
262 /* make room for <scheme>:// */
263 char *with_scheme = ast_malloc(len + strlen(uri) + 4);
264 if (!with_scheme) {
265 ast_log(LOG_ERROR, "Unable to allocate uri '%s' with "
266 "scheme '%s'", uri, scheme);
267 return NULL;
268 }
269
270 /* safe - 'with_scheme' created with size equal to len of
271 scheme plus length of uri plus space for extra characters
272 '://' and terminator */
273 sprintf(with_scheme, "%s://%s", scheme, uri);
274 res = ast_uri_parse(with_scheme);
275 ast_free(with_scheme);
276 }
277
278 if (res && ast_strlen_zero(ast_uri_port(res))) {
279 /* default the port if not given */
281 res, NULL, NULL, NULL,
282 ast_uri_is_secure(res) ? secure_port : port,
283 NULL, NULL);
284 ao2_ref(res, -1);
285 res = tmp;
286 }
287 return res;
288}
289
290struct ast_uri *ast_uri_parse_http(const char *uri)
291{
292 return uri_parse_and_default(uri, "http", "80", "443");
293}
294
296{
297 return uri_parse_and_default(uri, "ws", "80", "443");
298}
299
301{
302 char *res;
303
304 if (ast_asprintf(&res, "%s%s%s",
305 ast_uri_host(uri) ?: "",
306 ast_uri_port(uri) ? ":" : "",
307 ast_uri_port(uri) ?: "") == -1) {
308 return NULL;
309 }
310
311 return res;
312}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static int tmp()
Definition: bt_open.c:389
enum cc_state state
Definition: ccss.c:393
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_ERROR
#define NULL
Definition: resample.c:96
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Stores parsed uri information.
Definition: uri.c:30
char * host
Definition: uri.c:36
char * path
Definition: uri.c:40
char uri[0]
Definition: uri.c:44
char * user_info
Definition: uri.c:34
char * scheme
Definition: uri.c:32
char * port
Definition: uri.c:38
char * query
Definition: uri.c:42
const char * ast_uri_path(const struct ast_uri *uri)
Retrieve the uri path.
Definition: uri.c:135
const char * ast_uri_scheme(const struct ast_uri *uri)
Retrieve the uri scheme.
Definition: uri.c:115
struct ast_uri * ast_uri_copy_replace(const struct ast_uri *uri, const char *scheme, const char *user_info, const char *host, const char *port, const char *path, const char *query)
Copy the given uri replacing any value in the new uri with any given.
Definition: uri.c:101
int ast_uri_is_secure(const struct ast_uri *uri)
Retrieve if the uri is of a secure type.
Definition: uri.c:145
#define SET_VALUE(param, field, size)
struct ast_uri * ast_uri_parse_http(const char *uri)
Parse the given http uri into a structure.
Definition: uri.c:290
const char * ast_uri_port(const struct ast_uri *uri)
Retrieve the uri port.
Definition: uri.c:130
static struct ast_uri * uri_parse_and_default(const char *uri, const char *scheme, const char *port, const char *secure_port)
Definition: uri.c:253
struct ast_uri * ast_uri_parse_websocket(const char *uri)
Parse the given websocket uri into a structure.
Definition: uri.c:295
#define SET_VALUES(value)
const char * ast_uri_query(const struct ast_uri *uri)
Retrieve the uri query parameters.
Definition: uri.c:140
const char * ast_uri_user_info(const struct ast_uri *uri)
Retrieve the uri user information.
Definition: uri.c:120
const char * ast_uri_host(const struct ast_uri *uri)
Retrieve the uri host.
Definition: uri.c:125
struct ast_uri * ast_uri_create(const char *scheme, const char *user_info, const char *host, const char *port, const char *path, const char *query)
Create a uri with the given parameters.
Definition: uri.c:88
char * ast_uri_make_host_with_port(const struct ast_uri *uri)
Retrieve a string of the host and port.
Definition: uri.c:300
struct ast_uri * ast_uri_parse(const char *uri)
Parse the given uri into a structure.
Definition: uri.c:195
static struct ast_uri * ast_uri_create_(const char *scheme, unsigned int scheme_size, const char *user_info, unsigned int user_info_size, const char *host, unsigned int host_size, const char *port, unsigned int port_size, const char *path, unsigned int path_size, const char *query, unsigned int query_size)
Construct a uri object with the given values.
Definition: uri.c:54