Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 */
30 struct 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  */
54 static 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 
88 struct 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 
101 struct 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 
115 const char *ast_uri_scheme(const struct ast_uri *uri)
116 {
117  return uri->scheme;
118 }
119 
120 const char *ast_uri_user_info(const struct ast_uri *uri)
121 {
122  return uri->user_info;
123 }
124 
125 const char *ast_uri_host(const struct ast_uri *uri)
126 {
127  return uri->host;
128 }
129 
130 const char *ast_uri_port(const struct ast_uri *uri)
131 {
132  return uri->port;
133 }
134 
135 const char *ast_uri_path(const struct ast_uri *uri)
136 {
137  return uri->path;
138 }
139 
140 const char *ast_uri_query(const struct ast_uri *uri)
141 {
142  return uri->query;
143 }
144 
145 int 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
152 struct 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
195 struct 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, '@'))) {
214  SET_VALUES(user_info);
215  }
216 
217  if ((p = strchr(uri, ':'))) {
218  SET_VALUES(host);
219  }
220 
221  if ((p = strchr(uri, '/'))) {
222  if (!host) {
223  SET_VALUES(host);
224  } else {
225  SET_VALUES(port);
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) {
237  SET_VALUES(host);
238  } else if (*(uri - 1) == ':') {
239  SET_VALUES(port);
240  } else if (*(uri - 1) == '/') {
241  SET_VALUES(path);
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 
253 static 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 */
280  struct ast_uri *tmp = ast_uri_copy_replace(
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 
290 struct ast_uri *ast_uri_parse_http(const char *uri)
291 {
292  return uri_parse_and_default(uri, "http", "80", "443");
293 }
294 
295 struct ast_uri *ast_uri_parse_websocket(const char *uri)
296 {
297  return uri_parse_and_default(uri, "ws", "80", "443");
298 }
299 
301 {
302  int host_size = ast_uri_host(uri) ?
303  strlen(ast_uri_host(uri)) : 0;
304  /* if there is a port +1 for the colon */
305  int port_size = ast_uri_port(uri) ?
306  strlen(ast_uri_port(uri)) + 1 : 0;
307  char *res = ast_malloc(host_size + port_size + 1);
308 
309  if (!res) {
310  return NULL;
311  }
312 
313  memcpy(res, ast_uri_host(uri), host_size);
314 
315  if (ast_uri_port(uri)) {
316  res[host_size] = ':';
317  memcpy(res + host_size + 1,
318  ast_uri_port(uri), port_size - 1);
319  }
320 
321  res[host_size + port_size] = '\0';
322  return res;
323 }
struct ast_uri * ast_uri_parse_http(const char *uri)
Parse the given http uri into a structure.
Definition: uri.c:290
enum sip_cc_notify_state state
Definition: chan_sip.c:959
Asterisk main include file. File version handling, generic pbx functions.
char * scheme
Definition: uri.c:32
String manipulation functions.
char * ast_uri_make_host_with_port(const struct ast_uri *uri)
Retrieve a string of the host and port.
Definition: uri.c:300
Stores parsed uri information.
Definition: uri.c:30
static int tmp()
Definition: bt_open.c:389
char * user_info
Definition: uri.c:34
char * port
Definition: uri.c:38
int ast_uri_is_secure(const struct ast_uri *uri)
Retrieve if the uri is of a secure type.
Definition: uri.c:145
#define NULL
Definition: resample.c:96
const char * ast_uri_port(const struct ast_uri *uri)
Retrieve the uri port.
Definition: uri.c:130
char * path
Definition: uri.c:40
#define ast_strlen_zero(foo)
Definition: strings.h:52
const char * ast_uri_query(const struct ast_uri *uri)
Retrieve the uri query parameters.
Definition: uri.c:140
#define SET_VALUE(param, field, size)
#define ast_log
Definition: astobj2.c:42
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
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
const char * ast_uri_host(const struct ast_uri *uri)
Retrieve the uri host.
Definition: uri.c:125
struct ast_uri * ast_uri_parse_websocket(const char *uri)
Parse the given websocket uri into a structure.
Definition: uri.c:295
#define LOG_ERROR
Definition: logger.h:285
const char * ast_uri_path(const struct ast_uri *uri)
Retrieve the uri path.
Definition: uri.c:135
struct ast_uri * ast_uri_parse(const char *uri)
Parse the given uri into a structure.
Definition: uri.c:152
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define ast_free(a)
Definition: astmm.h:182
char * query
Definition: uri.c:42
char uri[0]
Definition: uri.c:44
char * host
Definition: uri.c:36
const char * ast_uri_user_info(const struct ast_uri *uri)
Retrieve the uri user information.
Definition: uri.c:120
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_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
const char * ast_uri_scheme(const struct ast_uri *uri)
Retrieve the uri scheme.
Definition: uri.c:115
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