libcoap 4.3.5-develop-0690cda
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
15
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 if ((int)(q - p) > 255) {
204 coap_log_warn("Host name length too long (%d > 255)\n", (int)(q - p));
205 res = -6;
206 goto error;
207 }
208
209 COAP_SET_STR(&uri->host, q - p, p);
210 ++q;
211 --len;
212#if COAP_AF_LLC_SUPPORT
213 } else if ((len >= LLC_HOST_LEN) && strncmp((const char *)p, "llc[", 4) == 0) {
214 unsigned long sap = 0;
215
216 is_llc = 1;
217
218 while (len && *q != ']') {
219 ++q;
220 --len;
221 }
222
223 if (!len || *q != ']' || p == q) {
224 res = -7;
225 goto error;
226 }
227
228 ++q;
229 --len;
230
231 if (!len || *q != ':') {
232 coap_log_warn("LLC SAP missing in URI\n");
233 res = -7;
234 goto error;
235 }
236
237 ++q;
238 --len;
239
240 while (len && isxdigit(*q)) {
241 if (*q >= 'a' && *q <= 'f')
242 sap = sap * 16 + (*q - 'a' + 10);
243 else if (*q >= 'A' && *q <= 'F')
244 sap = sap * 16 + (*q - 'A' + 10);
245
246 ++q;
247 --len;
248 }
249
250 if (sap > UINT8_MAX) {
251 coap_log_warn("LLC SAP invalid (%lu > 255)\n", sap);
252 res = -7;
253 goto error;
254 }
255
256 COAP_SET_STR(&uri->host, q - p, p);
257#endif /* COAP_AF_LLC_SUPPORT */
258 } else {
259 /* IPv4 address, FQDN or Unix domain socket */
260 if (len >= 3 && p[0] == '%' && p[1] == '2' &&
261 (p[2] == 'F' || p[2] == 'f')) {
262 /* Unix domain definition */
263 uri->port = 0;
264 is_unix_domain = 1;
265 }
266 while (len && *q != ':' && *q != '/' && *q != '?') {
267 ++q;
268 --len;
269 }
270
271 if (p == q) {
272 res = -3;
273 goto error;
274 }
275
276 if ((int)(q - p) > 255) {
277 coap_log_warn("Host name length too long (%d > 255)\n", (int)(q - p));
278 res = -6;
279 goto error;
280 }
281
282 COAP_SET_STR(&uri->host, q - p, p);
283 }
284
285 /* check for Uri-Port (invalid for Unix) */
286 if (len && *q == ':') {
287 if (is_unix_domain || is_llc) {
288 res = -5;
289 goto error;
290 }
291 p = ++q;
292 --len;
293
294 while (len && isdigit(*q)) {
295 ++q;
296 --len;
297 }
298
299 if (p < q) { /* explicit port number given */
300 long uri_port = 0;
301
302 while ((p < q) && (uri_port <= UINT16_MAX))
303 uri_port = uri_port * 10 + (*p++ - '0');
304
305 /* check if port number is in allowed range */
306 if (uri_port > UINT16_MAX) {
307 coap_log_warn("Port number too big (%ld > 65535)\n", uri_port);
308 res = -4;
309 goto error;
310 }
311
312 uri->port = (uint16_t)uri_port;
313 }
314 }
315
316path: /* at this point, p must point to an absolute path */
317
318 if (!len)
319 goto end;
320
321 if (*q == '/') {
322 p = ++q;
323 --len;
324
325 while (len && *q != '?') {
326 ++q;
327 --len;
328 }
329
330 if (p < q) {
331 COAP_SET_STR(&uri->path, q - p, p);
332 p = q;
333 }
334 }
335
336 /* Uri_Query */
337 if (len && *p == '?') {
338 ++p;
339 --len;
340 COAP_SET_STR(&uri->query, len, p);
341 len = 0;
342 }
343
344end:
345 return len ? -1 : 0;
346
347error:
348 return res;
349}
350
351int
352coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
353 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_URI);
354}
355
356int
357coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
358 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_PROXY);
359}
360
361static void
363 size_t i;
364
365 for (i = 0; i < optlist->length; i++) {
366 if (optlist->data[i] >= 'A' && optlist->data[i] <= 'Z') {
367 optlist->data[i] += 'a' - 'A';
368 }
369 }
370}
371
372int
374 coap_optlist_t **optlist_chain, int create_port_host_opt,
375 uint8_t *_buf COAP_UNUSED, size_t buflen COAP_UNUSED) {
376 return !coap_uri_into_optlist(uri, dst, optlist_chain, create_port_host_opt) ? -1 : 0;
377}
378
379int
381 coap_optlist_t **optlist_chain, int create_port_host_opt) {
382 return coap_uri_into_optlist_abbrev(uri, dst, optlist_chain, create_port_host_opt, NULL, 0);
383}
384
385int
387 coap_optlist_t **optlist_chain, int create_port_host_opt,
388 coap_upa_abbrev_t *mapping, uint32_t count) {
389 if (create_port_host_opt && !coap_host_is_unix_domain(&uri->host)) {
390 int add_option = 0;
391
392 if (dst && uri->host.length) {
393#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
394 char addr[INET6_ADDRSTRLEN];
395#else /* WITH_LWIP || WITH_CONTIKI */
396 char addr[40];
397#endif /* WITH_LWIP || WITH_CONTIKI */
398 coap_optlist_t *optlist;
399
400 /* Add in Uri-Host if not match (need to strip off %iface) */
401 size_t uri_host_len = uri->host.length;
402 const uint8_t *cp = uri->host.s;
403
404 /* Unfortunately not null terminated */
405 for (size_t i = 0; i < uri_host_len; i++) {
406 if (cp[i] == '%') {
407 /* %iface specified in host name */
408 uri_host_len = i;
409 break;
410 }
411 }
412
413 if (coap_print_ip_addr(dst, addr, sizeof(addr)) &&
414 (strlen(addr) != uri_host_len ||
415 strncasecmp(addr, (const char *)uri->host.s, uri_host_len) != 0)) {
416 /* add Uri-Host */
417 optlist = coap_new_optlist(COAP_OPTION_URI_HOST, uri_host_len,
418 uri->host.s);
419 if (!optlist)
420 return 0;
421 if (!coap_host_is_unix_domain(&uri->host)) {
422 coap_replace_percents(optlist);
424 }
425 if (!coap_insert_optlist(optlist_chain, optlist)) {
426 return 0;
427 }
428 }
429 }
430 /* Add in UriPort if not default */
431 switch ((int)uri->scheme) {
434 if (uri->port != 80)
435 add_option = 1;
436 break;
439 if (uri->port != 443)
440 add_option = 1;
441 break;
442 default:
445 add_option = 1;
446 break;
447 }
448 if (add_option) {
449 uint8_t tbuf[4];
450
451 coap_insert_optlist(optlist_chain,
453 coap_encode_var_safe(tbuf, 4,
454 (uri->port & 0xffff)),
455 tbuf));
456 }
457 }
458
459 if (uri->path.length) {
461 optlist_chain, mapping, count))
462 return 0;
463 }
464
465 if (uri->query.length) {
467 optlist_chain))
468 return 0;
469 }
470 return 1;
471}
472
473int
475 if (host->length >= 3 && host->s[0] == '%' &&
476 host->s[1] == '2' &&
477 (host->s[2] == 'F' || host->s[2] == 'f')) {
478 return 1;
479 }
480 if (host->length >= 1 && host->s[0] == '/')
481 return 1;
482 return 0;
483}
484
485int
487#if COAP_AF_LLC_SUPPORT
488 size_t length;
489 const uint8_t *s = NULL;
490 int i = 0;
491
492 length = host->length;
493 if (length != LLC_HOST_LEN)
494 return 0;
495
496 s = host->s;
497
498 if (strncmp((const char *)s, "llc[", 4) != 0)
499 return 0;
500
501 length -= 4;
502 s += 4;
503
504 while (length) {
505 if (!isxdigit(s[0]) || !isxdigit(s[1]))
506 return 0;
507
508 length -= 2;
509 s += 2;
510
511 i++;
512
513 if (length <= 0 || i >= 6)
514 break;
515
516 if (s[0] != ':')
517 return 0;
518
519 length--;
520 s++;
521 }
522
523 if (s[0] != ']' || s[1] != ':' || !isxdigit(s[2]) || !isxdigit(s[3]))
524 return 0;
525
526 return 1;
527#else /* COAP_AF_LLC_SUPPORT */
528 (void)host;
529 return 0;
530#endif /* COAP_AF_LLC_SUPPORT */
531}
532
540#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
541
554static void
555decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
556
557 while (length) {
558 length--;
559
560 if (*seg == '%') {
561 if (length < 2)
562 return;
563 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
564
565 seg += 2;
566 length -= 2;
567 } else {
568 *buf = *seg;
569 }
570
571 ++buf;
572 ++seg;
573 }
574}
575
581static int
582check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
583 size_t n = 0;
584
585 while (length) {
586 if (*s == '%') {
587 if (length < 3 || !(isxdigit(s[1]) && isxdigit(s[2])))
588 return -1;
589
590 s += 2;
591 length -= 2;
592 }
593
594 ++s;
595 ++n;
596 --length;
597 }
598
599 *segment_size = n;
600
601 return 0;
602}
603
624static int
625make_decoded_option(const uint8_t *s, size_t length,
626 unsigned char *buf, size_t buflen, size_t *optionsize) {
627 int res;
628 size_t segmentlen;
629 size_t written;
630
631 if (!buflen) {
632 coap_log_debug("make_decoded_option(): buflen is 0!\n");
633 return -1;
634 }
635
636 res = check_segment(s, length, &segmentlen);
637 if (res < 0)
638 return -1;
639
640 /* write option header using delta 0 and length res */
641 written = coap_opt_setheader(buf, buflen, 0, segmentlen);
642
643 assert(written <= buflen);
644
645 if (!written) /* encoding error */
646 return -1;
647
648 buf += written; /* advance past option type/length */
649 buflen -= written;
650
651 if (buflen < segmentlen) {
652 coap_log_debug("buffer too small for option\n");
653 return -1;
654 }
655
656 decode_segment(s, length, buf);
657
658 *optionsize = written + segmentlen;
659
660 return 0;
661}
662
663
664#ifndef min
665#define min(a,b) ((a) < (b) ? (a) : (b))
666#endif
667
668typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
669
675int
676coap_check_dots(const uint8_t *s, size_t len) {
677 uint8_t p;
678
679 if (!len)
680 return 0;
681
682 p = *s;
683
684 /* Check 'first' char */
685 if (p == '%' && len >=3) {
686 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
687 s += 2;
688 len -= 2;
689 }
690 p = '.';
691 }
692 if (p != '.')
693 return 0;
694 if (len == 1)
695 return 1;
696
697 /* Check 'second' char, first is '.' */
698 s++;
699 len--;
700 assert(len);
701 p = *s;
702 if (p == '%' && len >=3) {
703 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
704 len -= 2;
705 }
706 p = '.';
707 }
708 if (p != '.')
709 return 0;
710 if (len == 1)
711 return 2;
712
713 return 0;
714}
715
721
722static void
723backup_segment(void *data) {
724 struct cnt_str *state = (struct cnt_str *)data;
725 int i;
726 uint8_t *buf;
727
728 if (state->n == 0)
729 return;
730
731 state->n--;
732 buf = state->base_buf.s;
733 for (i = 0; i < state->n; i++) {
735 }
736 state->buf.s = buf;
737 state->buf.length = state->base_buf.length - (buf - state->base_buf.s);
738}
739
751static size_t
752coap_split_path_impl(const uint8_t *path, size_t len,
753 segment_handler_t h, void *data) {
754 const uint8_t *p, *q;
755 size_t length = len;
756 int num_dots;
757
758 p = q = path;
759 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
760 if (*q == '/') {
761 /* start new segment */
762 num_dots = coap_check_dots(p, q - p);
763 switch (num_dots) {
764 case 1:
765 /* drop segment */
766 break;
767 case 2:
768 /* backup segment */
769 backup_segment(data);
770 break;
771 case 0:
772 default:
773 /* add segment */
774 h(p, q - p, data);
775 break;
776 }
777
778 p = q + 1;
779 }
780
781 q++;
782 length--;
783 }
784
785 /* write last segment */
786 num_dots = coap_check_dots(p, q - p);
787 switch (num_dots) {
788 case 1:
789 /* drop segment */
790 break;
791 case 2:
792 /* backup segment */
793 backup_segment(data);
794 break;
795 case 0:
796 default:
797 /* add segment */
798 h(p, q - p, data);
799 break;
800 }
801
802 return q - path;
803}
804
805static void
806write_option(const uint8_t *s, size_t len, void *data) {
807 struct cnt_str *state = (struct cnt_str *)data;
808 int res;
809 size_t optionsize;
810 assert(state);
811
812 res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
813 if (res == 0) {
814 state->buf.s += optionsize;
815 state->buf.length -= optionsize;
816 state->n++;
817 }
818}
819
820int
821coap_split_path(const uint8_t *s, size_t length,
822 unsigned char *buf, size_t *buflen) {
823 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
824
825 coap_split_path_impl(s, length, write_option, &tmp);
826
827 *buflen = *buflen - tmp.buf.length;
828
829 return tmp.n;
830}
831
832void
834 size_t i;
835 size_t o = 0;
836
837 for (i = 0; i < optlist->length; i++) {
838 if (optlist->data[i] == '%' && optlist->length - i >= 3) {
839 optlist->data[o] = (hexchar_to_dec(optlist->data[i+1]) << 4) +
840 hexchar_to_dec(optlist->data[i+2]);
841 i+= 2;
842 } else if (o != i) {
843 optlist->data[o] = optlist->data[i];
844 }
845 o++;
846 }
847 optlist->length = o;
848}
849
850static void
852 coap_optlist_t *last = NULL;
853 coap_optlist_t *cur = *optlist_begin;
854
855 if (!cur)
856 return;
857
858 while (cur) {
859 if (!cur->next)
860 break;
861 last = cur;
862 cur = cur->next;
863 }
865 if (last) {
866 last->next = NULL;
867 } else {
868 *optlist_begin = NULL;
869 }
870}
871
872int
873coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
874 coap_optlist_t **optlist_chain) {
875 return coap_path_into_optlist_abbrev(s, length, optnum, optlist_chain, NULL, 0);
876}
877
878int
879coap_path_into_optlist_abbrev(const uint8_t *s, size_t length, coap_option_num_t optnum,
880 coap_optlist_t **optlist_chain, coap_upa_abbrev_t *mapping,
881 uint32_t count) {
882 const uint8_t *p = s;
883 coap_optlist_t *optlist;
884 int num_dots;
885 coap_optlist_t **optlist_start;
886
887 if (*optlist_chain) {
888 /* Something previously in optlist_chain. Need to make that the start */
889 optlist_start = &((*optlist_chain)->next);
890 } else {
891 optlist_start = optlist_chain;
892 }
893
894 if (length > 0 && mapping) {
895 uint32_t i;
896 uint8_t buf[4];
897
898 for (i = 0; i < count; i++) {
899 if (strlen(mapping[i].upa_path) == length &&
900 memcmp(mapping[i].upa_path, s, length) == 0) {
901 /* add in as Uri_path-Abbrev */
903 coap_encode_var_safe(buf, sizeof(buf), mapping[i].upa_value), buf);
904 if (!coap_insert_optlist(optlist_chain, optlist)) {
905 return 0;
906 }
907 return 1;
908 }
909 }
910 }
911 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *s)) {
912 if (*s == '/') { /* start of new path element */
913 /* start new segment */
914 num_dots = coap_check_dots(p, s - p);
915 switch (num_dots) {
916 case 1:
917 /* drop segment */
918 break;
919 case 2:
920 /* backup segment */
921 backup_optlist(optlist_start);
922 break;
923 case 0:
924 default:
925 /* add segment */
926 optlist = coap_new_optlist(optnum, s - p, p);
927 if (!optlist) {
928 return 0;
929 }
930 coap_replace_percents(optlist);
931 if (!coap_insert_optlist(optlist_chain, optlist)) {
932 return 0;
933 }
934 break;
935 }
936 p = s + 1;
937 }
938 s++;
939 length--;
940
941 }
942 /* add last path element */
943 num_dots = coap_check_dots(p, s - p);
944 switch (num_dots) {
945 case 1:
946 /* drop segment */
947 break;
948 case 2:
949 /* backup segment */
950 backup_optlist(optlist_start);
951 break;
952 case 0:
953 default:
954 /* add segment */
955 optlist = coap_new_optlist(optnum, s - p, p);
956 if (!optlist) {
957 return 0;
958 }
959 coap_replace_percents(optlist);
960 if (!coap_insert_optlist(optlist_chain, optlist)) {
961 return 0;
962 }
963 break;
964 }
965 return 1;
966}
967
968int
969coap_split_query(const uint8_t *s, size_t length,
970 unsigned char *buf, size_t *buflen) {
971 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
972 const uint8_t *p;
973
974 p = s;
975 while (length > 0 && *s != '#') {
976 if (*s == '&') { /* start new query element */
977 write_option(p, s - p, &tmp);
978 p = s + 1;
979 }
980
981 s++;
982 length--;
983 }
984
985 /* write last query element */
986 write_option(p, s - p, &tmp);
987
988 *buflen = *buflen - tmp.buf.length;
989 return tmp.n;
990}
991
992int
993coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
994 coap_optlist_t **optlist_chain) {
995 const uint8_t *p = s;
996 coap_optlist_t *optlist;
997
998 while (length > 0 && *s != '#') {
999 if (*s == '&') { /* start of new query element */
1000 /* add previous query element */
1001 optlist = coap_new_optlist(optnum, s - p, p);
1002 if (!optlist) {
1003 return 0;
1004 }
1005 coap_replace_percents(optlist);
1006 if (!coap_insert_optlist(optlist_chain, optlist)) {
1007 return 0;
1008 }
1009 p = s + 1;
1010 }
1011 s++;
1012 length--;
1013 }
1014 /* add last query element */
1015 optlist = coap_new_optlist(optnum, s - p, p);
1016 if (!optlist) {
1017 return 0;
1018 }
1019 coap_replace_percents(optlist);
1020 if (!coap_insert_optlist(optlist_chain, optlist)) {
1021 return 0;
1022 }
1023 return 1;
1024}
1025
1026#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
1027
1028coap_uri_t *
1029coap_new_uri(const uint8_t *uri, unsigned int length) {
1030 uint8_t *result;
1031 coap_uri_t *out_uri;
1032
1033 out_uri = (coap_uri_t *)coap_malloc_type(COAP_STRING, length + 1 + sizeof(coap_uri_t));
1034
1035 if (!out_uri)
1036 return NULL;
1037
1038 result = (uint8_t *)out_uri;
1039 memcpy(URI_DATA(result), uri, length);
1040 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
1041
1042 if (coap_split_uri(URI_DATA(result), length, out_uri) < 0) {
1043 coap_free_type(COAP_STRING, out_uri);
1044 return NULL;
1045 }
1046 return out_uri;
1047}
1048
1049coap_uri_t *
1051 coap_uri_t *result;
1052 uint8_t *p;
1053
1054 if (!uri)
1055 return NULL;
1056
1057 result = (coap_uri_t *)coap_malloc_type(COAP_STRING, uri->query.length + uri->host.length +
1058 uri->path.length + sizeof(coap_uri_t) + 1);
1059
1060 if (!result)
1061 return NULL;
1062
1063 memset(result, 0, sizeof(coap_uri_t));
1064
1065 result->port = uri->port;
1066
1067 if (uri->host.length) {
1068 result->host.s = p = URI_DATA(result);
1069 result->host.length = uri->host.length;
1070
1071 memcpy(p, uri->host.s, uri->host.length);
1072 }
1073
1074 if (uri->path.length) {
1075 result->path.s = p = URI_DATA(result) + uri->host.length;
1076 result->path.length = uri->path.length;
1077
1078 memcpy(p, uri->path.s, uri->path.length);
1079 }
1080
1081 if (uri->query.length) {
1082 result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
1083 result->query.length = uri->query.length;
1084
1085 memcpy(p, uri->query.s, uri->query.length);
1086 }
1087
1088 return result;
1089}
1090
1091void
1095
1096static int
1097is_unescaped_in_path(const uint8_t c) {
1098 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
1099 (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' ||
1100 c == '~' || c == '!' || c == '$' || c == '\'' || c == '(' ||
1101 c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
1102 c=='=' || c==':' || c=='@' || c == '&';
1103}
1104
1105static int
1106is_unescaped_in_query(const uint8_t c) {
1107 return is_unescaped_in_path(c) || c=='/' || c=='?';
1108}
1109
1112 coap_opt_iterator_t opt_iter;
1114 coap_opt_t *q;
1115 coap_string_t *query = NULL;
1116 size_t length = 0;
1117 static const uint8_t hex[] = "0123456789ABCDEF";
1118
1121 coap_option_iterator_init(request, &opt_iter, &f);
1122 while ((q = coap_option_next(&opt_iter))) {
1123 uint16_t seg_len = coap_opt_length(q), i;
1124 const uint8_t *seg= coap_opt_value(q);
1125 for (i = 0; i < seg_len; i++) {
1126 if (is_unescaped_in_query(seg[i]))
1127 length += 1;
1128 else
1129 length += 3;
1130 }
1131 length += 1;
1132 }
1133 if (length > 0)
1134 length -= 1;
1135 if (length > 0) {
1136 query = coap_new_string(length);
1137 if (query) {
1138 query->length = length;
1139 unsigned char *s = query->s;
1140 coap_option_iterator_init(request, &opt_iter, &f);
1141 while ((q = coap_option_next(&opt_iter))) {
1142 if (s != query->s)
1143 *s++ = '&';
1144 uint16_t seg_len = coap_opt_length(q), i;
1145 const uint8_t *seg= coap_opt_value(q);
1146 for (i = 0; i < seg_len; i++) {
1147 if (is_unescaped_in_query(seg[i])) {
1148 *s++ = seg[i];
1149 } else {
1150 *s++ = '%';
1151 *s++ = hex[seg[i]>>4];
1152 *s++ = hex[seg[i]&0x0F];
1153 }
1154 }
1155 }
1156 }
1157 }
1158 return query;
1159}
1160
1161const char *
1163 while (chain) {
1164 coap_upa_chain_t *next = chain->next;
1165
1166 if (chain->upa_value == value) {
1167 return chain->upa_path;
1168 }
1169 chain = next;
1170 }
1171 return NULL;
1172}
1173
1174int
1175coap_map_uri_path_abbrev(coap_upa_chain_t *chain, const char *path, size_t length,
1176 uint32_t *value) {
1177 while (chain) {
1178 coap_upa_chain_t *next = chain->next;
1179
1180 if (strlen(chain->upa_path) == length && memcmp(chain->upa_path, path, length) == 0) {
1181 *value = chain->upa_value;
1182 return 1;
1183 }
1184 chain = next;
1185 }
1186 return 0;
1187}
1188
1191 coap_opt_iterator_t opt_iter;
1193 coap_opt_t *q;
1194 coap_string_t *uri_path = NULL;
1195 size_t length = 0;
1196 static const uint8_t hex[] = "0123456789ABCDEF";
1197
1198 q = coap_check_option(request, COAP_OPTION_URI_PATH_ABB, &opt_iter);
1199 if (q) {
1200 uint32_t value;
1201 const char *exp;
1202 if (coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter) ||
1203 coap_check_option(request, COAP_OPTION_URI_PATH, &opt_iter)) {
1204 return NULL;
1205 }
1208 if (exp) {
1209 uri_path = coap_new_string(strlen(exp));
1210 if (uri_path) {
1211 memcpy(uri_path->s, exp, strlen(exp));
1212 }
1213 return uri_path;
1214 }
1215 return NULL;
1216 }
1217 q = coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter);
1218 if (q) {
1219 coap_uri_t uri;
1220
1222 coap_opt_length(q), &uri) < 0) {
1223 return NULL;
1224 }
1225 uri_path = coap_new_string(uri.path.length);
1226 if (uri_path && uri.path.length) {
1227 memcpy(uri_path->s, uri.path.s, uri.path.length);
1228 }
1229 return uri_path;
1230 }
1231
1234 coap_option_iterator_init(request, &opt_iter, &f);
1235 while ((q = coap_option_next(&opt_iter))) {
1236 uint16_t seg_len = coap_opt_length(q), i;
1237 const uint8_t *seg = coap_opt_value(q);
1238 for (i = 0; i < seg_len; i++) {
1239 if (is_unescaped_in_path(seg[i]))
1240 length += 1;
1241 else
1242 length += 3;
1243 }
1244 /* bump for the leading "/" */
1245 length += 1;
1246 }
1247 /* The first entry does not have a leading "/" */
1248 if (length > 0)
1249 length -= 1;
1250
1251 /* if 0, either no URI_PATH Option, or the first one was empty */
1252 uri_path = coap_new_string(length);
1253 if (uri_path) {
1254 uri_path->length = length;
1255 unsigned char *s = uri_path->s;
1256 int n = 0;
1257 coap_option_iterator_init(request, &opt_iter, &f);
1258 while ((q = coap_option_next(&opt_iter))) {
1259 if (n++) {
1260 *s++ = '/';
1261 }
1262 uint16_t seg_len = coap_opt_length(q), i;
1263 const uint8_t *seg= coap_opt_value(q);
1264 for (i = 0; i < seg_len; i++) {
1265 if (is_unescaped_in_path(seg[i])) {
1266 *s++ = seg[i];
1267 } else {
1268 *s++ = '%';
1269 *s++ = hex[seg[i]>>4];
1270 *s++ = hex[seg[i]&0x0F];
1271 }
1272 }
1273 }
1274 }
1275 return uri_path;
1276}
1277
1278void
1280 while (chain) {
1281 coap_upa_chain_t *next = chain->next;
1282
1284 chain = next;
1285 }
1286}
1287
1288static coap_upa_chain_t *
1290 uint32_t i;
1291 coap_upa_chain_t *chain = NULL;
1292 coap_upa_chain_t *next;
1293
1294 for (i = 0; i < count; i++) {
1295 next = coap_malloc_type(COAP_STRING, sizeof(coap_upa_chain_t) + strlen(list[i].upa_path) + 1);
1296 if (next == NULL)
1297 goto cleanup;
1298
1299 next->upa_value = list[i].upa_value;
1300 next->upa_path = (char *)next + sizeof(coap_upa_chain_t);
1301 strcpy(next->upa_path, list[i].upa_path);
1302 next->next = chain;
1303 chain = next;
1304 }
1305 return chain;
1306
1307cleanup:
1308 coap_delete_upa_chain(chain);
1309 return NULL;
1310}
1311
1312void
1319
1320void
#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...
@ COAP_OPTION_URI_PORT
Definition coap_option.h:76
@ COAP_OPTION_URI_HOST
Definition coap_option.h:72
@ COAP_OPTION_URI_PATH
Definition coap_option.h:79
@ COAP_OPTION_URI_QUERY
Definition coap_option.h:84
@ COAP_OPTION_PROXY_URI
Definition coap_option.h:94
@ COAP_OPTION_URI_PATH_ABB
Definition coap_option.h:81
static void coap_replace_upper_lower(coap_optlist_t *optlist)
Definition coap_uri.c:362
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:373
static void backup_optlist(coap_optlist_t **optlist_begin)
Definition coap_uri.c:851
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:555
static coap_upa_chain_t * coap_build_upa_chain(coap_upa_abbrev_t *list, uint32_t count)
Definition coap_uri.c:1289
static int is_unescaped_in_query(const uint8_t c)
Definition coap_uri.c:1106
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:582
static void write_option(const uint8_t *s, size_t len, void *data)
Definition coap_uri.c:806
static void backup_segment(void *data)
Definition coap_uri.c:723
void coap_delete_uri(coap_uri_t *uri)
Removes the specified coap_uri_t object.
Definition coap_uri.c:1092
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:752
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:540
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:625
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:486
static int is_unescaped_in_path(const uint8_t c)
Definition coap_uri.c:1097
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:1050
#define URI_DATA(uriobj)
Definition coap_uri.c:1026
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:1029
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:474
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition coap_uri.c:668
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(coap_option_num_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_DEFAULT_PORT
Definition coap_pdu.h:39
#define COAPS_DEFAULT_PORT
Definition coap_pdu.h:40
#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:938
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:943
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition coap_uri.c:1190
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:821
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:1313
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:1321
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:993
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:352
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:873
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:357
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:386
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:380
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:969
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:879
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:1111
int coap_map_uri_path_abbrev(coap_upa_chain_t *chain, const char *path, size_t length, uint32_t *value)
Definition coap_uri.c:1175
int coap_check_dots(const uint8_t *s, size_t len)
Checks if path segment s consists of one or two dots.
Definition coap_uri.c:676
void coap_delete_upa_chain(coap_upa_chain_t *chain)
Clean up a UPA chain.
Definition coap_uri.c:1279
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:1162
void coap_replace_percents(coap_optlist_t *optlist)
replace any % hex definitions with the actual character.
Definition coap_uri.c:833
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:719
coap_string_t base_buf
Definition coap_uri.c:717
coap_string_t buf
Definition coap_uri.c:718
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 '/').
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