librnr  1.14.5
RoadNarrows Robotics Common Library 1
uri.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RoadNarrows Robotics Common Library 1
4 //
5 // Library: librnr
6 //
7 // File: uri.c
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2012-02-24 11:19:26 -0700 (Fri, 24 Feb 2012) $
12  * $Rev: 1848 $
13  *
14  * \brief Uniform Resource Identifier (URI) parsing utiliies.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \pkgcopyright{2011-2018,RoadNarrows LLC.,http://www.roadnarrows.com}
19  */
20 // Permission is hereby granted, without written agreement and without
21 // license or royalty fees, to use, copy, modify, and distribute this
22 // software and its documentation for any purpose, provided that
23 // (1) The above copyright notice and the following two paragraphs
24 // appear in all copies of the source code and (2) redistributions
25 // including binaries reproduces these notices in the supporting
26 // documentation. Substantial modifications to this software may be
27 // copyrighted by their authors and need not follow the licensing terms
28 // described here, provided that the new terms are clearly indicated in
29 // all files where they apply.
30 //
31 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
32 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
33 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
34 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
35 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
36 // THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
39 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
40 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
41 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
42 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
43 //
44 ////////////////////////////////////////////////////////////////////////////////
45 
46 #include <stdlib.h>
47 #include <string.h>
48 #include <stdio.h>
49 
50 #include "rnr/rnrconfig.h"
51 #include "rnr/new.h"
52 #include "rnr/uri.h"
53 
54 /*!
55  * \brief Parse a URI string.
56  *
57  * Any URI string components not found are set to NULL. If no port is specified,
58  * the port number is set to \ref URI_PORT_NONE (0).
59  *
60  * The Uri_T structure is allocated. The calling application owns the
61  * structure. See \ref UriDelete().
62  *
63  * \par Format:
64  * scheme://userinfo\@hostname:port/path/to/something?query&field=val...
65  *
66  * \param sUri URI string.
67  *
68  * \return Allocated and assigned Uri_T *.
69  */
70 Uri_T *UriParseNew(const char *sUri)
71 {
72  Uri_T *pUri = NEW(Uri_T); // new uri structure, initialized to 0 (null)
73  char *s = (char *)sUri; // working uri string head pointer
74  char *t; // working uri string tail pointer
75  size_t n; // size of uri string component
76 
77  // scheme://
78  if( (t = strstr(s, URI_SEP_SCHEME)) != NULL )
79  {
80  n = (size_t)(t - s);
81 
82  if( n > 0 )
83  {
84  pUri->m_sScheme = new_strndup(s, n);
85  }
86 
87  s = t + URI_SEP_SCHEME_LEN;
88  }
89 
90  if( *s == 0 )
91  {
92  return pUri;
93  }
94 
95  // userinfo@
96  if( (t = strstr(s, URI_SEP_USER_INFO)) != NULL )
97  {
98  n = (size_t)(t - s);
99 
100  if( n > 0 )
101  {
102  pUri->m_sUserInfo = new_strndup(s, n);
103  }
104 
105  s = t + URI_SEP_USER_INFO_LEN;
106  }
107 
108  if( *s == 0 )
109  {
110  return pUri;
111  }
112 
113  // hostname:port
114  s = UriParseHostNew(s, &(pUri->m_sHostName), &(pUri->m_nPortNum));
115 
116  if( *s == 0 )
117  {
118  return pUri;
119  }
120 
121  // /path?query
122  if( !strncmp(s, URI_SEP_PATH, (size_t)URI_SEP_PATH_LEN) )
123  {
124  if( *s == 0 )
125  {
126  return pUri;
127  }
128 
129  if( (t = strstr(s, URI_SEP_QUERY)) != NULL )
130  {
131  n = (size_t)(t - s);
132 
133  if( n > 0 )
134  {
135  pUri->m_sPath = new_strndup(s, n);
136  }
137 
138  s = t + URI_SEP_QUERY_LEN;
139 
140  if( *s != 0 )
141  {
142  pUri->m_sQuery = new_strdup(s);
143  }
144  }
145  else
146  {
147  pUri->m_sPath = new_strdup(s);
148  }
149  }
150 
151  // ?query
152  if( !strncmp(s, URI_SEP_QUERY, (size_t)URI_SEP_QUERY_LEN) )
153  {
154  s += URI_SEP_QUERY_LEN;
155 
156  if( *s != 0 )
157  {
158  pUri->m_sQuery = new_strdup(s);
159  }
160  }
161 
162  return pUri;
163 }
164 
165 /*!
166  * \brief Parse the host string.
167  *
168  * If no hostname is specified, NULL is set. If no port number is specified,
169  * URI_PORT_NONE is set.
170  *
171  * \par Format:
172  * hostname:port...
173  *
174  * \param sHost Host string.
175  * \param [out] pHostName Pointer to the allocated parsed host name string.
176  * \param [out] pPortNum Pointer to the parsed port number.
177  *
178  * \return
179  * Returns pointer to the first character after the host substring. If sHost
180  * is NULL, NULL is return. If now URI components follow the host string,
181  * will point to the end terminator of sHost.
182  */
183 char *UriParseHostNew(const char *sHost, char **pHostName, int *pPortNum)
184 {
185  char *s; // working host string head pointer
186  char *t; // working host string tail pointer
187  size_t n; // size of host string component
188 
189  *pHostName = NULL;
190  *pPortNum = URI_PORT_NONE;
191 
192  if( sHost == NULL )
193  {
194  return NULL;
195  }
196 
197  if( ((t = strstr(sHost, URI_SEP_PATH)) == NULL) &&
198  ((t = strstr(sHost, URI_SEP_QUERY)) == NULL) )
199  {
200  t = (char *)sHost + strlen(sHost);
201  }
202 
203  if( (s = strstr(sHost, URI_SEP_PORT)) == NULL )
204  {
205  s = t;
206  }
207 
208  n = (size_t)(s - sHost);
209 
210  if( n > 0 )
211  {
212  *pHostName = new_strndup(sHost, n);
213  }
214 
215  if( s+1 < t )
216  {
217  *pPortNum = (int)strtol(s+1, NULL, 10);
218  }
219 
220  return t;
221 }
222 
223 /*!
224  * \brief Set the scheme.
225  *
226  * \param pUri URI scheme.
227  * \param sScheme New scheme.
228  */
229 void UriSetScheme(Uri_T *pUri, const char *sScheme)
230 {
231  if( pUri == NULL )
232  {
233  return;
234  }
235 
236  if( pUri->m_sScheme != NULL )
237  {
238  delete(pUri->m_sScheme);
239  pUri->m_sScheme = NULL;
240  }
241 
242  if( (sScheme != NULL) && (*sScheme != 0) )
243  {
244  pUri->m_sScheme = new_strdup(sScheme);
245  }
246 }
247 
248 /*!
249  * \brief Set the hostname.
250  *
251  * \param pUri URI scheme.
252  * \param sHostName New hostname.
253  */
254 void UriSetHostName(Uri_T *pUri, const char *sHostName)
255 {
256  if( pUri == NULL )
257  {
258  return;
259  }
260 
261  if( pUri->m_sHostName != NULL )
262  {
263  delete(pUri->m_sHostName);
264  pUri->m_sHostName = NULL;
265  }
266 
267  if( (sHostName != NULL) && (*sHostName != 0) )
268  {
269  pUri->m_sHostName = new_strdup(sHostName);
270  }
271 }
272 
273 /*!
274  * \brief Set the port number.
275  *
276  * \param pUri URI scheme.
277  * \param nPortNum New scheme.
278  */
279 void UriSetPortNum(Uri_T *pUri, int nPortNum)
280 {
281  if( pUri == NULL )
282  {
283  return;
284  }
285 
286  pUri->m_nPortNum = nPortNum >= 0? nPortNum: URI_PORT_NONE;
287 }
288 
289 /*!
290  * \brief Set the file path.
291  *
292  * \param pUri URI scheme.
293  * \param sPath New scheme.
294  */
295 void UriSetPath(Uri_T *pUri, const char *sPath)
296 {
297  if( pUri == NULL )
298  {
299  return;
300  }
301 
302  if( pUri->m_sPath != NULL )
303  {
304  delete(pUri->m_sPath);
305  pUri->m_sPath = NULL;
306  }
307 
308  if( (sPath != NULL) && (*sPath != 0) )
309  {
310  pUri->m_sPath = new_strdup(sPath);
311  }
312 }
313 
314 /*!
315  * \brief Construct a new URI string from the given URI components.
316  *
317  * \param pUri Pointer to URI structure.
318  *
319  * \return Allocated string.
320  */
321 char *UriStrNew(const Uri_T *pUri)
322 {
323  char *sUri; // uri string
324  Uri_T uri = {"", "", "", 0, "", ""};
325  Uri_T sep = {"", "", "", 0, "", ""};
326  char bufPort[URI_SEP_PORT_LEN+URI_PORT_MAX_LEN+1] = {0, };
327  size_t n = 0;
328 
329  if( pUri == NULL )
330  {
331  return NULL;
332  }
333 
334  if( pUri->m_sScheme != NULL )
335  {
336  n += strlen(pUri->m_sScheme) + (size_t)URI_SEP_SCHEME_LEN;
337  uri.m_sScheme = pUri->m_sScheme;
339  }
340 
341  if( pUri->m_sUserInfo != NULL )
342  {
343  n += strlen(pUri->m_sUserInfo) + (size_t)URI_SEP_USER_INFO_LEN;
344  uri.m_sUserInfo = pUri->m_sUserInfo;
346  }
347 
348  if( pUri->m_sHostName != NULL )
349  {
350  n += strlen(pUri->m_sHostName);
351  uri.m_sHostName = pUri->m_sHostName;
352 
353  if( pUri->m_nPortNum != URI_PORT_NONE )
354  {
355  n += (size_t)URI_SEP_PORT_LEN + (size_t)URI_PORT_MAX_LEN;
356  snprintf(bufPort, sizeof(bufPort), "%s%d",
357  URI_SEP_PORT, pUri->m_nPortNum);
358  bufPort[sizeof(bufPort)-1] = 0;
359  }
360  }
361 
362  if( pUri->m_sPath != NULL )
363  {
364  n += strlen(pUri->m_sPath);
365  uri.m_sPath = pUri->m_sPath;
366  if( strncmp(uri.m_sPath, URI_SEP_PATH, URI_SEP_PATH_LEN) )
367  {
368  n++;
369  sep.m_sPath = URI_SEP_PATH;
370  }
371  }
372 
373  if( pUri->m_sQuery != NULL )
374  {
375  n += URI_SEP_QUERY_LEN + strlen(pUri->m_sQuery);
376  uri.m_sQuery = pUri->m_sQuery;
377  sep.m_sQuery = URI_SEP_QUERY;
378  }
379 
380  sUri = NEWSTR(n);
381 
382  sprintf(sUri, "%s%s%s%s%s%s%s%s%s%s",
383  uri.m_sScheme, sep.m_sScheme,
384  uri.m_sUserInfo, sep.m_sUserInfo,
385  uri.m_sHostName, bufPort,
386  sep.m_sPath, uri.m_sPath,
387  sep.m_sQuery, uri.m_sQuery);
388 
389  return sUri;
390 }
391 
392 /*!
393  * \brief Delete the URI compenent structure.
394  *
395  * \param pUri Pointer to allocated Uri_T.
396  */
397 void UriDelete(Uri_T *pUri)
398 {
399  if( pUri == NULL )
400  {
401  return;
402  }
403 
404  if( pUri->m_sScheme != NULL )
405  {
406  delete(pUri->m_sScheme);
407  }
408 
409  if( pUri->m_sUserInfo != NULL )
410  {
411  delete(pUri->m_sUserInfo);
412  }
413 
414  if( pUri->m_sHostName != NULL )
415  {
416  delete(pUri->m_sHostName);
417  }
418 
419  if( pUri->m_sPath != NULL )
420  {
421  delete(pUri->m_sPath);
422  }
423 
424  if( pUri->m_sQuery != NULL )
425  {
426  delete(pUri->m_sQuery);
427  }
428 
429  delete(pUri);
430 }
char * UriStrNew(const Uri_T *pUri)
Construct a new URI string from the given URI components.
Definition: uri.c:321
char * m_sScheme
scheme
Definition: uri.h:60
char * new_strndup(const char *s, size_t n)
Duplicate not more than n characters of string.
Definition: new.c:208
#define NEWSTR(len)
Allocate new string buffer of length len+1.
Definition: new.h:64
char * m_sQuery
query
Definition: uri.h:65
char * new_strdup(const char *s)
Duplicate a string.
Definition: new.c:176
void UriSetScheme(Uri_T *pUri, const char *sScheme)
Set the scheme.
Definition: uri.c:229
#define URI_SEP_QUERY_LEN
query separator length
Definition: uri.h:46
void UriSetHostName(Uri_T *pUri, const char *sHostName)
Set the hostname.
Definition: uri.c:254
#define NULL
null pointer
Definition: rnrconfig.h:199
#define URI_PORT_MAX_LEN
port max string length (2 bytes)
Definition: uri.h:48
void UriDelete(Uri_T *pUri)
Delete the URI compenent structure.
Definition: uri.c:397
Uniform Resource Identifier (URI) parsing utilities declarations.
Memory allocation and deallocation declarations.
char * m_sPath
absolute file path
Definition: uri.h:64
Uri_T * UriParseNew(const char *sUri)
Parse a URI string.
Definition: uri.c:70
#define URI_PORT_NONE
no port number
Definition: uri.h:52
#define URI_SEP_QUERY
query separator
Definition: uri.h:45
char * m_sUserInfo
user info
Definition: uri.h:61
#define URI_SEP_SCHEME_LEN
scheme separator length
Definition: uri.h:36
#define URI_SEP_USER_INFO
user info separator
Definition: uri.h:39
#define NEW(T)
Allocate new type.
Definition: new.h:49
RoadNarrows Robotics common configuration file.
#define URI_SEP_PORT_LEN
port number separator length
Definition: uri.h:42
#define URI_SEP_USER_INFO_LEN
user info separator length
Definition: uri.h:40
#define URI_SEP_SCHEME
scheme separator
Definition: uri.h:35
void UriSetPortNum(Uri_T *pUri, int nPortNum)
Set the port number.
Definition: uri.c:279
char * UriParseHostNew(const char *sHost, char **pHostName, int *pPortNum)
Parse the host string.
Definition: uri.c:183
void UriSetPath(Uri_T *pUri, const char *sPath)
Set the file path.
Definition: uri.c:295
#define URI_SEP_PATH
absolute path separator and start
Definition: uri.h:43
#define URI_SEP_PORT
port number separator
Definition: uri.h:41
char * m_sHostName
host name (domain or address)
Definition: uri.h:62
int m_nPortNum
port number
Definition: uri.h:63
#define URI_SEP_PATH_LEN
absolute path separator length
Definition: uri.h:44