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