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