Modifying version number for building on tizen 3.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / libcoap-4.1.1 / uri.c
1 /* uri.c -- helper functions for URI treatment
2  *
3  * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use. 
7  */
8
9 #include "config.h"
10
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "mem.h"
20 #include "debug.h"
21 #include "pdu.h"
22 #include "option.h"
23 #include "uri.h"
24
25 /** 
26  * A length-safe version of strchr(). This function returns a pointer
27  * to the first occurrence of @p c  in @p s, or @c NULL if not found.
28  * 
29  * @param s   The string to search for @p c.
30  * @param len The length of @p s.
31  * @param c   The character to search.
32  * 
33  * @return A pointer to the first occurence of @p c, or @c NULL 
34  * if not found.
35  */
36 static inline unsigned char *
37 strnchr(unsigned char *s, size_t len, unsigned char c)
38 {
39     while (len && *s++ != c)
40         --len;
41
42     return len ? s : NULL;
43 }
44
45 int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri)
46 {
47
48     unsigned char *p, *q;
49     int secure = 0, res = 0;
50
51     if (!str_var || !uri)
52         return -1;
53
54     memset(uri, 0, sizeof(coap_uri_t));
55     uri->port = COAP_DEFAULT_PORT;
56
57     /* search for scheme */
58     p = str_var;
59     if (*p == '/')
60     {
61         q = p;
62         goto path;
63     }
64
65     q = (unsigned char *) COAP_DEFAULT_SCHEME;
66     while (len && *q && tolower(*p) == *q)
67     {
68         ++p;
69         ++q;
70         --len;
71     }
72
73     /* If q does not point to the string end marker '\0', the schema
74      * identifier is wrong. */
75     if (*q)
76     {
77         res = -1;
78         goto error;
79     }
80
81     /* There might be an additional 's', indicating the secure version: */
82     if (len && (secure = tolower(*p) == 's'))
83     {
84         ++p;
85         --len;
86     }
87
88     q = (unsigned char *) "://";
89     while (len && *q && tolower(*p) == *q)
90     {
91         ++p;
92         ++q;
93         --len;
94     }
95
96     if (*q)
97     {
98         res = -2;
99         goto error;
100     }
101
102     /* p points to beginning of Uri-Host */
103     q = p;
104     if (len && *p == '[')
105     { /* IPv6 address reference */
106         ++p;
107
108         while (len && *q != ']')
109         {
110             ++q;
111             --len;
112         }
113
114         if (!len || *q != ']' || p == q)
115         {
116             res = -3;
117             goto error;
118         }
119
120         COAP_SET_STR(&uri->host, q - p, p);
121         ++q;
122         --len;
123     }
124     else
125     { /* IPv4 address or FQDN */
126         while (len && *q != ':' && *q != '/' && *q != '?')
127         {
128             // *q = tolower(*q);
129
130             ++q;
131             --len;
132         }
133
134         if (p == q)
135         {
136             res = -3;
137             goto error;
138         }
139
140         COAP_SET_STR(&uri->host, q - p, p);
141
142     }
143
144     /* check for Uri-Port */
145     if (len && *q == ':')
146     {
147         p = ++q;
148         --len;
149
150         while (len && isdigit(*q))
151         {
152             ++q;
153             --len;
154         }
155
156         if (p < q)
157         { /* explicit port number given */
158             int uri_port = 0;
159
160             while (p < q)
161                 uri_port = uri_port * 10 + (*p++ - '0');
162
163             uri->port = uri_port;
164         }
165     }
166
167     path: /* at this point, p must point to an absolute path */
168
169     if (!len)
170         goto end;
171
172     if (*q == '/')
173     {
174         p = ++q;
175         --len;
176
177         while (len && *q != '?')
178         {
179             ++q;
180             --len;
181         }
182
183         if (p < q)
184         {
185             COAP_SET_STR(&uri->path, q - p, p);
186             p = q;
187         }
188     }
189
190     /* Uri_Query */
191     if (len && *p == '?')
192     {
193         ++p;
194         --len;
195         COAP_SET_STR(&uri->query, len, p);
196         len = 0;
197     }
198
199     end: return len ? -1 : 0;
200
201     error: return res;
202 }
203
204 /** 
205  * Calculates decimal value from hexadecimal ASCII character given in
206  * @p c. The caller must ensure that @p c actually represents a valid
207  * heaxdecimal character, e.g. with isxdigit(3). 
208  *
209  * @hideinitializer
210  */
211 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
212
213 /** 
214  * Decodes percent-encoded characters while copying the string @p seg
215  * of size @p length to @p buf. The caller of this function must
216  * ensure that the percent-encodings are correct (i.e. the character
217  * '%' is always followed by two hex digits. and that @p buf provides
218  * sufficient space to hold the result. This function is supposed to
219  * be called by make_decoded_option() only.
220  * 
221  * @param seg     The segment to decode and copy.
222  * @param length  Length of @p seg.
223  * @param buf     The result buffer.
224  */
225 void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf)
226 {
227
228     while (length--)
229     {
230
231         if (*seg == '%')
232         {
233             *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
234
235             seg += 2;
236             length -= 2;
237         }
238         else
239         {
240             *buf = *seg;
241         }
242
243         ++buf;
244         ++seg;
245     }
246 }
247
248 /**
249  * Runs through the given path (or query) segment and checks if
250  * percent-encodings are correct. This function returns @c -1 on error
251  * or the length of @p s when decoded.
252  */
253 int check_segment(const unsigned char *s, size_t length)
254 {
255
256     size_t n = 0;
257
258     while (length)
259     {
260         if (*s == '%')
261         {
262             if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
263                 return -1;
264
265             s += 2;
266             length -= 2;
267         }
268
269         ++s;
270         ++n;
271         --length;
272     }
273
274     return n;
275 }
276
277 /** 
278  * Writes a coap option from given string @p s to @p buf. @p s should
279  * point to a (percent-encoded) path or query segment of a coap_uri_t
280  * object.  The created option will have type @c 0, and the length
281  * parameter will be set according to the size of the decoded string.
282  * On success, this function returns the option's size, or a value
283  * less than zero on error. This function must be called from
284  * coap_split_path_impl() only.
285  * 
286  * @param s       The string to decode.
287  * @param length  The size of the percent-encoded string @p s.
288  * @param buf     The buffer to store the new coap option.
289  * @param buflen  The maximum size of @p buf.
290  * 
291  * @return The option's size, or @c -1 on error.
292  *
293  * @bug This function does not split segments that are bigger than 270
294  * bytes.
295  */
296 int make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen)
297 {
298     int res;
299     size_t written;
300
301     if (!buflen)
302     {
303         debug("make_decoded_option(): buflen is 0!\n");
304         return -1;
305     }
306
307     res = check_segment(s, length);
308     if (res < 0)
309         return -1;
310
311     /* write option header using delta 0 and length res */
312     written = coap_opt_setheader(buf, buflen, 0, res);
313
314     assert(written <= buflen);
315
316     if (!written) /* encoding error */
317         return -1;
318
319     buf += written; /* advance past option type/length */
320     buflen -= written;
321
322     if (buflen < (size_t) res)
323     {
324         debug("buffer too small for option\n");
325         return -1;
326     }
327
328     decode_segment(s, length, buf);
329
330     return written + res;
331 }
332
333 #ifndef min
334 #define min(a,b) ((a) < (b) ? (a) : (b))
335 #endif
336
337 typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
338
339 /** 
340  * Splits the given string into segments. You should call one of the
341  * macros coap_split_path() or coap_split_query() instead.
342  * 
343  * @param parse_iter The iterator used for tokenizing.
344  * @param h      A handler that is called with every token.
345  * @param data   Opaque data that is passed to @p h when called.
346  * 
347  * @return The number of characters that have been parsed from @p s.
348  */
349 size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter, segment_handler_t h, void *data)
350 {
351     unsigned char *seg;
352     size_t length;
353
354     assert(parse_iter);
355     assert(h);
356
357     length = parse_iter->n;
358
359     while ((seg = coap_parse_next(parse_iter)))
360     {
361
362         /* any valid path segment is handled here: */
363         h(seg, parse_iter->segment_length, data);
364     }
365
366     return length - (parse_iter->n - parse_iter->segment_length);
367 }
368
369 struct cnt_str
370 {
371     str buf;
372     int n;
373 };
374
375 void write_option(unsigned char *s, size_t len, void *data)
376 {
377     struct cnt_str *state = (struct cnt_str *) data;
378     int res;
379     assert(state);
380
381     /* skip empty segments and those that consist of only one or two dots */
382     if (memcmp(s, "..", min(len,2)) == 0)
383         return;
384
385     res = make_decoded_option(s, len, state->buf.s, state->buf.length);
386     if (res > 0)
387     {
388         state->buf.s += res;
389         state->buf.length -= res;
390         state->n++;
391     }
392 }
393
394 int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
395 {
396     struct cnt_str tmp =
397     {
398     { *buflen, buf }, 0 };
399     coap_parse_iterator_t pi;
400
401     coap_parse_iterator_init((unsigned char *) s, length, '/', (unsigned char *) "?#", 2, &pi);
402     coap_split_path_impl(&pi, write_option, &tmp);
403
404     *buflen = *buflen - tmp.buf.length;
405     return tmp.n;
406 }
407
408 int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
409 {
410     struct cnt_str tmp =
411     {
412     { *buflen, buf }, 0 };
413     coap_parse_iterator_t pi;
414
415     coap_parse_iterator_init((unsigned char *) s, length, '&', (unsigned char *) "#", 1, &pi);
416
417     coap_split_path_impl(&pi, write_option, &tmp);
418
419     *buflen = tmp.buf.length;
420     return tmp.n;
421 }
422
423 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
424
425 coap_uri_t *
426 coap_new_uri(const unsigned char *uri, unsigned int length)
427 {
428     unsigned char *result;
429
430     result = coap_malloc(length + 1 + sizeof(coap_uri_t));
431
432     if (!result)
433         return NULL;
434
435     memcpy(URI_DATA(result), uri, length);
436     URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
437
438     if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *) result) < 0)
439     {
440         free(result);
441         return NULL;
442     }
443     return (coap_uri_t *) result;
444 }
445
446 coap_uri_t *
447 coap_clone_uri(const coap_uri_t *uri)
448 {
449     coap_uri_t *result;
450
451     if (!uri)
452         return NULL;
453
454     result = (coap_uri_t *) coap_malloc( uri->query.length + uri->host.length +
455             uri->path.length + sizeof(coap_uri_t) + 1);
456
457     if (!result)
458         return NULL;
459
460     memset(result, 0, sizeof(coap_uri_t));
461
462     result->port = uri->port;
463
464     if (uri->host.length)
465     {
466         result->host.s = URI_DATA(result);
467         result->host.length = uri->host.length;
468
469         memcpy(result->host.s, uri->host.s, uri->host.length);
470     }
471
472     if (uri->path.length)
473     {
474         result->path.s = URI_DATA(result) + uri->host.length;
475         result->path.length = uri->path.length;
476
477         memcpy(result->path.s, uri->path.s, uri->path.length);
478     }
479
480     if (uri->query.length)
481     {
482         result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
483         result->query.length = uri->query.length;
484
485         memcpy(result->query.s, uri->query.s, uri->query.length);
486     }
487
488     return result;
489 }
490
491 /* hash URI path segments */
492
493 /* The function signature of coap_hash() is different from
494  * segment_handler_t hence we use this wrapper as safe typecast. */
495 static inline void hash_segment(unsigned char *s, size_t len, void *data)
496 {
497     coap_hash(s, len, data);
498 }
499
500 int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key)
501 {
502     coap_parse_iterator_t pi;
503
504     if (!path)
505         return 0;
506
507     memset(key, 0, sizeof(coap_key_t));
508
509     coap_parse_iterator_init((unsigned char *) path, len, '/', (unsigned char *) "?#", 2, &pi);
510     coap_split_path_impl(&pi, hash_segment, key);
511
512     return 1;
513 }
514
515 /* iterator functions */
516
517 coap_parse_iterator_t *
518 coap_parse_iterator_init(unsigned char *s, size_t n, unsigned char separator, unsigned char *delim,
519         size_t dlen, coap_parse_iterator_t *pi)
520 {
521     assert(pi);
522     assert(separator);
523
524     pi->separator = separator;
525     pi->delim = delim;
526     pi->dlen = dlen;
527     pi->pos = s;
528     pi->n = n;
529     pi->segment_length = 0;
530
531     return pi;
532 }
533
534 unsigned char *
535 coap_parse_next(coap_parse_iterator_t *pi)
536 {
537     unsigned char *p;
538
539     if (!pi)
540         return NULL;
541
542     /* proceed to the next segment */
543     pi->n -= pi->segment_length;
544     pi->pos += pi->segment_length;
545     pi->segment_length = 0;
546
547     /* last segment? */
548     if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos))
549     {
550         pi->pos = NULL;
551         return NULL;
552     }
553
554     /* skip following separator (the first segment might not have one) */
555     if (*pi->pos == pi->separator)
556     {
557         ++pi->pos;
558         --pi->n;
559     }
560
561     p = pi->pos;
562
563     while (pi->segment_length < pi->n && *p != pi->separator && !strnchr(pi->delim, pi->dlen, *p))
564     {
565         ++p;
566         ++pi->segment_length;
567     }
568
569     if (!pi->n)
570     {
571         pi->pos = NULL;
572         pi->segment_length = 0;
573     }
574
575     return pi->pos;
576 }
577