1 /* uri.c -- helper functions for URI treatment
3 * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
5 * This file is part of the CoAP library libcoap. Please see
6 * README for terms of use.
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
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.
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.
33 * @return A pointer to the first occurence of @p c, or @c NULL
36 static inline unsigned char *
37 strnchr(unsigned char *s, size_t len, unsigned char c)
39 while (len && *s++ != c)
42 return len ? s : NULL;
45 int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri)
49 int secure = 0, res = 0;
54 memset(uri, 0, sizeof(coap_uri_t));
55 uri->port = COAP_DEFAULT_PORT;
57 /* search for scheme */
65 q = (unsigned char *) COAP_DEFAULT_SCHEME;
66 while (len && *q && tolower(*p) == *q)
73 /* If q does not point to the string end marker '\0', the schema
74 * identifier is wrong. */
81 /* There might be an additional 's', indicating the secure version: */
82 if (len && (secure = tolower(*p) == 's'))
88 q = (unsigned char *) "://";
89 while (len && *q && tolower(*p) == *q)
102 /* p points to beginning of Uri-Host */
104 if (len && *p == '[')
105 { /* IPv6 address reference */
108 while (len && *q != ']')
114 if (!len || *q != ']' || p == q)
120 COAP_SET_STR(&uri->host, q - p, p);
125 { /* IPv4 address or FQDN */
126 while (len && *q != ':' && *q != '/' && *q != '?')
140 COAP_SET_STR(&uri->host, q - p, p);
144 /* check for Uri-Port */
145 if (len && *q == ':')
150 while (len && isdigit(*q))
157 { /* explicit port number given */
161 uri_port = uri_port * 10 + (*p++ - '0');
163 uri->port = uri_port;
167 path: /* at this point, p must point to an absolute path */
177 while (len && *q != '?')
185 COAP_SET_STR(&uri->path, q - p, p);
191 if (len && *p == '?')
195 COAP_SET_STR(&uri->query, len, p);
199 end: return len ? -1 : 0;
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).
211 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
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.
221 * @param seg The segment to decode and copy.
222 * @param length Length of @p seg.
223 * @param buf The result buffer.
225 void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf)
233 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
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.
253 int check_segment(const unsigned char *s, size_t length)
262 if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
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.
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.
291 * @return The option's size, or @c -1 on error.
293 * @bug This function does not split segments that are bigger than 270
296 int make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen)
303 debug("make_decoded_option(): buflen is 0!\n");
307 res = check_segment(s, length);
311 /* write option header using delta 0 and length res */
312 written = coap_opt_setheader(buf, buflen, 0, res);
314 assert(written <= buflen);
316 if (!written) /* encoding error */
319 buf += written; /* advance past option type/length */
322 if (buflen < (size_t) res)
324 debug("buffer too small for option\n");
328 decode_segment(s, length, buf);
330 return written + res;
334 #define min(a,b) ((a) < (b) ? (a) : (b))
337 typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
340 * Splits the given string into segments. You should call one of the
341 * macros coap_split_path() or coap_split_query() instead.
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.
347 * @return The number of characters that have been parsed from @p s.
349 size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter, segment_handler_t h, void *data)
357 length = parse_iter->n;
359 while ((seg = coap_parse_next(parse_iter)))
362 /* any valid path segment is handled here: */
363 h(seg, parse_iter->segment_length, data);
366 return length - (parse_iter->n - parse_iter->segment_length);
375 void write_option(unsigned char *s, size_t len, void *data)
377 struct cnt_str *state = (struct cnt_str *) data;
381 /* skip empty segments and those that consist of only one or two dots */
382 if (memcmp(s, "..", min(len,2)) == 0)
385 res = make_decoded_option(s, len, state->buf.s, state->buf.length);
389 state->buf.length -= res;
394 int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
398 { *buflen, buf }, 0 };
399 coap_parse_iterator_t pi;
401 coap_parse_iterator_init((unsigned char *) s, length, '/', (unsigned char *) "?#", 2, &pi);
402 coap_split_path_impl(&pi, write_option, &tmp);
404 *buflen = *buflen - tmp.buf.length;
408 int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
412 { *buflen, buf }, 0 };
413 coap_parse_iterator_t pi;
415 coap_parse_iterator_init((unsigned char *) s, length, '&', (unsigned char *) "#", 1, &pi);
417 coap_split_path_impl(&pi, write_option, &tmp);
419 *buflen = tmp.buf.length;
423 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
426 coap_new_uri(const unsigned char *uri, unsigned int length)
428 unsigned char *result;
430 result = coap_malloc(length + 1 + sizeof(coap_uri_t));
435 memcpy(URI_DATA(result), uri, length);
436 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
438 if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *) result) < 0)
443 return (coap_uri_t *) result;
447 coap_clone_uri(const coap_uri_t *uri)
454 result = (coap_uri_t *) coap_malloc( uri->query.length + uri->host.length +
455 uri->path.length + sizeof(coap_uri_t) + 1);
460 memset(result, 0, sizeof(coap_uri_t));
462 result->port = uri->port;
464 if (uri->host.length)
466 result->host.s = URI_DATA(result);
467 result->host.length = uri->host.length;
469 memcpy(result->host.s, uri->host.s, uri->host.length);
472 if (uri->path.length)
474 result->path.s = URI_DATA(result) + uri->host.length;
475 result->path.length = uri->path.length;
477 memcpy(result->path.s, uri->path.s, uri->path.length);
480 if (uri->query.length)
482 result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
483 result->query.length = uri->query.length;
485 memcpy(result->query.s, uri->query.s, uri->query.length);
491 /* hash URI path segments */
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)
497 coap_hash(s, len, data);
500 int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key)
502 coap_parse_iterator_t pi;
507 memset(key, 0, sizeof(coap_key_t));
509 coap_parse_iterator_init((unsigned char *) path, len, '/', (unsigned char *) "?#", 2, &pi);
510 coap_split_path_impl(&pi, hash_segment, key);
515 /* iterator functions */
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)
524 pi->separator = separator;
529 pi->segment_length = 0;
535 coap_parse_next(coap_parse_iterator_t *pi)
542 /* proceed to the next segment */
543 pi->n -= pi->segment_length;
544 pi->pos += pi->segment_length;
545 pi->segment_length = 0;
548 if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos))
554 /* skip following separator (the first segment might not have one) */
555 if (*pi->pos == pi->separator)
563 while (pi->segment_length < pi->n && *p != pi->separator && !strnchr(pi->delim, pi->dlen, *p))
566 ++pi->segment_length;
572 pi->segment_length = 0;