libcoap  4.2.1
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_internal.h"
10 
11 #if defined(HAVE_LIMITS_H)
12 #include <limits.h>
13 #endif
14 
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 
32 strnchr(const uint8_t *s, size_t len, unsigned char c) {
33  while (len && *s++ != c)
34  --len;
35 
36  return len ? s : NULL;
37 }
38 
39 #define ISEQUAL_CI(a,b) \
40  ((a) == (b) || (islower(b) && ((a) == ((b) - 0x20))))
41 
42 int
43 coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
44  const uint8_t *p, *q;
45  int res = 0;
46 
47  if (!str_var || !uri)
48  return -1;
49 
50  memset(uri, 0, sizeof(coap_uri_t));
51  uri->port = COAP_DEFAULT_PORT;
52 
53  /* search for scheme */
54  p = str_var;
55  if (*p == '/') {
56  q = p;
57  goto path;
58  }
59 
60  q = (const uint8_t *)COAP_DEFAULT_SCHEME;
61  while (len && *q && ISEQUAL_CI(*p, *q)) {
62  ++p; ++q; --len;
63  }
64 
65  /* If q does not point to the string end marker '\0', the schema
66  * identifier is wrong. */
67  if (*q) {
68  res = -1;
69  goto error;
70  }
71 
72  /* There might be an additional 's', indicating the secure version: */
73  if (len && (*p == 's')) {
74  ++p; --len;
76  uri->port = COAPS_DEFAULT_PORT;
77  } else {
79  }
80 
81  /* There might be and addition "+tcp", indicating reliable transport: */
82  if (len>=4 && p[0] == '+' && p[1] == 't' && p[2] == 'c' && p[3] == 'p' ) {
83  p += 4;
84  len -= 4;
85  if (uri->scheme == COAP_URI_SCHEME_COAPS)
87  else
89  }
90  q = (const uint8_t *)"://";
91  while (len && *q && *p == *q) {
92  ++p; ++q; --len;
93  }
94 
95  if (*q) {
96  res = -2;
97  goto error;
98  }
99 
100  /* p points to beginning of Uri-Host */
101  q = p;
102  if (len && *p == '[') { /* IPv6 address reference */
103  ++p;
104 
105  while (len && *q != ']') {
106  ++q; --len;
107  }
108 
109  if (!len || *q != ']' || p == q) {
110  res = -3;
111  goto error;
112  }
113 
114  COAP_SET_STR(&uri->host, q - p, p);
115  ++q; --len;
116  } else { /* IPv4 address or FQDN */
117  while (len && *q != ':' && *q != '/' && *q != '?') {
118  ++q;
119  --len;
120  }
121 
122  if (p == q) {
123  res = -3;
124  goto error;
125  }
126 
127  COAP_SET_STR(&uri->host, q - p, p);
128  }
129 
130  /* check for Uri-Port */
131  if (len && *q == ':') {
132  p = ++q;
133  --len;
134 
135  while (len && isdigit(*q)) {
136  ++q;
137  --len;
138  }
139 
140  if (p < q) { /* explicit port number given */
141  int uri_port = 0;
142 
143  while ((p < q) && (uri_port <= UINT16_MAX))
144  uri_port = uri_port * 10 + (*p++ - '0');
145 
146  /* check if port number is in allowed range */
147  if (uri_port > UINT16_MAX) {
148  res = -4;
149  goto error;
150  }
151 
152  uri->port = (uint16_t)uri_port;
153  }
154  }
155 
156  path: /* at this point, p must point to an absolute path */
157 
158  if (!len)
159  goto end;
160 
161  if (*q == '/') {
162  p = ++q;
163  --len;
164 
165  while (len && *q != '?') {
166  ++q;
167  --len;
168  }
169 
170  if (p < q) {
171  COAP_SET_STR(&uri->path, q - p, p);
172  p = q;
173  }
174  }
175 
176  /* Uri_Query */
177  if (len && *p == '?') {
178  ++p;
179  --len;
180  COAP_SET_STR(&uri->query, len, p);
181  len = 0;
182  }
183 
184  end:
185  return len ? -1 : 0;
186 
187  error:
188  return res;
189 }
190 
198 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
199 
212 static void
213 decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
214 
215  while (length--) {
216 
217  if (*seg == '%') {
218  *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
219 
220  seg += 2; length -= 2;
221  } else {
222  *buf = *seg;
223  }
224 
225  ++buf; ++seg;
226  }
227 }
228 
234 static int
235 check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
236  size_t n = 0;
237 
238  while (length) {
239  if (*s == '%') {
240  if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
241  return -1;
242 
243  s += 2;
244  length -= 2;
245  }
246 
247  ++s; ++n; --length;
248  }
249 
250  *segment_size = n;
251 
252  return 0;
253 }
254 
275 static int
276 make_decoded_option(const uint8_t *s, size_t length,
277  unsigned char *buf, size_t buflen, size_t* optionsize) {
278  int res;
279  size_t segmentlen;
280  size_t written;
281 
282  if (!buflen) {
283  coap_log(LOG_DEBUG, "make_decoded_option(): buflen is 0!\n");
284  return -1;
285  }
286 
287  res = check_segment(s, length, &segmentlen);
288  if (res < 0)
289  return -1;
290 
291  /* write option header using delta 0 and length res */
292  written = coap_opt_setheader(buf, buflen, 0, segmentlen);
293 
294  assert(written <= buflen);
295 
296  if (!written) /* encoding error */
297  return -1;
298 
299  buf += written; /* advance past option type/length */
300  buflen -= written;
301 
302  if (buflen < segmentlen) {
303  coap_log(LOG_DEBUG, "buffer too small for option\n");
304  return -1;
305  }
306 
307  decode_segment(s, length, buf);
308 
309  *optionsize = written + segmentlen;
310 
311  return 0;
312 }
313 
314 
315 #ifndef min
316 #define min(a,b) ((a) < (b) ? (a) : (b))
317 #endif
318 
319 typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
320 
325 dots(const uint8_t *s, size_t len) {
326  return len && *s == '.' && (len == 1 || (len == 2 && *(s+1) == '.'));
327 }
328 
340 static size_t
341 coap_split_path_impl(const uint8_t *s, size_t length,
342  segment_handler_t h, void *data) {
343 
344  const uint8_t *p, *q;
345 
346  p = q = s;
347  while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
348  if (*q == '/') { /* start new segment */
349 
350  if (!dots(p, q - p)) {
351  h(p, q - p, data);
352  }
353 
354  p = q + 1;
355  }
356 
357  q++;
358  length--;
359  }
360 
361  /* write last segment */
362  if (!dots(p, q - p)) {
363  h(p, q - p, data);
364  }
365 
366  return q - s;
367 }
368 
369 struct cnt_str {
371  int n;
372 };
373 
374 static void
375 write_option(const uint8_t *s, size_t len, void *data) {
376  struct cnt_str *state = (struct cnt_str *)data;
377  int res;
378  size_t optionsize;
379  assert(state);
380 
381  res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
382  if (res == 0) {
383  state->buf.s += optionsize;
384  state->buf.length -= optionsize;
385  state->n++;
386  }
387 }
388 
389 int
390 coap_split_path(const uint8_t *s, size_t length,
391  unsigned char *buf, size_t *buflen) {
392  struct cnt_str tmp = { { *buflen, buf }, 0 };
393 
394  coap_split_path_impl(s, length, write_option, &tmp);
395 
396  *buflen = *buflen - tmp.buf.length;
397 
398  return tmp.n;
399 }
400 
401 int
402 coap_split_query(const uint8_t *s, size_t length,
403  unsigned char *buf, size_t *buflen) {
404  struct cnt_str tmp = { { *buflen, buf }, 0 };
405  const uint8_t *p;
406 
407  p = s;
408  while (length > 0 && *s != '#') {
409  if (*s == '&') { /* start new query element */
410  write_option(p, s - p, &tmp);
411  p = s + 1;
412  }
413 
414  s++;
415  length--;
416  }
417 
418  /* write last query element */
419  write_option(p, s - p, &tmp);
420 
421  *buflen = *buflen - tmp.buf.length;
422  return tmp.n;
423 }
424 
425 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
426 
427 coap_uri_t *
428 coap_new_uri(const uint8_t *uri, unsigned int length) {
429  unsigned char *result;
430 
431  result = (unsigned char*)coap_malloc(length + 1 + sizeof(coap_uri_t));
432 
433  if (!result)
434  return NULL;
435 
436  memcpy(URI_DATA(result), uri, length);
437  URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
438 
439  if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
440  coap_free(result);
441  return NULL;
442  }
443  return (coap_uri_t *)result;
444 }
445 
446 coap_uri_t *
448  coap_uri_t *result;
449  uint8_t *p;
450 
451  if ( !uri )
452  return NULL;
453 
454  result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
455  uri->path.length + sizeof(coap_uri_t) + 1);
456 
457  if ( !result )
458  return NULL;
459 
460  memset( result, 0, sizeof(coap_uri_t) );
461 
462  result->port = uri->port;
463 
464  if ( uri->host.length ) {
465  result->host.s = p = URI_DATA(result);
466  result->host.length = uri->host.length;
467 
468  memcpy(p, uri->host.s, uri->host.length);
469  }
470 
471  if ( uri->path.length ) {
472  result->path.s = p = URI_DATA(result) + uri->host.length;
473  result->path.length = uri->path.length;
474 
475  memcpy(p, uri->path.s, uri->path.length);
476  }
477 
478  if ( uri->query.length ) {
479  result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
480  result->query.length = uri->query.length;
481 
482  memcpy (p, uri->query.s, uri->query.length);
483  }
484 
485  return result;
486 }
487 
490  return ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' )
491  || ( c >= '0' && c <= '9' ) || c == '-' || c == '.' || c == '_'
492  || c == '~' || c == '!' || c == '$' || c == '\'' || c == '('
493  || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c=='='
494  || c==':' || c=='@' || c == '&';
495 }
496 
499  return is_unescaped_in_path(c) || c=='/' || c=='?';
500 }
501 
503  coap_opt_iterator_t opt_iter;
505  coap_opt_t *q;
506  coap_string_t *query = NULL;
507  size_t length = 0;
508  static const uint8_t hex[] = "0123456789ABCDEF";
509 
512  coap_option_iterator_init(request, &opt_iter, f);
513  while ((q = coap_option_next(&opt_iter))) {
514  uint16_t seg_len = coap_opt_length(q), i;
515  const uint8_t *seg= coap_opt_value(q);
516  for (i = 0; i < seg_len; i++) {
517  if (is_unescaped_in_query(seg[i]))
518  length += 1;
519  else
520  length += 3;
521  }
522  length += 1;
523  }
524  if (length > 0)
525  length -= 1;
526  if (length > 0) {
527  query = coap_new_string(length);
528  if (query) {
529  query->length = length;
530  unsigned char *s = query->s;
531  coap_option_iterator_init(request, &opt_iter, f);
532  while ((q = coap_option_next(&opt_iter))) {
533  if (s != query->s)
534  *s++ = '&';
535  uint16_t seg_len = coap_opt_length(q), i;
536  const uint8_t *seg= coap_opt_value(q);
537  for (i = 0; i < seg_len; i++) {
538  if (is_unescaped_in_query(seg[i])) {
539  *s++ = seg[i];
540  } else {
541  *s++ = '%';
542  *s++ = hex[seg[i]>>4];
543  *s++ = hex[seg[i]&0x0F];
544  }
545  }
546  }
547  }
548  }
549  return query;
550 }
551 
553  coap_opt_iterator_t opt_iter;
555  coap_opt_t *q;
556  coap_string_t *uri_path = NULL;
557  size_t length = 0;
558  static const uint8_t hex[] = "0123456789ABCDEF";
559 
562  coap_option_iterator_init(request, &opt_iter, f);
563  while ((q = coap_option_next(&opt_iter))) {
564  uint16_t seg_len = coap_opt_length(q), i;
565  const uint8_t *seg= coap_opt_value(q);
566  for (i = 0; i < seg_len; i++) {
567  if (is_unescaped_in_path(seg[i]))
568  length += 1;
569  else
570  length += 3;
571  }
572  /* bump for the leading "/" */
573  length += 1;
574  }
575  /* The first entry does not have a leading "/" */
576  if (length > 0)
577  length -= 1;
578 
579  /* if 0, either no URI_PATH Option, or the first one was empty */
580  uri_path = coap_new_string(length);
581  if (uri_path) {
582  uri_path->length = length;
583  unsigned char *s = uri_path->s;
584  int n = 0;
585  coap_option_iterator_init(request, &opt_iter, f);
586  while ((q = coap_option_next(&opt_iter))) {
587  if (n++) {
588  *s++ = '/';
589  }
590  uint16_t seg_len = coap_opt_length(q), i;
591  const uint8_t *seg= coap_opt_value(q);
592  for (i = 0; i < seg_len; i++) {
593  if (is_unescaped_in_path(seg[i])) {
594  *s++ = seg[i];
595  } else {
596  *s++ = '%';
597  *s++ = hex[seg[i]>>4];
598  *s++ = hex[seg[i]&0x0F];
599  }
600  }
601  }
602  }
603  return uri_path;
604 }
605 
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:425
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:402
static void write_option(const uint8_t *s, size_t len, void *data)
Definition: uri.c:375
coap_string_t * coap_get_query(const coap_pdu_t *request)
Definition: uri.c:502
Definition: uri.c:369
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:276
int coap_option_filter_set(coap_opt_filter_t filter, uint16_t type)
Sets the corresponding entry for type in filter.
Definition: option.c:523
Debug.
Definition: coap_debug.h:55
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:146
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:235
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition: uri.c:319
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:390
#define ISEQUAL_CI(a, b)
Definition: uri.c:39
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:13
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:238
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:552
#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:370
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:325
#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
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:489
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:428
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:447
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:318
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:275
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:498
#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:213
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:102
int n
Definition: uri.c:371
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:129
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:43
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:110
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition: uri.c:198
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:32
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:341
Pulls together all the internal only header files.