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) {
38 while (len && *s++ != c)
41 return len ? s : NULL;
45 coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
47 int secure = 0, res = 0;
52 memset(uri, 0, sizeof(coap_uri_t));
53 uri->port = COAP_DEFAULT_PORT;
55 /* search for scheme */
62 q = (unsigned char *)COAP_DEFAULT_SCHEME;
63 while (len && *q && tolower(*p) == *q) {
67 /* If q does not point to the string end marker '\0', the schema
68 * identifier is wrong. */
74 /* There might be an additional 's', indicating the secure version: */
75 if (len && (secure = tolower(*p) == 's')) {
79 q = (unsigned char *)"://";
80 while (len && *q && tolower(*p) == *q) {
89 /* p points to beginning of Uri-Host */
91 if (len && *p == '[') { /* IPv6 address reference */
94 while (len && *q != ']') {
98 if (!len || *q != ']' || p == q) {
103 COAP_SET_STR(&uri->host, q - p, p);
105 } else { /* IPv4 address or FQDN */
106 while (len && *q != ':' && *q != '/' && *q != '?') {
117 COAP_SET_STR(&uri->host, q - p, p);
120 /* check for Uri-Port */
121 if (len && *q == ':') {
125 while (len && isdigit(*q)) {
130 if (p < q) { /* explicit port number given */
134 uri_port = uri_port * 10 + (*p++ - '0');
136 uri->port = uri_port;
140 path: /* at this point, p must point to an absolute path */
149 while (len && *q != '?') {
155 COAP_SET_STR(&uri->path, q - p, p);
161 if (len && *p == '?') {
164 COAP_SET_STR(&uri->query, len, p);
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).
182 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
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.
192 * @param seg The segment to decode and copy.
193 * @param length Length of @p seg.
194 * @param buf The result buffer.
197 decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
202 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
204 seg += 2; length -= 2;
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.
219 check_segment(const unsigned char *s, size_t length) {
225 if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
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.
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.
252 * @return The option's size, or @c -1 on error.
254 * @bug This function does not split segments that are bigger than 270
258 make_decoded_option(const unsigned char *s, size_t length,
259 unsigned char *buf, size_t buflen) {
264 debug("make_decoded_option(): buflen is 0!\n");
268 res = check_segment(s, length);
272 /* write option header using delta 0 and length res */
273 written = coap_opt_setheader(buf, buflen, 0, res);
275 assert(written <= buflen);
277 if (!written) /* encoding error */
280 buf += written; /* advance past option type/length */
283 if (buflen < (size_t)res) {
284 debug("buffer too small for option\n");
288 decode_segment(s, length, buf);
290 return written + res;
295 #define min(a,b) ((a) < (b) ? (a) : (b))
298 typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
301 * Splits the given string into segments. You should call one of the
302 * macros coap_split_path() or coap_split_query() instead.
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.
308 * @return The number of characters that have been parsed from @p s.
311 coap_split_path_impl(coap_parse_iterator_t *parse_iter,
312 segment_handler_t h, void *data) {
319 length = parse_iter->n;
321 while ( (seg = coap_parse_next(parse_iter)) ) {
323 /* any valid path segment is handled here: */
324 h(seg, parse_iter->segment_length, data);
327 return length - (parse_iter->n - parse_iter->segment_length);
336 write_option(unsigned char *s, size_t len, void *data) {
337 struct cnt_str *state = (struct cnt_str *)data;
341 /* skip empty segments and those that consist of only one or two dots */
342 if (memcmp(s, "..", min(len,2)) == 0)
345 res = make_decoded_option(s, len, state->buf.s, state->buf.length);
348 state->buf.length -= res;
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;
359 coap_parse_iterator_init((unsigned char *)s, length,
360 '/', (unsigned char *)"?#", 2, &pi);
361 coap_split_path_impl(&pi, write_option, &tmp);
363 *buflen = *buflen - tmp.buf.length;
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;
373 coap_parse_iterator_init((unsigned char *)s, length,
374 '&', (unsigned char *)"#", 1, &pi);
376 coap_split_path_impl(&pi, write_option, &tmp);
378 *buflen = tmp.buf.length;
382 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
385 coap_new_uri(const unsigned char *uri, unsigned int length) {
386 unsigned char *result;
388 result = (unsigned char*)coap_malloc(length + 1 + sizeof(coap_uri_t));
393 memcpy(URI_DATA(result), uri, length);
394 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
396 if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
400 return (coap_uri_t *)result;
404 coap_clone_uri(const coap_uri_t *uri) {
410 result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
411 uri->path.length + sizeof(coap_uri_t) + 1);
416 memset( result, 0, sizeof(coap_uri_t) );
418 result->port = uri->port;
420 if ( uri->host.length ) {
421 result->host.s = URI_DATA(result);
422 result->host.length = uri->host.length;
424 memcpy(result->host.s, uri->host.s, uri->host.length);
427 if ( uri->path.length ) {
428 result->path.s = URI_DATA(result) + uri->host.length;
429 result->path.length = uri->path.length;
431 memcpy(result->path.s, uri->path.s, uri->path.length);
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;
438 memcpy(result->query.s, uri->query.s, uri->query.length);
444 /* hash URI path segments */
446 /* The function signature of coap_hash() is different from
447 * segment_handler_t hence we use this wrapper as safe typecast. */
449 hash_segment(unsigned char *s, size_t len, void *data) {
450 coap_hash(s, len, (unsigned char*)data);
454 coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
455 coap_parse_iterator_t pi;
460 memset(key, 0, sizeof(coap_key_t));
462 coap_parse_iterator_init((unsigned char *)path, len,
463 '/', (unsigned char *)"?#", 2, &pi);
464 coap_split_path_impl(&pi, hash_segment, key);
469 /* iterator functions */
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) {
479 pi->separator = separator;
484 pi->segment_length = 0;
490 coap_parse_next(coap_parse_iterator_t *pi) {
496 /* proceed to the next segment */
497 pi->n -= pi->segment_length;
498 pi->pos += pi->segment_length;
499 pi->segment_length = 0;
502 if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos)) {
507 /* skip following separator (the first segment might not have one) */
508 if (*pi->pos == pi->separator) {
515 while (pi->segment_length < pi->n && *p != pi->separator &&
516 !strnchr(pi->delim, pi->dlen, *p)) {
518 ++pi->segment_length;
523 pi->segment_length = 0;