libcoap  4.3.0rc2
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 "coap3/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 
31 COAP_STATIC_INLINE const uint8_t *
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 typedef enum coap_uri_check_t {
46 
47 static int
48 coap_split_uri_sub(const uint8_t *str_var,
49  size_t len,
50  coap_uri_t *uri,
51  coap_uri_check_t check_proxy) {
52  const uint8_t *p, *q;
53  int res = 0;
54  int is_http_proxy_scheme = 0;
55  size_t keep_len = len;
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  if (check_proxy == COAP_URI_CHECK_PROXY)
67  return -1;
68  q = p;
69  goto path;
70  }
71 
72  q = (const uint8_t *)COAP_DEFAULT_SCHEME;
73  while (len && *q && ISEQUAL_CI(*p, *q)) {
74  ++p; ++q; --len;
75  }
76  if (*q && check_proxy == COAP_URI_CHECK_PROXY) {
77  /* Scheme could be something other than coap */
78  len = keep_len;
79  p = str_var;
80  q = (const uint8_t *)"http";
81  while (len && *q && ISEQUAL_CI(*p, *q)) {
82  ++p; ++q; --len;
83  }
84  if (*q == 0) {
85  if (len && ISEQUAL_CI(*p, 's')) {
86  /* https:// */
87  ++p; --len;
89  uri->port = 443;
90  }
91  else {
92  /* http:// */
94  uri->port = 80;
95  }
96  }
97  else {
98  /* Unknown scheme */
99  res = -1;
100  goto error;
101  }
102  is_http_proxy_scheme = 1;
103  }
104 
105  /* If q does not point to the string end marker '\0', the schema
106  * identifier is wrong. */
107  if (*q) {
108  res = -1;
109  goto error;
110  }
111 
112  if (is_http_proxy_scheme == 0) {
113  /* There might be an additional 's', indicating the secure version: */
114  if (len && (*p == 's')) {
115  ++p; --len;
117  uri->port = COAPS_DEFAULT_PORT;
118  } else {
120  }
121 
122  /* There might be an addition "+tcp", indicating reliable transport: */
123  if (len>=4 && p[0] == '+' && p[1] == 't' && p[2] == 'c' && p[3] == 'p' ) {
124  p += 4;
125  len -= 4;
126  if (uri->scheme == COAP_URI_SCHEME_COAPS)
128  else
130  }
131  }
132  q = (const uint8_t *)"://";
133  while (len && *q && *p == *q) {
134  ++p; ++q; --len;
135  }
136 
137  if (*q) {
138  res = -2;
139  goto error;
140  }
141 
142  /* p points to beginning of Uri-Host */
143  q = p;
144  if (len && *p == '[') { /* IPv6 address reference */
145  ++p;
146 
147  while (len && *q != ']') {
148  ++q; --len;
149  }
150 
151  if (!len || *q != ']' || p == q) {
152  res = -3;
153  goto error;
154  }
155 
156  COAP_SET_STR(&uri->host, q - p, p);
157  ++q; --len;
158  } else { /* IPv4 address or FQDN */
159  while (len && *q != ':' && *q != '/' && *q != '?') {
160  ++q;
161  --len;
162  }
163 
164  if (p == q) {
165  res = -3;
166  goto error;
167  }
168 
169  COAP_SET_STR(&uri->host, q - p, p);
170  }
171 
172  /* check for Uri-Port */
173  if (len && *q == ':') {
174  p = ++q;
175  --len;
176 
177  while (len && isdigit(*q)) {
178  ++q;
179  --len;
180  }
181 
182  if (p < q) { /* explicit port number given */
183  int uri_port = 0;
184 
185  while ((p < q) && (uri_port <= UINT16_MAX))
186  uri_port = uri_port * 10 + (*p++ - '0');
187 
188  /* check if port number is in allowed range */
189  if (uri_port > UINT16_MAX) {
190  res = -4;
191  goto error;
192  }
193 
194  uri->port = (uint16_t)uri_port;
195  }
196  }
197 
198  path: /* at this point, p must point to an absolute path */
199 
200  if (!len)
201  goto end;
202 
203  if (*q == '/') {
204  p = ++q;
205  --len;
206 
207  while (len && *q != '?') {
208  ++q;
209  --len;
210  }
211 
212  if (p < q) {
213  COAP_SET_STR(&uri->path, q - p, p);
214  p = q;
215  }
216  }
217 
218  /* Uri_Query */
219  if (len && *p == '?') {
220  ++p;
221  --len;
222  COAP_SET_STR(&uri->query, len, p);
223  len = 0;
224  }
225 
226  end:
227  return len ? -1 : 0;
228 
229  error:
230  return res;
231 }
232 
233 int
234 coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
235  return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_URI);
236 }
237 
238 int
239 coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
240  return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_PROXY);
241 }
242 
250 #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
251 
264 static void
265 decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
266 
267  while (length--) {
268 
269  if (*seg == '%') {
270  *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
271 
272  seg += 2; length -= 2;
273  } else {
274  *buf = *seg;
275  }
276 
277  ++buf; ++seg;
278  }
279 }
280 
286 static int
287 check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
288  size_t n = 0;
289 
290  while (length) {
291  if (*s == '%') {
292  if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
293  return -1;
294 
295  s += 2;
296  length -= 2;
297  }
298 
299  ++s; ++n; --length;
300  }
301 
302  *segment_size = n;
303 
304  return 0;
305 }
306 
327 static int
328 make_decoded_option(const uint8_t *s, size_t length,
329  unsigned char *buf, size_t buflen, size_t* optionsize) {
330  int res;
331  size_t segmentlen;
332  size_t written;
333 
334  if (!buflen) {
335  coap_log(LOG_DEBUG, "make_decoded_option(): buflen is 0!\n");
336  return -1;
337  }
338 
339  res = check_segment(s, length, &segmentlen);
340  if (res < 0)
341  return -1;
342 
343  /* write option header using delta 0 and length res */
344  written = coap_opt_setheader(buf, buflen, 0, segmentlen);
345 
346  assert(written <= buflen);
347 
348  if (!written) /* encoding error */
349  return -1;
350 
351  buf += written; /* advance past option type/length */
352  buflen -= written;
353 
354  if (buflen < segmentlen) {
355  coap_log(LOG_DEBUG, "buffer too small for option\n");
356  return -1;
357  }
358 
359  decode_segment(s, length, buf);
360 
361  *optionsize = written + segmentlen;
362 
363  return 0;
364 }
365 
366 
367 #ifndef min
368 #define min(a,b) ((a) < (b) ? (a) : (b))
369 #endif
370 
371 typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
372 
377 dots(const uint8_t *s, size_t len) {
378  return len && *s == '.' && (len == 1 || (len == 2 && *(s+1) == '.'));
379 }
380 
392 static size_t
393 coap_split_path_impl(const uint8_t *s, size_t length,
394  segment_handler_t h, void *data) {
395 
396  const uint8_t *p, *q;
397 
398  p = q = s;
399  while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
400  if (*q == '/') { /* start new segment */
401 
402  if (!dots(p, q - p)) {
403  h(p, q - p, data);
404  }
405 
406  p = q + 1;
407  }
408 
409  q++;
410  length--;
411  }
412 
413  /* write last segment */
414  if (!dots(p, q - p)) {
415  h(p, q - p, data);
416  }
417 
418  return q - s;
419 }
420 
421 struct cnt_str {
423  int n;
424 };
425 
426 static void
427 write_option(const uint8_t *s, size_t len, void *data) {
428  struct cnt_str *state = (struct cnt_str *)data;
429  int res;
430  size_t optionsize;
431  assert(state);
432 
433  res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
434  if (res == 0) {
435  state->buf.s += optionsize;
436  state->buf.length -= optionsize;
437  state->n++;
438  }
439 }
440 
441 int
442 coap_split_path(const uint8_t *s, size_t length,
443  unsigned char *buf, size_t *buflen) {
444  struct cnt_str tmp = { { *buflen, buf }, 0 };
445 
446  coap_split_path_impl(s, length, write_option, &tmp);
447 
448  *buflen = *buflen - tmp.buf.length;
449 
450  return tmp.n;
451 }
452 
453 int
454 coap_split_query(const uint8_t *s, size_t length,
455  unsigned char *buf, size_t *buflen) {
456  struct cnt_str tmp = { { *buflen, buf }, 0 };
457  const uint8_t *p;
458 
459  p = s;
460  while (length > 0 && *s != '#') {
461  if (*s == '&') { /* start new query element */
462  write_option(p, s - p, &tmp);
463  p = s + 1;
464  }
465 
466  s++;
467  length--;
468  }
469 
470  /* write last query element */
471  write_option(p, s - p, &tmp);
472 
473  *buflen = *buflen - tmp.buf.length;
474  return tmp.n;
475 }
476 
477 #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
478 
479 coap_uri_t *
480 coap_new_uri(const uint8_t *uri, unsigned int length) {
481  unsigned char *result;
482 
483  result = (unsigned char*)coap_malloc(length + 1 + sizeof(coap_uri_t));
484 
485  if (!result)
486  return NULL;
487 
488  memcpy(URI_DATA(result), uri, length);
489  URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
490 
491  if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
492  coap_free(result);
493  return NULL;
494  }
495  return (coap_uri_t *)result;
496 }
497 
498 coap_uri_t *
500  coap_uri_t *result;
501  uint8_t *p;
502 
503  if ( !uri )
504  return NULL;
505 
506  result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
507  uri->path.length + sizeof(coap_uri_t) + 1);
508 
509  if ( !result )
510  return NULL;
511 
512  memset( result, 0, sizeof(coap_uri_t) );
513 
514  result->port = uri->port;
515 
516  if ( uri->host.length ) {
517  result->host.s = p = URI_DATA(result);
518  result->host.length = uri->host.length;
519 
520  memcpy(p, uri->host.s, uri->host.length);
521  }
522 
523  if ( uri->path.length ) {
524  result->path.s = p = URI_DATA(result) + uri->host.length;
525  result->path.length = uri->path.length;
526 
527  memcpy(p, uri->path.s, uri->path.length);
528  }
529 
530  if ( uri->query.length ) {
531  result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
532  result->query.length = uri->query.length;
533 
534  memcpy (p, uri->query.s, uri->query.length);
535  }
536 
537  return result;
538 }
539 
541 is_unescaped_in_path(const uint8_t c) {
542  return ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' )
543  || ( c >= '0' && c <= '9' ) || c == '-' || c == '.' || c == '_'
544  || c == '~' || c == '!' || c == '$' || c == '\'' || c == '('
545  || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c=='='
546  || c==':' || c=='@' || c == '&';
547 }
548 
550 is_unescaped_in_query(const uint8_t c) {
551  return is_unescaped_in_path(c) || c=='/' || c=='?';
552 }
553 
555  coap_opt_iterator_t opt_iter;
557  coap_opt_t *q;
558  coap_string_t *query = NULL;
559  size_t length = 0;
560  static const uint8_t hex[] = "0123456789ABCDEF";
561 
564  coap_option_iterator_init(request, &opt_iter, &f);
565  while ((q = coap_option_next(&opt_iter))) {
566  uint16_t seg_len = coap_opt_length(q), i;
567  const uint8_t *seg= coap_opt_value(q);
568  for (i = 0; i < seg_len; i++) {
569  if (is_unescaped_in_query(seg[i]))
570  length += 1;
571  else
572  length += 3;
573  }
574  length += 1;
575  }
576  if (length > 0)
577  length -= 1;
578  if (length > 0) {
579  query = coap_new_string(length);
580  if (query) {
581  query->length = length;
582  unsigned char *s = query->s;
583  coap_option_iterator_init(request, &opt_iter, &f);
584  while ((q = coap_option_next(&opt_iter))) {
585  if (s != query->s)
586  *s++ = '&';
587  uint16_t seg_len = coap_opt_length(q), i;
588  const uint8_t *seg= coap_opt_value(q);
589  for (i = 0; i < seg_len; i++) {
590  if (is_unescaped_in_query(seg[i])) {
591  *s++ = seg[i];
592  } else {
593  *s++ = '%';
594  *s++ = hex[seg[i]>>4];
595  *s++ = hex[seg[i]&0x0F];
596  }
597  }
598  }
599  }
600  }
601  return query;
602 }
603 
605  coap_opt_iterator_t opt_iter;
607  coap_opt_t *q;
608  coap_string_t *uri_path = NULL;
609  size_t length = 0;
610  static const uint8_t hex[] = "0123456789ABCDEF";
611 
614  coap_option_iterator_init(request, &opt_iter, &f);
615  while ((q = coap_option_next(&opt_iter))) {
616  uint16_t seg_len = coap_opt_length(q), i;
617  const uint8_t *seg= coap_opt_value(q);
618  for (i = 0; i < seg_len; i++) {
619  if (is_unescaped_in_path(seg[i]))
620  length += 1;
621  else
622  length += 3;
623  }
624  /* bump for the leading "/" */
625  length += 1;
626  }
627  /* The first entry does not have a leading "/" */
628  if (length > 0)
629  length -= 1;
630 
631  /* if 0, either no URI_PATH Option, or the first one was empty */
632  uri_path = coap_new_string(length);
633  if (uri_path) {
634  uri_path->length = length;
635  unsigned char *s = uri_path->s;
636  int n = 0;
637  coap_option_iterator_init(request, &opt_iter, &f);
638  while ((q = coap_option_next(&opt_iter))) {
639  if (n++) {
640  *s++ = '/';
641  }
642  uint16_t seg_len = coap_opt_length(q), i;
643  const uint8_t *seg= coap_opt_value(q);
644  for (i = 0; i < seg_len; i++) {
645  if (is_unescaped_in_path(seg[i])) {
646  *s++ = seg[i];
647  } else {
648  *s++ = '%';
649  *s++ = hex[seg[i]>>4];
650  *s++ = hex[seg[i]&0x0F];
651  }
652  }
653  }
654  }
655  return uri_path;
656 }
657 
Pulls together all the internal only header files.
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:57
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
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:209
void coap_option_filter_clear(coap_opt_filter_t *filter)
Clears filter filter.
Definition: option.c:486
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:246
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's option list.
Definition: option.c:110
int coap_option_filter_set(coap_opt_filter_t *filter, coap_option_num_t option)
Sets the corresponding entry for number in filter.
Definition: option.c:491
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:289
#define COAP_DEFAULT_PORT
Definition: pdu.h:33
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:118
#define COAP_OPTION_URI_PATH
Definition: pdu.h:113
#define COAP_DEFAULT_SCHEME
Definition: pdu.h:44
#define COAPS_DEFAULT_PORT
Definition: pdu.h:34
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
#define COAP_SET_STR(st, l, v)
Definition: str.h:43
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition: uri.c:604
coap_string_t * coap_get_query(const coap_pdu_t *request)
Extract query string from request PDU according to escape rules in 6.5.8.
Definition: uri.c:554
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:442
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:454
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:234
int coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition: uri.c:239
#define COAP_STATIC_INLINE
Definition: libcoap.h:38
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:96
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:103
const uint32_t n
Definition: murmur3.c:56
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:26
Definition: uri.c:421
int n
Definition: uri.c:423
coap_string_t buf
Definition: uri.c:422
Iterator to run through PDU options.
Definition: option.h:170
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
const uint8_t * s
read-only string data
Definition: str.h:40
size_t length
length of string
Definition: str.h:39
CoAP string data definition.
Definition: str.h:30
uint8_t * s
string data
Definition: str.h:32
size_t length
length of string
Definition: str.h:31
Representation of parsed URI.
Definition: uri.h:38
enum coap_uri_scheme_t scheme
The parsed scheme specifier.
Definition: uri.h:46
coap_str_const_t path
Beginning of the first path segment.
Definition: uri.h:41
uint16_t port
The port in host byte order.
Definition: uri.h:40
coap_str_const_t query
The query part if present.
Definition: uri.h:43
coap_str_const_t host
host part of the URI
Definition: uri.h:39
COAP_STATIC_INLINE int is_unescaped_in_path(const uint8_t c)
Definition: uri.c:541
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:265
COAP_STATIC_INLINE int is_unescaped_in_query(const uint8_t c)
Definition: uri.c:550
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:377
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
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:393
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:287
#define ISEQUAL_CI(a, b)
Definition: uri.c:39
static void write_option(const uint8_t *s, size_t len, void *data)
Definition: uri.c:427
static int coap_split_uri_sub(const uint8_t *str_var, size_t len, coap_uri_t *uri, coap_uri_check_t check_proxy)
Definition: uri.c:48
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:480
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition: uri.c:250
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:328
coap_uri_t * coap_clone_uri(const coap_uri_t *uri)
Clones the specified coap_uri_t object.
Definition: uri.c:499
coap_uri_check_t
Definition: uri.c:42
@ COAP_URI_CHECK_URI
Definition: uri.c:43
@ COAP_URI_CHECK_PROXY
Definition: uri.c:44
#define URI_DATA(uriobj)
Definition: uri.c:477
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition: uri.c:371
@ COAP_URI_SCHEME_COAPS_TCP
Definition: uri.h:25
@ COAP_URI_SCHEME_COAPS
Definition: uri.h:23
@ COAP_URI_SCHEME_COAP_TCP
Definition: uri.h:24
@ COAP_URI_SCHEME_HTTPS
Definition: uri.h:27
@ COAP_URI_SCHEME_COAP
Definition: uri.h:22
@ COAP_URI_SCHEME_HTTP
Definition: uri.h:26