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