libcoap  4.2.0
uri.c
Go to the documentation of this file.
1 /* uri.c -- helper functions for URI treatment
2  *
3  * Copyright (C) 2010--2012,2015-2016 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 "coap_config.h"
10 
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14 
15 #if defined(HAVE_LIMITS_H)
16 #include <limits.h>
17 #endif
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
22 
23 #include "libcoap.h"
24 #include "mem.h"
25 #include "coap_debug.h"
26 #include "pdu.h"
27 #include "option.h"
28 #include "uri.h"
29 
42 strnchr(const uint8_t *s, size_t len, unsigned char c) {
43  while (len && *s++ != c)
44  --len;
45 
46  return len ? s : NULL;
47 }
48 
49 #define ISEQUAL_CI(a,b) \
50  ((a) == (b) || (islower(b) && ((a) == ((b) - 0x20))))
51 
52 int
53 coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
54  const uint8_t *p, *q;
55  int res = 0;
56 
57  if (!str_var || !uri)
58  return -1;
59 
60  memset(uri, 0, sizeof(coap_uri_t));
61  uri->port = COAP_DEFAULT_PORT;
62 
63  /* search for scheme */
64  p = str_var;
65  if (*p == '/') {
66  q = p;
67  goto path;
68  }
69 
70  q = (const uint8_t *)COAP_DEFAULT_SCHEME;
71  while (len && *q && ISEQUAL_CI(*p, *q)) {
72  ++p; ++q; --len;
73  }
74 
75  /* If q does not point to the string end marker '\0', the schema
76  * identifier is wrong. */
77  if (*q) {
78  res = -1;
79  goto error;
80  }
81 
82  /* There might be an additional 's', indicating the secure version: */
83  if (len && (*p == 's')) {
84  ++p; --len;
86  uri->port = COAPS_DEFAULT_PORT;
87  } else {
89  }
90 
91  /* There might be and addition "+tcp", indicating reliable transport: */
92  if (len>=4 && p[0] == '+' && p[1] == 't' && p[2] == 'c' && p[3] == 'p' ) {
93  p += 4;
94  len -= 4;
95  if (uri->scheme == COAP_URI_SCHEME_COAPS)
97  else
99  }
100  q = (const uint8_t *)"://";
101  while (len && *q && *p == *q) {
102  ++p; ++q; --len;
103  }
104 
105  if (*q) {
106  res = -2;
107  goto error;
108  }
109 
110  /* p points to beginning of Uri-Host */
111  q = p;
112  if (len && *p == '[') { /* IPv6 address reference */
113  ++p;
114 
115  while (len && *q != ']') {
116  ++q; --len;
117  }
118 
119  if (!len || *q != ']' || p == q) {
120  res = -3;
121  goto error;
122  }
123 
124  COAP_SET_STR(&uri->host, q - p, p);
125  ++q; --len;
126  } else { /* IPv4 address or FQDN */
127  while (len && *q != ':' && *q != '/' && *q != '?') {
128  ++q;
129  --len;
130  }
131 
132  if (p == q) {
133  res = -3;
134  goto error;
135  }
136 
137  COAP_SET_STR(&uri->host, q - p, p);
138  }
139 
140  /* check for Uri-Port */
141  if (len && *q == ':') {
142  p = ++q;
143  --len;
144 
145  while (len && isdigit(*q)) {
146  ++q;
147  --len;
148  }
149 
150  if (p < q) { /* explicit port number given */
151  int uri_port = 0;
152 
153  while (p < q)
154  uri_port = uri_port * 10 + (*p++ - '0');
155 
156  /* check if port number is in allowed range */
157  if (uri_port > 65535) {
158  res = -4;
159  goto error;
160  }
161 
162  uri->port = (uint16_t)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  p = ++q;
173  --len;
174 
175  while (len && *q != '?') {
176  ++q;
177  --len;
178  }
179 
180  if (p < q) {
181  COAP_SET_STR(&uri->path, q - p, p);
182  p = q;
183  }
184  }
185 
186  /* Uri_Query */
187  if (len && *p == '?') {
188  ++p;
189  --len;
190  COAP_SET_STR(&uri->query, len, p);
191  len = 0;
192  }
193 
194  end:
195  return len ? -1 : 0;
196 
197  error:
198  return res;
199 }
200 
208 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
209 
222 static void
223 decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
224 
225  while (length--) {
226 
227  if (*seg == '%') {
228  *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
229 
230  seg += 2; length -= 2;
231  } else {
232  *buf = *seg;
233  }
234 
235  ++buf; ++seg;
236  }
237 }
238 
244 static int
245 check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
246  size_t n = 0;
247 
248  while (length) {
249  if (*s == '%') {
250  if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
251  return -1;
252 
253  s += 2;
254  length -= 2;
255  }
256 
257  ++s; ++n; --length;
258  }
259 
260  *segment_size = n;
261 
262  return 0;
263 }
264 
285 static int
286 make_decoded_option(const uint8_t *s, size_t length,
287  unsigned char *buf, size_t buflen, size_t* optionsize) {
288  int res;
289  size_t segmentlen;
290  size_t written;
291 
292  if (!buflen) {
293  coap_log(LOG_DEBUG, "make_decoded_option(): buflen is 0!\n");
294  return -1;
295  }
296 
297  res = check_segment(s, length, &segmentlen);
298  if (res < 0)
299  return -1;
300 
301  /* write option header using delta 0 and length res */
302  written = coap_opt_setheader(buf, buflen, 0, segmentlen);
303 
304  assert(written <= buflen);
305 
306  if (!written) /* encoding error */
307  return -1;
308 
309  buf += written; /* advance past option type/length */
310  buflen -= written;
311 
312  if (buflen < segmentlen) {
313  coap_log(LOG_DEBUG, "buffer too small for option\n");
314  return -1;
315  }
316 
317  decode_segment(s, length, buf);
318 
319  *optionsize = written + segmentlen;
320 
321  return 0;
322 }
323 
324 
325 #ifndef min
326 #define min(a,b) ((a) < (b) ? (a) : (b))
327 #endif
328 
329 typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
330 
335 dots(const uint8_t *s, size_t len) {
336  return len && *s == '.' && (len == 1 || (len == 2 && *(s+1) == '.'));
337 }
338 
350 static size_t
351 coap_split_path_impl(const uint8_t *s, size_t length,
352  segment_handler_t h, void *data) {
353 
354  const uint8_t *p, *q;
355 
356  p = q = s;
357  while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
358  if (*q == '/') { /* start new segment */
359 
360  if (!dots(p, q - p)) {
361  h(p, q - p, data);
362  }
363 
364  p = q + 1;
365  }
366 
367  q++;
368  length--;
369  }
370 
371  /* write last segment */
372  if (!dots(p, q - p)) {
373  h(p, q - p, data);
374  }
375 
376  return q - s;
377 }
378 
379 struct cnt_str {
381  int n;
382 };
383 
384 static void
385 write_option(const uint8_t *s, size_t len, void *data) {
386  struct cnt_str *state = (struct cnt_str *)data;
387  int res;
388  size_t optionsize;
389  assert(state);
390 
391  res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
392  if (res == 0) {
393  state->buf.s += optionsize;
394  state->buf.length -= optionsize;
395  state->n++;
396  }
397 }
398 
399 int
400 coap_split_path(const uint8_t *s, size_t length,
401  unsigned char *buf, size_t *buflen) {
402  struct cnt_str tmp = { { *buflen, buf }, 0 };
403 
404  coap_split_path_impl(s, length, write_option, &tmp);
405 
406  *buflen = *buflen - tmp.buf.length;
407 
408  return tmp.n;
409 }
410 
411 int
412 coap_split_query(const uint8_t *s, size_t length,
413  unsigned char *buf, size_t *buflen) {
414  struct cnt_str tmp = { { *buflen, buf }, 0 };
415  const uint8_t *p;
416 
417  p = s;
418  while (length > 0 && *s != '#') {
419  if (*s == '&') { /* start new query element */
420  write_option(p, s - p, &tmp);
421  p = s + 1;
422  }
423 
424  s++;
425  length--;
426  }
427 
428  /* write last query element */
429  write_option(p, s - p, &tmp);
430 
431  *buflen = *buflen - tmp.buf.length;
432  return tmp.n;
433 }
434 
435 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
436 
437 coap_uri_t *
438 coap_new_uri(const uint8_t *uri, unsigned int length) {
439  unsigned char *result;
440 
441  result = (unsigned char*)coap_malloc(length + 1 + sizeof(coap_uri_t));
442 
443  if (!result)
444  return NULL;
445 
446  memcpy(URI_DATA(result), uri, length);
447  URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
448 
449  if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
450  coap_free(result);
451  return NULL;
452  }
453  return (coap_uri_t *)result;
454 }
455 
456 coap_uri_t *
458  coap_uri_t *result;
459  uint8_t *p;
460 
461  if ( !uri )
462  return NULL;
463 
464  result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
465  uri->path.length + sizeof(coap_uri_t) + 1);
466 
467  if ( !result )
468  return NULL;
469 
470  memset( result, 0, sizeof(coap_uri_t) );
471 
472  result->port = uri->port;
473 
474  if ( uri->host.length ) {
475  result->host.s = p = URI_DATA(result);
476  result->host.length = uri->host.length;
477 
478  memcpy(p, uri->host.s, uri->host.length);
479  }
480 
481  if ( uri->path.length ) {
482  result->path.s = p = URI_DATA(result) + uri->host.length;
483  result->path.length = uri->path.length;
484 
485  memcpy(p, uri->path.s, uri->path.length);
486  }
487 
488  if ( uri->query.length ) {
489  result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
490  result->query.length = uri->query.length;
491 
492  memcpy (p, uri->query.s, uri->query.length);
493  }
494 
495  return result;
496 }
497 
500  return ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' )
501  || ( c >= '0' && c <= '9' ) || c == '-' || c == '.' || c == '_'
502  || c == '~' || c == '!' || c == '$' || c == '\'' || c == '('
503  || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c=='='
504  || c==':' || c=='@' || c == '&';
505 }
506 
509  return is_unescaped_in_path(c) || c=='/' || c=='?';
510 }
511 
513  coap_opt_iterator_t opt_iter;
515  coap_opt_t *q;
516  coap_string_t *query = NULL;
517  size_t length = 0;
518  static const uint8_t hex[] = "0123456789ABCDEF";
519 
522  coap_option_iterator_init(request, &opt_iter, f);
523  while ((q = coap_option_next(&opt_iter))) {
524  uint16_t seg_len = coap_opt_length(q), i;
525  const uint8_t *seg= coap_opt_value(q);
526  for (i = 0; i < seg_len; i++) {
527  if (is_unescaped_in_query(seg[i]))
528  length += 1;
529  else
530  length += 3;
531  }
532  length += 1;
533  }
534  if (length > 0)
535  length -= 1;
536  if (length > 0) {
537  query = coap_new_string(length);
538  if (query) {
539  query->length = length;
540  unsigned char *s = query->s;
541  coap_option_iterator_init(request, &opt_iter, f);
542  while ((q = coap_option_next(&opt_iter))) {
543  if (s != query->s)
544  *s++ = '&';
545  uint16_t seg_len = coap_opt_length(q), i;
546  const uint8_t *seg= coap_opt_value(q);
547  for (i = 0; i < seg_len; i++) {
548  if (is_unescaped_in_query(seg[i])) {
549  *s++ = seg[i];
550  } else {
551  *s++ = '%';
552  *s++ = hex[seg[i]>>4];
553  *s++ = hex[seg[i]&0x0F];
554  }
555  }
556  }
557  }
558  }
559  return query;
560 }
561 
563  coap_opt_iterator_t opt_iter;
565  coap_opt_t *q;
566  coap_string_t *uri_path = NULL;
567  size_t length = 0;
568  static const uint8_t hex[] = "0123456789ABCDEF";
569 
572  coap_option_iterator_init(request, &opt_iter, f);
573  while ((q = coap_option_next(&opt_iter))) {
574  uint16_t seg_len = coap_opt_length(q), i;
575  const uint8_t *seg= coap_opt_value(q);
576  for (i = 0; i < seg_len; i++) {
577  if (is_unescaped_in_path(seg[i]))
578  length += 1;
579  else
580  length += 3;
581  }
582  /* bump for the leading "/" */
583  length += 1;
584  }
585  /* The first entry does not have a leading "/" */
586  if (length > 0)
587  length -= 1;
588 
589  /* if 0, either no URI_PATH Option, or the first one was empty */
590  uri_path = coap_new_string(length);
591  if (uri_path) {
592  uri_path->length = length;
593  unsigned char *s = uri_path->s;
594  int n = 0;
595  coap_option_iterator_init(request, &opt_iter, f);
596  while ((q = coap_option_next(&opt_iter))) {
597  if (n++) {
598  *s++ = '/';
599  }
600  uint16_t seg_len = coap_opt_length(q), i;
601  const uint8_t *seg= coap_opt_value(q);
602  for (i = 0; i < seg_len; i++) {
603  if (is_unescaped_in_path(seg[i])) {
604  *s++ = seg[i];
605  } else {
606  *s++ = '%';
607  *s++ = hex[seg[i]>>4];
608  *s++ = hex[seg[i]&0x0F];
609  }
610  }
611  }
612  }
613  return uri_path;
614 }
615 
Representation of parsed URI.
Definition: uri.h:36
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:25
#define URI_DATA(uriobj)
Definition: uri.c:435
int coap_split_query(const uint8_t *s, size_t length, unsigned char *buf, size_t *buflen)
Splits the given URI query into segments.
Definition: uri.c:412
static void write_option(const uint8_t *s, size_t len, void *data)
Definition: uri.c:385
coap_string_t * coap_get_query(const coap_pdu_t *request)
Definition: uri.c:512
Definition: uri.c:379
static int make_decoded_option(const uint8_t *s, size_t length, unsigned char *buf, size_t buflen, size_t *optionsize)
Writes a coap option from given string s to buf.
Definition: uri.c:286
int coap_option_filter_set(coap_opt_filter_t filter, uint16_t type)
Sets the corresponding entry for type in filter.
Definition: option.c:534
Debug.
Definition: coap_debug.h:49
coap_str_const_t host
host part of the URI
Definition: uri.h:37
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:157
Helpers for handling options in CoAP PDUs.
size_t length
length of string
Definition: str.h:34
uint8_t * s
string data
Definition: str.h:27
static int check_segment(const uint8_t *s, size_t length, size_t *segment_size)
Runs through the given path (or query) segment and checks if percent-encodings are correct...
Definition: uri.c:245
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition: uri.c:329
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:75
Coap string data definition.
Definition: str.h:25
int coap_split_path(const uint8_t *s, size_t length, unsigned char *buf, size_t *buflen)
Splits the given URI path into segments.
Definition: uri.c:400
#define ISEQUAL_CI(a, b)
Definition: uri.c:49
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
Definition: str.c:18
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
uint16_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:249
#define assert(...)
Definition: mem.c:18
enum coap_uri_scheme_t scheme
The parsed scheme specifier.
Definition: uri.h:44
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Definition: uri.c:562
#define COAPS_DEFAULT_PORT
Definition: pdu.h:29
Iterator to run through PDU options.
Definition: option.h:237
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:82
coap_string_t buf
Definition: uri.c:380
COAP_STATIC_INLINE int dots(const uint8_t *s, size_t len)
Checks if path segment s consists of one or two dots.
Definition: uri.c:335
#define COAP_DEFAULT_SCHEME
Definition: pdu.h:65
COAP_STATIC_INLINE void coap_option_filter_clear(coap_opt_filter_t f)
Clears filter f.
Definition: option.h:130
uint16_t port
The port in host byte order.
Definition: uri.h:38
#define COAP_STATIC_INLINE
Definition: libcoap.h:38
#define COAP_DEFAULT_PORT
Definition: pdu.h:28
Pre-defined constants that reflect defaults for CoAP.
size_t length
length of string
Definition: str.h:26
COAP_STATIC_INLINE int is_unescaped_in_path(const uint8_t c)
Definition: uri.c:499
uint16_t coap_opt_filter_t[COAP_OPT_FILTER_SIZE]
Fixed-size vector we use for option filtering.
Definition: option.h:119
coap_uri_t * coap_new_uri(const uint8_t *uri, unsigned int length)
Creates a new coap_uri_t object from the specified URI.
Definition: uri.c:438
const uint8_t * s
string data
Definition: str.h:35
coap_uri_t * coap_clone_uri(const coap_uri_t *uri)
Clones the specified coap_uri_t object.
Definition: uri.c:457
size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, uint16_t delta, size_t length)
Encodes the given delta and length values into opt.
Definition: option.c:329
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:286
coap_str_const_t query
The query part if present.
Definition: uri.h:41
#define COAP_OPTION_URI_PATH
Definition: pdu.h:98
COAP_STATIC_INLINE int is_unescaped_in_query(const uint8_t c)
Definition: uri.c:508
#define COAP_SET_STR(st, l, v)
Definition: str.h:38
static void decode_segment(const uint8_t *seg, size_t length, unsigned char *buf)
Decodes percent-encoded characters while copying the string seg of size length to buf...
Definition: uri.c:223
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:102
int n
Definition: uri.c:381
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:122
int coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition: uri.c:53
unsigned char uint8_t
Definition: uthash.h:79
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
Initializes the given option iterator oi to point to the beginning of the pdu&#39;s option list...
Definition: option.c:121
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition: uri.c:208
COAP_STATIC_INLINE const uint8_t * strnchr(const uint8_t *s, size_t len, unsigned char c)
A length-safe version of strchr().
Definition: uri.c:42
coap_str_const_t path
Beginning of the first path segment.
Definition: uri.h:39
static size_t coap_split_path_impl(const uint8_t *s, size_t length, segment_handler_t h, void *data)
Splits the given string into segments.
Definition: uri.c:351