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