libcoap 4.3.5-develop-783b531
Loading...
Searching...
No Matches
coap_uri.c
Go to the documentation of this file.
1/* coap_uri.c -- helper functions for URI treatment
2 *
3 * Copyright (C) 2010--2012,2015-2016,2022-2026 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
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
27#ifdef _WIN32
28#define strcasecmp _stricmp
29#define strncasecmp _strnicmp
30#endif
31
34
46COAP_STATIC_INLINE const uint8_t *
47strnchr(const uint8_t *s, size_t len, unsigned char c) {
48 while (len && *s++ != c)
49 --len;
50
51 return len ? s : NULL;
52}
53
58
64 { "http", 80, 1, COAP_URI_SCHEME_HTTP },
65 { "https", 443, 1, COAP_URI_SCHEME_HTTPS },
66 { "coap+ws", 80, 0, COAP_URI_SCHEME_COAP_WS },
67 { "coaps+ws", 443, 0, COAP_URI_SCHEME_COAPS_WS }
68};
69
70/*
71 * Returns 0 All OK
72 * -1 Insufficient / Invalid parameters
73 * -2 No '://'
74 * -3 Ipv6 definition error or no host defined after scheme://
75 * -4 Invalid port value
76 * -5 Port defined for Unix domain or LLC host
77 * -6 Hostname > 255 chars
78 * -7 Invalid LLC address
79 */
80static int
81coap_split_uri_sub(const uint8_t *str_var,
82 size_t len,
83 coap_uri_t *uri,
84 coap_uri_check_t check_proxy) {
85 const uint8_t *p, *q;
86 int res = 0;
87 size_t i;
88 int is_unix_domain = 0;
89 int is_llc = 0;
90
91 if (!str_var || !uri || len == 0)
92 return -1;
93
94 memset(uri, 0, sizeof(coap_uri_t));
96
97 /* search for scheme */
98 p = str_var;
99 if (*p == '/') {
100 /* no scheme, host or port */
101 if (check_proxy == COAP_URI_CHECK_PROXY) {
102 /* Must have ongoing host if proxy definition */
103 return -1;
104 }
105 q = p;
106 goto path;
107 }
108
109 /* find scheme terminating :// */
110 while (len >= 3 && !(p[0] == ':' && p[1] == '/' && p[2] == '/')) {
111 ++p;
112 --len;
113 }
114 if (len < 3) {
115 /* scheme not defined with a :// terminator */
116 res = -2;
117 goto error;
118 }
119 for (i = 0; i < COAP_URI_SCHEME_LAST; i++) {
120 if ((p - str_var) == (int)strlen(coap_uri_scheme[i].name) &&
121 memcmp(str_var, coap_uri_scheme[i].name, p - str_var) == 0) {
122 if (check_proxy != COAP_URI_CHECK_PROXY && coap_uri_scheme[i].proxy_only) {
123 coap_log_err("%.*s URI scheme not enabled (not a proxy)\n",
124 (int)(p - str_var), str_var);
125 return -1;
126 }
127 uri->scheme = coap_uri_scheme[i].scheme;
128 uri->port = coap_uri_scheme[i].port;
129 break;
130 }
131 }
132 if (i == COAP_URI_SCHEME_LAST) {
133 /* scheme unknown */
134 coap_log_err("%.*s URI scheme unknown\n", (int)(p - str_var), str_var);
135 res = -1;
136 goto error;
137 }
138 switch (uri->scheme) {
140 break;
142 if (!coap_dtls_is_supported()) {
143 coap_log_err("coaps URI scheme not supported in this version of libcoap\n");
144 return -1;
145 }
146 break;
148 if (!coap_tcp_is_supported()) {
149 coap_log_err("coap+tcp URI scheme not supported in this version of libcoap\n");
150 return -1;
151 }
152 break;
154 if (!coap_tls_is_supported()) {
155 coap_log_err("coaps+tcp URI scheme not supported in this version of libcoap\n");
156 return -1;
157 }
158 break;
160 if (!coap_ws_is_supported()) {
161 coap_log_err("coap+ws URI scheme not supported in this version of libcoap\n");
162 return -1;
163 }
164 break;
166 if (!coap_wss_is_supported()) {
167 coap_log_err("coaps+ws URI scheme not supported in this version of libcoap\n");
168 return -1;
169 }
170 break;
173 /* Not proxy, caught above. For proxy, assume app is doing CoAP <> HTTP mapping. */
174 break;
176 default:
177 coap_log_warn("Unsupported URI type %d\n", uri->scheme);
178 return -1;
179 }
180 /* skip :// */
181 p += 3;
182 len -= 3;
183
184 /* p points to beginning of Uri-Host */
185 q = p;
186
187 if (len && *p == '[') {
188 /* IPv6 address reference or Unix domain */
189 ++p;
190 ++q;
191 --len;
192
193 while (len && *q != ']') {
194 ++q;
195 --len;
196 }
197
198 if (!len || *q != ']' || p == q) {
199 res = -3;
200 goto error;
201 }
202
203 COAP_SET_STR(&uri->host, q - p, p);
204 ++q;
205 --len;
206#if COAP_AF_LLC_SUPPORT
207 } else if ((len >= LLC_HOST_LEN) && strncmp((const char *)p, "llc[", 4) == 0) {
208 unsigned long sap = 0;
209
210 is_llc = 1;
211
212 while (len && *q != ']') {
213 ++q;
214 --len;
215 }
216
217 if (!len || *q != ']' || p == q) {
218 res = -7;
219 goto error;
220 }
221
222 ++q;
223 --len;
224
225 if (!len || *q != ':') {
226 coap_log_warn("LLC SAP missing in URI\n");
227 res = -7;
228 goto error;
229 }
230
231 ++q;
232 --len;
233
234 while (len && isxdigit(*q)) {
235 if (*q >= 'a' && *q <= 'f')
236 sap = sap * 16 + (*q - 'a' + 10);
237 else if (*q >= 'A' && *q <= 'F')
238 sap = sap * 16 + (*q - 'A' + 10);
239
240 ++q;
241 --len;
242 }
243
244 if (sap > UINT8_MAX) {
245 coap_log_warn("LLC SAP invalid (%lu > 255)\n", sap);
246 res = -7;
247 goto error;
248 }
249
250 COAP_SET_STR(&uri->host, q - p, p);
251#endif /* COAP_AF_LLC_SUPPORT */
252 } else {
253 /* IPv4 address, FQDN or Unix domain socket */
254 if (len >= 3 && p[0] == '%' && p[1] == '2' &&
255 (p[2] == 'F' || p[2] == 'f')) {
256 /* Unix domain definition */
257 uri->port = 0;
258 is_unix_domain = 1;
259 }
260 while (len && *q != ':' && *q != '/' && *q != '?') {
261 ++q;
262 --len;
263 }
264
265 if (p == q) {
266 res = -3;
267 goto error;
268 }
269
270 if ((int)(q - p) > 255) {
271 coap_log_warn("Host name length too long (%d > 255)\n", (int)(q - p));
272 res = -6;
273 goto error;
274 }
275
276 COAP_SET_STR(&uri->host, q - p, p);
277 }
278
279 /* check for Uri-Port (invalid for Unix) */
280 if (len && *q == ':') {
281 if (is_unix_domain || is_llc) {
282 res = -5;
283 goto error;
284 }
285 p = ++q;
286 --len;
287
288 while (len && isdigit(*q)) {
289 ++q;
290 --len;
291 }
292
293 if (p < q) { /* explicit port number given */
294 long uri_port = 0;
295
296 while ((p < q) && (uri_port <= UINT16_MAX))
297 uri_port = uri_port * 10 + (*p++ - '0');
298
299 /* check if port number is in allowed range */
300 if (uri_port > UINT16_MAX) {
301 coap_log_warn("Port number too big (%ld > 65535)\n", uri_port);
302 res = -4;
303 goto error;
304 }
305
306 uri->port = (uint16_t)uri_port;
307 }
308 }
309
310path: /* at this point, p must point to an absolute path */
311
312 if (!len)
313 goto end;
314
315 if (*q == '/') {
316 p = ++q;
317 --len;
318
319 while (len && *q != '?') {
320 ++q;
321 --len;
322 }
323
324 if (p < q) {
325 COAP_SET_STR(&uri->path, q - p, p);
326 p = q;
327 }
328 }
329
330 /* Uri_Query */
331 if (len && *p == '?') {
332 ++p;
333 --len;
334 COAP_SET_STR(&uri->query, len, p);
335 len = 0;
336 }
337
338end:
339 return len ? -1 : 0;
340
341error:
342 return res;
343}
344
345int
346coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
347 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_URI);
348}
349
350int
351coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
352 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_PROXY);
353}
354
355static void
357 size_t i;
358
359 for (i = 0; i < optlist->length; i++) {
360 if (optlist->data[i] >= 'A' && optlist->data[i] <= 'Z') {
361 optlist->data[i] += 'a' - 'A';
362 }
363 }
364}
365
366int
368 coap_optlist_t **optlist_chain, int create_port_host_opt,
369 uint8_t *_buf COAP_UNUSED, size_t buflen COAP_UNUSED) {
370 return !coap_uri_into_optlist(uri, dst, optlist_chain, create_port_host_opt) ? -1 : 0;
371}
372
373int
375 coap_optlist_t **optlist_chain, int create_port_host_opt) {
376 return coap_uri_into_optlist_abbrev(uri, dst, optlist_chain, create_port_host_opt, NULL, 0);
377}
378
379int
381 coap_optlist_t **optlist_chain, int create_port_host_opt,
382 coap_upa_abbrev_t *mapping, uint32_t count) {
383 if (create_port_host_opt && !coap_host_is_unix_domain(&uri->host)) {
384 int add_option = 0;
385
386 if (dst && uri->host.length) {
387#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
388 char addr[INET6_ADDRSTRLEN];
389#else /* WITH_LWIP || WITH_CONTIKI */
390 char addr[40];
391#endif /* WITH_LWIP || WITH_CONTIKI */
392 coap_optlist_t *optlist;
393
394 /* Add in Uri-Host if not match (need to strip off %iface) */
395 size_t uri_host_len = uri->host.length;
396 const uint8_t *cp = uri->host.s;
397
398 /* Unfortunately not null terminated */
399 for (size_t i = 0; i < uri_host_len; i++) {
400 if (cp[i] == '%') {
401 /* %iface specified in host name */
402 uri_host_len = i;
403 break;
404 }
405 }
406
407 if (coap_print_ip_addr(dst, addr, sizeof(addr)) &&
408 (strlen(addr) != uri_host_len ||
409 strncasecmp(addr, (const char *)uri->host.s, uri_host_len) != 0)) {
410 /* add Uri-Host */
411 optlist = coap_new_optlist(COAP_OPTION_URI_HOST, uri_host_len,
412 uri->host.s);
413 if (!coap_host_is_unix_domain(&uri->host)) {
414 coap_replace_percents(optlist);
416 }
417 if (!coap_insert_optlist(optlist_chain, optlist)) {
418 return 0;
419 }
420 }
421 }
422 /* Add in UriPort if not default */
423 switch ((int)uri->scheme) {
426 if (uri->port != 80)
427 add_option = 1;
428 break;
431 if (uri->port != 443)
432 add_option = 1;
433 break;
434 default:
437 add_option = 1;
438 break;
439 }
440 if (add_option) {
441 uint8_t tbuf[4];
442
443 coap_insert_optlist(optlist_chain,
445 coap_encode_var_safe(tbuf, 4,
446 (uri->port & 0xffff)),
447 tbuf));
448 }
449 }
450
451 if (uri->path.length) {
453 optlist_chain, mapping, count))
454 return 0;
455 }
456
457 if (uri->query.length) {
459 optlist_chain))
460 return 0;
461 }
462 return 1;
463}
464
465int
467 if (host->length >= 3 && host->s[0] == '%' &&
468 host->s[1] == '2' &&
469 (host->s[2] == 'F' || host->s[2] == 'f')) {
470 return 1;
471 }
472 if (host->length >= 1 && host->s[0] == '/')
473 return 1;
474 return 0;
475}
476
477int
479#if COAP_AF_LLC_SUPPORT
480 size_t length;
481 const uint8_t *s = NULL;
482 int i = 0;
483
484 length = host->length;
485 if (length != LLC_HOST_LEN)
486 return 0;
487
488 s = host->s;
489
490 if (strncmp((const char *)s, "llc[", 4) != 0)
491 return 0;
492
493 length -= 4;
494 s += 4;
495
496 while (length) {
497 if (!isxdigit(s[0]) || !isxdigit(s[1]))
498 return 0;
499
500 length -= 2;
501 s += 2;
502
503 i++;
504
505 if (length <= 0 || i >= 6)
506 break;
507
508 if (s[0] != ':')
509 return 0;
510
511 length--;
512 s++;
513 }
514
515 if (s[0] != ']' || s[1] != ':' || !isxdigit(s[2]) || !isxdigit(s[3]))
516 return 0;
517
518 return 1;
519#else /* COAP_AF_LLC_SUPPORT */
520 (void)host;
521 return 0;
522#endif /* COAP_AF_LLC_SUPPORT */
523}
524
532#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
533
546static void
547decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
548
549 while (length) {
550 length--;
551
552 if (*seg == '%') {
553 if (length < 2)
554 return;
555 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
556
557 seg += 2;
558 length -= 2;
559 } else {
560 *buf = *seg;
561 }
562
563 ++buf;
564 ++seg;
565 }
566}
567
573static int
574check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
575 size_t n = 0;
576
577 while (length) {
578 if (*s == '%') {
579 if (length < 3 || !(isxdigit(s[1]) && isxdigit(s[2])))
580 return -1;
581
582 s += 2;
583 length -= 2;
584 }
585
586 ++s;
587 ++n;
588 --length;
589 }
590
591 *segment_size = n;
592
593 return 0;
594}
595
616static int
617make_decoded_option(const uint8_t *s, size_t length,
618 unsigned char *buf, size_t buflen, size_t *optionsize) {
619 int res;
620 size_t segmentlen;
621 size_t written;
622
623 if (!buflen) {
624 coap_log_debug("make_decoded_option(): buflen is 0!\n");
625 return -1;
626 }
627
628 res = check_segment(s, length, &segmentlen);
629 if (res < 0)
630 return -1;
631
632 /* write option header using delta 0 and length res */
633 written = coap_opt_setheader(buf, buflen, 0, segmentlen);
634
635 assert(written <= buflen);
636
637 if (!written) /* encoding error */
638 return -1;
639
640 buf += written; /* advance past option type/length */
641 buflen -= written;
642
643 if (buflen < segmentlen) {
644 coap_log_debug("buffer too small for option\n");
645 return -1;
646 }
647
648 decode_segment(s, length, buf);
649
650 *optionsize = written + segmentlen;
651
652 return 0;
653}
654
655
656#ifndef min
657#define min(a,b) ((a) < (b) ? (a) : (b))
658#endif
659
660typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
661
667static int
668dots(const uint8_t *s, size_t len) {
669 uint8_t p;
670
671 if (!len)
672 return 0;
673
674 p = *s;
675
676 /* Check 'first' char */
677 if (p == '%' && len >=3) {
678 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
679 s += 2;
680 len -= 2;
681 }
682 p = '.';
683 }
684 if (p != '.')
685 return 0;
686 if (len == 1)
687 return 1;
688
689 /* Check 'second' char, first is '.' */
690 s++;
691 len--;
692 assert(len);
693 p = *s;
694 if (p == '%' && len >=3) {
695 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
696 len -= 2;
697 }
698 p = '.';
699 }
700 if (p != '.')
701 return 0;
702 if (len == 1)
703 return 2;
704
705 return 0;
706}
707
713
714static void
715backup_segment(void *data) {
716 struct cnt_str *state = (struct cnt_str *)data;
717 int i;
718 uint8_t *buf;
719
720 if (state->n == 0)
721 return;
722
723 state->n--;
724 buf = state->base_buf.s;
725 for (i = 0; i < state->n; i++) {
727 }
728 state->buf.s = buf;
729 state->buf.length = state->base_buf.length - (buf - state->base_buf.s);
730}
731
743static size_t
744coap_split_path_impl(const uint8_t *path, size_t len,
745 segment_handler_t h, void *data) {
746 const uint8_t *p, *q;
747 size_t length = len;
748 int num_dots;
749
750 p = q = path;
751 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
752 if (*q == '/') {
753 /* start new segment */
754 num_dots = dots(p, q - p);
755 switch (num_dots) {
756 case 1:
757 /* drop segment */
758 break;
759 case 2:
760 /* backup segment */
761 backup_segment(data);
762 break;
763 case 0:
764 default:
765 /* add segment */
766 h(p, q - p, data);
767 break;
768 }
769
770 p = q + 1;
771 }
772
773 q++;
774 length--;
775 }
776
777 /* write last segment */
778 num_dots = dots(p, q - p);
779 switch (num_dots) {
780 case 1:
781 /* drop segment */
782 break;
783 case 2:
784 /* backup segment */
785 backup_segment(data);
786 break;
787 case 0:
788 default:
789 /* add segment */
790 h(p, q - p, data);
791 break;
792 }
793
794 return q - path;
795}
796
797static void
798write_option(const uint8_t *s, size_t len, void *data) {
799 struct cnt_str *state = (struct cnt_str *)data;
800 int res;
801 size_t optionsize;
802 assert(state);
803
804 res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
805 if (res == 0) {
806 state->buf.s += optionsize;
807 state->buf.length -= optionsize;
808 state->n++;
809 }
810}
811
812int
813coap_split_path(const uint8_t *s, size_t length,
814 unsigned char *buf, size_t *buflen) {
815 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
816
817 coap_split_path_impl(s, length, write_option, &tmp);
818
819 *buflen = *buflen - tmp.buf.length;
820
821 return tmp.n;
822}
823
824void
826 size_t i;
827 size_t o = 0;
828
829 for (i = 0; i < optlist->length; i++) {
830 if (optlist->data[i] == '%' && optlist->length - i >= 3) {
831 optlist->data[o] = (hexchar_to_dec(optlist->data[i+1]) << 4) +
832 hexchar_to_dec(optlist->data[i+2]);
833 i+= 2;
834 } else if (o != i) {
835 optlist->data[o] = optlist->data[i];
836 }
837 o++;
838 }
839 optlist->length = o;
840}
841
842static void
844 coap_optlist_t *last = NULL;
845 coap_optlist_t *cur = *optlist_begin;
846
847 if (!cur)
848 return;
849
850 while (cur) {
851 if (!cur->next)
852 break;
853 last = cur;
854 cur = cur->next;
855 }
857 if (last) {
858 last->next = NULL;
859 } else {
860 *optlist_begin = NULL;
861 }
862}
863
864int
865coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
866 coap_optlist_t **optlist_chain) {
867 return coap_path_into_optlist_abbrev(s, length, optnum, optlist_chain, NULL, 0);
868}
869
870int
871coap_path_into_optlist_abbrev(const uint8_t *s, size_t length, coap_option_num_t optnum,
872 coap_optlist_t **optlist_chain, coap_upa_abbrev_t *mapping,
873 uint32_t count) {
874 const uint8_t *p = s;
875 coap_optlist_t *optlist;
876 int num_dots;
877 coap_optlist_t **optlist_start;
878
879 if (*optlist_chain) {
880 /* Something previously in optlist_chain. Need to make that the start */
881 optlist_start = &((*optlist_chain)->next);
882 } else {
883 optlist_start = optlist_chain;
884 }
885
886 if (length > 0 && mapping) {
887 uint32_t i;
888 uint8_t buf[4];
889
890 for (i = 0; i < count; i++) {
891 if (strlen(mapping[i].upa_path) == length &&
892 memcmp(mapping[i].upa_path, s, length) == 0) {
893 /* add in as Uri_path-Abbrev */
895 coap_encode_var_safe(buf, sizeof(buf), mapping[i].upa_value), buf);
896 if (!coap_insert_optlist(optlist_chain, optlist)) {
897 return 0;
898 }
899 return 1;
900 }
901 }
902 }
903 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *s)) {
904 if (*s == '/') { /* start of new path element */
905 /* start new segment */
906 num_dots = dots(p, s - p);
907 switch (num_dots) {
908 case 1:
909 /* drop segment */
910 break;
911 case 2:
912 /* backup segment */
913 backup_optlist(optlist_start);
914 break;
915 case 0:
916 default:
917 /* add segment */
918 optlist = coap_new_optlist(optnum, s - p, p);
919 if (!optlist) {
920 return 0;
921 }
922 coap_replace_percents(optlist);
923 if (!coap_insert_optlist(optlist_chain, optlist)) {
924 return 0;
925 }
926 break;
927 }
928 p = s + 1;
929 }
930 s++;
931 length--;
932
933 }
934 /* add last path element */
935 num_dots = dots(p, s - p);
936 switch (num_dots) {
937 case 1:
938 /* drop segment */
939 break;
940 case 2:
941 /* backup segment */
942 backup_optlist(optlist_start);
943 break;
944 case 0:
945 default:
946 /* add segment */
947 optlist = coap_new_optlist(optnum, s - p, p);
948 if (!optlist) {
949 return 0;
950 }
951 coap_replace_percents(optlist);
952 if (!coap_insert_optlist(optlist_chain, optlist)) {
953 return 0;
954 }
955 break;
956 }
957 return 1;
958}
959
960int
961coap_split_query(const uint8_t *s, size_t length,
962 unsigned char *buf, size_t *buflen) {
963 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
964 const uint8_t *p;
965
966 p = s;
967 while (length > 0 && *s != '#') {
968 if (*s == '&') { /* start new query element */
969 write_option(p, s - p, &tmp);
970 p = s + 1;
971 }
972
973 s++;
974 length--;
975 }
976
977 /* write last query element */
978 write_option(p, s - p, &tmp);
979
980 *buflen = *buflen - tmp.buf.length;
981 return tmp.n;
982}
983
984int
985coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
986 coap_optlist_t **optlist_chain) {
987 const uint8_t *p = s;
988 coap_optlist_t *optlist;
989
990 while (length > 0 && *s != '#') {
991 if (*s == '&') { /* start of new query element */
992 /* add previous query element */
993 optlist = coap_new_optlist(optnum, s - p, p);
994 if (!optlist) {
995 return 0;
996 }
997 coap_replace_percents(optlist);
998 if (!coap_insert_optlist(optlist_chain, optlist)) {
999 return 0;
1000 }
1001 p = s + 1;
1002 }
1003 s++;
1004 length--;
1005 }
1006 /* add last query element */
1007 optlist = coap_new_optlist(optnum, s - p, p);
1008 if (!optlist) {
1009 return 0;
1010 }
1011 coap_replace_percents(optlist);
1012 if (!coap_insert_optlist(optlist_chain, optlist)) {
1013 return 0;
1014 }
1015 return 1;
1016}
1017
1018#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
1019
1020coap_uri_t *
1021coap_new_uri(const uint8_t *uri, unsigned int length) {
1022 uint8_t *result;
1023 coap_uri_t *out_uri;
1024
1025 out_uri = (coap_uri_t *)coap_malloc_type(COAP_STRING, length + 1 + sizeof(coap_uri_t));
1026
1027 if (!out_uri)
1028 return NULL;
1029
1030 result = (uint8_t *)out_uri;
1031 memcpy(URI_DATA(result), uri, length);
1032 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
1033
1034 if (coap_split_uri(URI_DATA(result), length, out_uri) < 0) {
1035 coap_free_type(COAP_STRING, out_uri);
1036 return NULL;
1037 }
1038 return out_uri;
1039}
1040
1041coap_uri_t *
1043 coap_uri_t *result;
1044 uint8_t *p;
1045
1046 if (!uri)
1047 return NULL;
1048
1049 result = (coap_uri_t *)coap_malloc_type(COAP_STRING, uri->query.length + uri->host.length +
1050 uri->path.length + sizeof(coap_uri_t) + 1);
1051
1052 if (!result)
1053 return NULL;
1054
1055 memset(result, 0, sizeof(coap_uri_t));
1056
1057 result->port = uri->port;
1058
1059 if (uri->host.length) {
1060 result->host.s = p = URI_DATA(result);
1061 result->host.length = uri->host.length;
1062
1063 memcpy(p, uri->host.s, uri->host.length);
1064 }
1065
1066 if (uri->path.length) {
1067 result->path.s = p = URI_DATA(result) + uri->host.length;
1068 result->path.length = uri->path.length;
1069
1070 memcpy(p, uri->path.s, uri->path.length);
1071 }
1072
1073 if (uri->query.length) {
1074 result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
1075 result->query.length = uri->query.length;
1076
1077 memcpy(p, uri->query.s, uri->query.length);
1078 }
1079
1080 return result;
1081}
1082
1083void
1087
1088static int
1089is_unescaped_in_path(const uint8_t c) {
1090 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
1091 (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' ||
1092 c == '~' || c == '!' || c == '$' || c == '\'' || c == '(' ||
1093 c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
1094 c=='=' || c==':' || c=='@' || c == '&';
1095}
1096
1097static int
1098is_unescaped_in_query(const uint8_t c) {
1099 return is_unescaped_in_path(c) || c=='/' || c=='?';
1100}
1101
1104 coap_opt_iterator_t opt_iter;
1106 coap_opt_t *q;
1107 coap_string_t *query = NULL;
1108 size_t length = 0;
1109 static const uint8_t hex[] = "0123456789ABCDEF";
1110
1113 coap_option_iterator_init(request, &opt_iter, &f);
1114 while ((q = coap_option_next(&opt_iter))) {
1115 uint16_t seg_len = coap_opt_length(q), i;
1116 const uint8_t *seg= coap_opt_value(q);
1117 for (i = 0; i < seg_len; i++) {
1118 if (is_unescaped_in_query(seg[i]))
1119 length += 1;
1120 else
1121 length += 3;
1122 }
1123 length += 1;
1124 }
1125 if (length > 0)
1126 length -= 1;
1127 if (length > 0) {
1128 query = coap_new_string(length);
1129 if (query) {
1130 query->length = length;
1131 unsigned char *s = query->s;
1132 coap_option_iterator_init(request, &opt_iter, &f);
1133 while ((q = coap_option_next(&opt_iter))) {
1134 if (s != query->s)
1135 *s++ = '&';
1136 uint16_t seg_len = coap_opt_length(q), i;
1137 const uint8_t *seg= coap_opt_value(q);
1138 for (i = 0; i < seg_len; i++) {
1139 if (is_unescaped_in_query(seg[i])) {
1140 *s++ = seg[i];
1141 } else {
1142 *s++ = '%';
1143 *s++ = hex[seg[i]>>4];
1144 *s++ = hex[seg[i]&0x0F];
1145 }
1146 }
1147 }
1148 }
1149 }
1150 return query;
1151}
1152
1153const char *
1155 while (chain) {
1156 coap_upa_chain_t *next = chain->next;
1157
1158 if (chain->upa_value == value) {
1159 return chain->upa_path;
1160 }
1161 chain = next;
1162 }
1163 return NULL;
1164}
1165
1166int
1167coap_map_uri_path_abbrev(coap_upa_chain_t *chain, const char *path, size_t length,
1168 uint32_t *value) {
1169 while (chain) {
1170 coap_upa_chain_t *next = chain->next;
1171
1172 if (strlen(chain->upa_path) == length && memcmp(chain->upa_path, path, length) == 0) {
1173 *value = chain->upa_value;
1174 return 1;
1175 }
1176 chain = next;
1177 }
1178 return 0;
1179}
1180
1183 coap_opt_iterator_t opt_iter;
1185 coap_opt_t *q;
1186 coap_string_t *uri_path = NULL;
1187 size_t length = 0;
1188 static const uint8_t hex[] = "0123456789ABCDEF";
1189
1190 q = coap_check_option(request, COAP_OPTION_URI_PATH_ABB, &opt_iter);
1191 if (q) {
1192 uint32_t value;
1193 const char *exp;
1194 if (coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter) ||
1195 coap_check_option(request, COAP_OPTION_URI_PATH, &opt_iter)) {
1196 return NULL;
1197 }
1200 if (exp) {
1201 uri_path = coap_new_string(strlen(exp));
1202 if (uri_path) {
1203 memcpy(uri_path->s, exp, strlen(exp));
1204 }
1205 return uri_path;
1206 }
1207 return NULL;
1208 }
1209 q = coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter);
1210 if (q) {
1211 coap_uri_t uri;
1212
1214 coap_opt_length(q), &uri) < 0) {
1215 return NULL;
1216 }
1217 uri_path = coap_new_string(uri.path.length);
1218 if (uri_path && uri.path.length) {
1219 memcpy(uri_path->s, uri.path.s, uri.path.length);
1220 }
1221 return uri_path;
1222 }
1223
1226 coap_option_iterator_init(request, &opt_iter, &f);
1227 while ((q = coap_option_next(&opt_iter))) {
1228 uint16_t seg_len = coap_opt_length(q), i;
1229 const uint8_t *seg = coap_opt_value(q);
1230 for (i = 0; i < seg_len; i++) {
1231 if (is_unescaped_in_path(seg[i]))
1232 length += 1;
1233 else
1234 length += 3;
1235 }
1236 /* bump for the leading "/" */
1237 length += 1;
1238 }
1239 /* The first entry does not have a leading "/" */
1240 if (length > 0)
1241 length -= 1;
1242
1243 /* if 0, either no URI_PATH Option, or the first one was empty */
1244 uri_path = coap_new_string(length);
1245 if (uri_path) {
1246 uri_path->length = length;
1247 unsigned char *s = uri_path->s;
1248 int n = 0;
1249 coap_option_iterator_init(request, &opt_iter, &f);
1250 while ((q = coap_option_next(&opt_iter))) {
1251 if (n++) {
1252 *s++ = '/';
1253 }
1254 uint16_t seg_len = coap_opt_length(q), i;
1255 const uint8_t *seg= coap_opt_value(q);
1256 for (i = 0; i < seg_len; i++) {
1257 if (is_unescaped_in_path(seg[i])) {
1258 *s++ = seg[i];
1259 } else {
1260 *s++ = '%';
1261 *s++ = hex[seg[i]>>4];
1262 *s++ = hex[seg[i]&0x0F];
1263 }
1264 }
1265 }
1266 }
1267 return uri_path;
1268}
1269
1270void
1272 while (chain) {
1273 coap_upa_chain_t *next = chain->next;
1274
1276 chain = next;
1277 }
1278}
1279
1280static coap_upa_chain_t *
1282 uint32_t i;
1283 coap_upa_chain_t *chain = NULL;
1284 coap_upa_chain_t *next;
1285
1286 for (i = 0; i < count; i++) {
1287 next = coap_malloc_type(COAP_STRING, sizeof(coap_upa_chain_t) + strlen(list[i].upa_path) + 1);
1288 if (next == NULL)
1289 goto cleanup;
1290
1291 next->upa_value = list[i].upa_value;
1292 next->upa_path = (char *)next + sizeof(coap_upa_chain_t);
1293 strcpy(next->upa_path, list[i].upa_path);
1294 next->next = chain;
1295 chain = next;
1296 }
1297 return chain;
1298
1299cleanup:
1300 coap_delete_upa_chain(chain);
1301 return NULL;
1302}
1303
1304void
1311
1312void
#define INET6_ADDRSTRLEN
Definition coap_debug.c:234
Library specific build wrapper for coap_internal.h.
@ COAP_STRING
Definition coap_mem.h:33
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
size_t coap_opt_size(const coap_opt_t *opt)
Returns the size of the given option, taking into account a possible option jump.
#define NULL
Definition coap_option.h:30
uint16_t coap_option_num_t
Definition coap_option.h:37
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:43
static void coap_replace_upper_lower(coap_optlist_t *optlist)
Definition coap_uri.c:356
static int dots(const uint8_t *s, size_t len)
Checks if path segment s consists of one or two dots.
Definition coap_uri.c:668
int coap_uri_into_options(const coap_uri_t *uri, const coap_address_t *dst, coap_optlist_t **optlist_chain, int create_port_host_opt, uint8_t *_buf COAP_UNUSED, size_t buflen COAP_UNUSED)
Definition coap_uri.c:367
static void backup_optlist(coap_optlist_t **optlist_begin)
Definition coap_uri.c:843
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 coap_uri.c:547
static coap_upa_chain_t * coap_build_upa_chain(coap_upa_abbrev_t *list, uint32_t count)
Definition coap_uri.c:1281
static int is_unescaped_in_query(const uint8_t c)
Definition coap_uri.c:1098
COAP_STATIC_INLINE const uint8_t * strnchr(const uint8_t *s, size_t len, unsigned char c)
A length-safe version of strchr().
Definition coap_uri.c:47
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 coap_uri.c:574
static void write_option(const uint8_t *s, size_t len, void *data)
Definition coap_uri.c:798
static void backup_segment(void *data)
Definition coap_uri.c:715
void coap_delete_uri(coap_uri_t *uri)
Removes the specified coap_uri_t object.
Definition coap_uri.c:1084
static size_t coap_split_path_impl(const uint8_t *path, size_t len, segment_handler_t h, void *data)
Splits the given string into segments.
Definition coap_uri.c:744
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 coap_uri.c:81
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition coap_uri.c:532
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 coap_uri.c:617
int coap_host_is_llc(const coap_str_const_t *host)
Determines from the host whether this is an LLC socket request.
Definition coap_uri.c:478
static int is_unescaped_in_path(const uint8_t c)
Definition coap_uri.c:1089
coap_uri_check_t
Definition coap_uri.c:54
@ COAP_URI_CHECK_URI
Definition coap_uri.c:55
@ COAP_URI_CHECK_PROXY
Definition coap_uri.c:56
coap_uri_t * coap_clone_uri(const coap_uri_t *uri)
Clones the specified coap_uri_t object.
Definition coap_uri.c:1042
#define URI_DATA(uriobj)
Definition coap_uri.c:1018
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 coap_uri.c:1021
int coap_host_is_unix_domain(const coap_str_const_t *host)
Determines from the host whether this is a Unix Domain socket request.
Definition coap_uri.c:466
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition coap_uri.c:660
static int coap_uri_scheme_is_secure(const coap_uri_t *uri)
Definition coap_uri.h:92
@ COAP_URI_SCHEME_COAPS_WS
Definition coap_uri.h:38
@ COAP_URI_SCHEME_COAPS_TCP
Definition coap_uri.h:34
@ COAP_URI_SCHEME_COAPS
Definition coap_uri.h:32
@ COAP_URI_SCHEME_COAP_TCP
Definition coap_uri.h:33
@ COAP_URI_SCHEME_COAP_WS
Definition coap_uri.h:37
@ COAP_URI_SCHEME_HTTPS
Definition coap_uri.h:36
@ COAP_URI_SCHEME_COAP
Definition coap_uri.h:31
@ COAP_URI_SCHEME_LAST
Definition coap_uri.h:39
@ COAP_URI_SCHEME_HTTP
Definition coap_uri.h:35
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:47
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:38
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:126
const char * coap_print_ip_addr(const coap_address_t *addr, char *buf, size_t len)
Print the IP address into the defined buffer.
Definition coap_debug.c:424
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log_err(...)
Definition coap_debug.h:102
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
coap_optlist_t * coap_new_optlist(uint16_t number, size_t length, const uint8_t *data)
Create a new optlist entry.
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
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.
void coap_delete_optlist(coap_optlist_t *queue)
Removes all entries from the optlist_chain, freeing off their memory usage.
void coap_option_filter_clear(coap_opt_filter_t *filter)
Clears filter filter.
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.
int coap_insert_optlist(coap_optlist_t **head, coap_optlist_t *node)
Adds optlist to the given optlist_chain.
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
int coap_option_filter_set(coap_opt_filter_t *filter, coap_option_num_t option)
Sets the corresponding entry for number in filter.
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.
#define COAP_OPTION_URI_HOST
Definition coap_pdu.h:122
#define COAP_DEFAULT_PORT
Definition coap_pdu.h:39
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:135
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:129
#define COAPS_DEFAULT_PORT
Definition coap_pdu.h:40
#define COAP_OPTION_URI_PATH_ABB
Definition coap_pdu.h:131
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:126
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:145
#define COAP_SET_STR(st, l, v)
Definition coap_str.h:52
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
Definition coap_str.c:21
int coap_tcp_is_supported(void)
Check whether TCP is available.
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition coap_notls.c:41
int coap_ws_is_supported(void)
Check whether WebSockets is available.
Definition coap_ws.c:934
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition coap_notls.c:36
int coap_wss_is_supported(void)
Check whether Secure WebSockets is available.
Definition coap_ws.c:939
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition coap_uri.c:1182
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 coap_uri.c:813
void coap_upa_client_fallback(coap_upa_abbrev_t *list, uint32_t count)
Define a Path to use if an Uri-Path-Abbrev option fails and the client is to retry the request using ...
Definition coap_uri.c:1305
void coap_upa_server_mapping(coap_upa_abbrev_t *list, uint32_t count)
Define a Path to use on receipt of an Uri-Path-Abbrev option value.
Definition coap_uri.c:1313
int coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain)
Splits the given URI query into '&' separate segments, and then adds the Uri-Query / Location-Query o...
Definition coap_uri.c:985
int coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition coap_uri.c:346
int coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain)
Splits the given URI path into '/' separate segments, and then adds the Uri-Path / Location-Path opti...
Definition coap_uri.c:865
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 coap_uri.c:351
int coap_uri_into_optlist_abbrev(const coap_uri_t *uri, const coap_address_t *dst, coap_optlist_t **optlist_chain, int create_port_host_opt, coap_upa_abbrev_t *mapping, uint32_t count)
Takes a coap_uri_t and then adds CoAP options into the optlist_chain.
Definition coap_uri.c:380
int coap_uri_into_optlist(const coap_uri_t *uri, const coap_address_t *dst, coap_optlist_t **optlist_chain, int create_port_host_opt)
Takes a coap_uri_t and then adds CoAP options into the optlist_chain.
Definition coap_uri.c:374
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 coap_uri.c:961
int coap_path_into_optlist_abbrev(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain, coap_upa_abbrev_t *mapping, uint32_t count)
Splits the given URI path into '/' separate segments, and then adds the Uri-Path / Location-Path opti...
Definition coap_uri.c:871
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 coap_uri.c:1103
int coap_map_uri_path_abbrev(coap_upa_chain_t *chain, const char *path, size_t length, uint32_t *value)
Definition coap_uri.c:1167
void coap_delete_upa_chain(coap_upa_chain_t *chain)
Clean up a UPA chain.
Definition coap_uri.c:1271
coap_uri_info_t coap_uri_scheme[COAP_URI_SCHEME_LAST]
Definition coap_uri.c:59
coap_upa_chain_t * coap_upa_server_mapping_chain
Definition coap_uri.c:33
const char * coap_map_abbrev_uri_path(coap_upa_chain_t *chain, uint32_t value)
Determine the expanded Uri-Path-Abbrev option value.
Definition coap_uri.c:1154
void coap_replace_percents(coap_optlist_t *optlist)
replace any % hex definitions with the actual character.
Definition coap_uri.c:825
coap_upa_chain_t * coap_upa_client_fallback_chain
Definition coap_uri.c:32
#define COAP_UNUSED
Definition libcoap.h:74
#define COAP_STATIC_INLINE
Definition libcoap.h:57
int n
Definition coap_uri.c:711
coap_string_t base_buf
Definition coap_uri.c:709
coap_string_t buf
Definition coap_uri.c:710
Multi-purpose address abstraction.
Iterator to run through PDU options.
Representation of chained list of CoAP options to install.
size_t length
the option value length
uint8_t * data
the option data
struct coap_optlist_t * next
next entry in the optlist chain
structure for CoAP PDUs
CoAP string data definition with const data.
Definition coap_str.h:47
const uint8_t * s
read-only string data
Definition coap_str.h:49
size_t length
length of string
Definition coap_str.h:48
CoAP string data definition.
Definition coap_str.h:39
uint8_t * s
string data
Definition coap_str.h:41
size_t length
length of string
Definition coap_str.h:40
uint32_t upa_value
The Uri-Path-Abbrev option value.
Definition coap_uri.h:86
const char * upa_path
The Uri-Path-Abbrev option path representation (withouot the leading '/')
Definition coap_uri.h:87
uint32_t upa_value
The Uri-Path-Abbrev option value.
struct coap_upa_chain_t * next
Next entry in the chain.
char * upa_path
The Uri-Path-Abbrev option path representation (withouot the leading '/')
coap_uri_scheme_t scheme
scheme
uint16_t port
default scheme port
Representation of parsed URI.
Definition coap_uri.h:70
enum coap_uri_scheme_t scheme
The parsed scheme specifier.
Definition coap_uri.h:82
coap_str_const_t path
The complete path if present or {0, NULL}.
Definition coap_uri.h:73
uint16_t port
The port in host byte order.
Definition coap_uri.h:72
coap_str_const_t query
The complete query if present or {0, NULL}.
Definition coap_uri.h:77
coap_str_const_t host
The host part of the URI.
Definition coap_uri.h:71