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)
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.
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.
32 * @return A pointer to the first occurence of @p c, or @c NULL
35 static inline unsigned char *
36 strnchr(unsigned char *s, size_t len, unsigned char c)
38 while (len && *s++ != c)
41 return len ? s : NULL;
44 int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri)
48 int secure = 0, res = 0;
53 memset(uri, 0, sizeof(coap_uri_t));
54 uri->port = COAP_DEFAULT_PORT;
56 /* search for scheme */
64 q = (unsigned char *) COAP_DEFAULT_SCHEME;
65 while (len && *q && tolower(*p) == *q)
72 /* If q does not point to the string end marker '\0', the schema
73 * identifier is wrong. */
80 /* There might be an additional 's', indicating the secure version: */
81 if (len && (secure = tolower(*p) == 's'))
87 q = (unsigned char *) "://";
88 while (len && *q && tolower(*p) == *q)
101 /* p points to beginning of Uri-Host */
103 if (len && *p == '[')
104 { /* IPv6 address reference */
107 while (len && *q != ']')
113 if (!len || *q != ']' || p == q)
119 COAP_SET_STR(&uri->host, q - p, p);
124 { /* IPv4 address or FQDN */
125 while (len && *q != ':' && *q != '/' && *q != '?')
139 COAP_SET_STR(&uri->host, q - p, p);
143 /* check for Uri-Port */
144 if (len && *q == ':')
149 while (len && isdigit(*q))
156 { /* explicit port number given */
160 uri_port = uri_port * 10 + (*p++ - '0');
162 uri->port = uri_port;
166 path: /* at this point, p must point to an absolute path */
176 while (len && *q != '?')
184 COAP_SET_STR(&uri->path, q - p, p);
190 if (len && *p == '?')
194 COAP_SET_STR(&uri->query, len, p);
198 end: return len ? -1 : 0;
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).
210 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
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.
220 * @param seg The segment to decode and copy.
221 * @param length Length of @p seg.
222 * @param buf The result buffer.
224 void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf)
232 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
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.
252 int check_segment(const unsigned char *s, size_t length)
261 if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
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.
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.
290 * @return The option's size, or @c -1 on error.
292 * @bug This function does not split segments that are bigger than 270
295 int make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen)
302 debug("make_decoded_option(): buflen is 0!\n");
306 res = check_segment(s, length);
310 /* write option header using delta 0 and length res */
311 written = coap_opt_setheader(buf, buflen, 0, res);
313 assert(written <= buflen);
315 if (!written) /* encoding error */
318 buf += written; /* advance past option type/length */
321 if (buflen < (size_t) res)
323 debug("buffer too small for option\n");
327 decode_segment(s, length, buf);
329 return written + res;
333 #define min(a,b) ((a) < (b) ? (a) : (b))
336 typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
339 * Splits the given string into segments. You should call one of the
340 * macros coap_split_path() or coap_split_query() instead.
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.
346 * @return The number of characters that have been parsed from @p s.
348 size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter, segment_handler_t h, void *data)
356 length = parse_iter->n;
358 while ((seg = coap_parse_next(parse_iter)))
361 /* any valid path segment is handled here: */
362 h(seg, parse_iter->segment_length, data);
365 return length - (parse_iter->n - parse_iter->segment_length);
374 void write_option(unsigned char *s, size_t len, void *data)
376 struct cnt_str *state = (struct cnt_str *) data;
380 /* skip empty segments and those that consist of only one or two dots */
381 if (memcmp(s, "..", min(len, 2)) == 0)
384 res = make_decoded_option(s, len, state->buf.s, state->buf.length);
388 state->buf.length -= res;
393 int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
397 { *buflen, buf }, 0 };
398 coap_parse_iterator_t pi;
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);
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 *)OC_QUERY_SEPARATOR,
416 (unsigned char *) "#", 1, &pi);
418 coap_split_path_impl(&pi, write_option, &tmp);
420 *buflen = tmp.buf.length;
424 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
427 coap_new_uri(const unsigned char *uri, unsigned int length)
429 unsigned char *result;
431 result = (unsigned char *) coap_malloc(length + 1 + sizeof(coap_uri_t));
436 memcpy(URI_DATA(result), uri, length);
437 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
439 if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *) result) < 0)
444 return (coap_uri_t *) result;
448 coap_clone_uri(const coap_uri_t *uri)
455 result = (coap_uri_t *) coap_malloc(
456 uri->query.length + uri->host.length + uri->path.length + sizeof(coap_uri_t) + 1);
461 memset(result, 0, sizeof(coap_uri_t));
463 result->port = uri->port;
465 if (uri->host.length)
467 result->host.s = URI_DATA(result);
468 result->host.length = uri->host.length;
470 memcpy(result->host.s, uri->host.s, uri->host.length);
473 if (uri->path.length)
475 result->path.s = URI_DATA(result) + uri->host.length;
476 result->path.length = uri->path.length;
478 memcpy(result->path.s, uri->path.s, uri->path.length);
481 if (uri->query.length)
483 result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
484 result->query.length = uri->query.length;
486 memcpy(result->query.s, uri->query.s, uri->query.length);
492 /* hash URI path segments */
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)
498 coap_hash(s, len, (unsigned char *) data);
501 int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key)
503 coap_parse_iterator_t pi;
508 memset(key, 0, sizeof(coap_key_t));
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);
517 /* iterator functions */
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)
526 pi->separator = separator;
531 pi->segment_length = 0;
537 coap_parse_next(coap_parse_iterator_t *pi)
539 unsigned char *p, *s;
544 /* proceed to the next segment */
545 pi->n -= pi->segment_length;
546 pi->pos += pi->segment_length;
547 pi->segment_length = 0;
551 if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos))
557 /* skip following separator (the first segment might not have one) */
559 if (strchr((const char*)s,*(pi->pos)))
567 while ((pi->segment_length < pi->n) && (!strchr((const char*)s,*p))
568 && (!strnchr(pi->delim, pi->dlen, *p)))
571 ++pi->segment_length;
577 pi->segment_length = 0;