libcoap 4.3.5-develop-0bd03b6
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-2025 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
43COAP_STATIC_INLINE const uint8_t *
44strnchr(const uint8_t *s, size_t len, unsigned char c) {
45 while (len && *s++ != c)
46 --len;
47
48 return len ? s : NULL;
49}
50
55
61 { "http", 80, 1, COAP_URI_SCHEME_HTTP },
62 { "https", 443, 1, COAP_URI_SCHEME_HTTPS },
63 { "coap+ws", 80, 0, COAP_URI_SCHEME_COAP_WS },
64 { "coaps+ws", 443, 0, COAP_URI_SCHEME_COAPS_WS }
65};
66
67/*
68 * Returns 0 All OK
69 * -1 Insufficient / Invalid parameters
70 * -2 No '://'
71 * -3 Ipv6 definition error or no host defined after scheme://
72 * -4 Invalid port value
73 * -5 Port defined for Unix domain
74 * -6 Hostname > 255 chars
75 */
76static int
77coap_split_uri_sub(const uint8_t *str_var,
78 size_t len,
79 coap_uri_t *uri,
80 coap_uri_check_t check_proxy) {
81 const uint8_t *p, *q;
82 int res = 0;
83 size_t i;
84 int is_unix_domain = 0;
85
86 if (!str_var || !uri || len == 0)
87 return -1;
88
89 memset(uri, 0, sizeof(coap_uri_t));
91
92 /* search for scheme */
93 p = str_var;
94 if (*p == '/') {
95 /* no scheme, host or port */
96 if (check_proxy == COAP_URI_CHECK_PROXY) {
97 /* Must have ongoing host if proxy definition */
98 return -1;
99 }
100 q = p;
101 goto path;
102 }
103
104 /* find scheme terminating :// */
105 while (len >= 3 && !(p[0] == ':' && p[1] == '/' && p[2] == '/')) {
106 ++p;
107 --len;
108 }
109 if (len < 3) {
110 /* scheme not defined with a :// terminator */
111 res = -2;
112 goto error;
113 }
114 for (i = 0; i < COAP_URI_SCHEME_LAST; i++) {
115 if ((p - str_var) == (int)strlen(coap_uri_scheme[i].name) &&
116 memcmp(str_var, coap_uri_scheme[i].name, p - str_var) == 0) {
117 if (check_proxy != COAP_URI_CHECK_PROXY && coap_uri_scheme[i].proxy_only) {
118 coap_log_err("%.*s URI scheme not enabled (not a proxy)\n",
119 (int)(p - str_var), str_var);
120 return -1;
121 }
122 uri->scheme = coap_uri_scheme[i].scheme;
123 uri->port = coap_uri_scheme[i].port;
124 break;
125 }
126 }
127 if (i == COAP_URI_SCHEME_LAST) {
128 /* scheme unknown */
129 coap_log_err("%.*s URI scheme unknown\n", (int)(p - str_var), str_var);
130 res = -1;
131 goto error;
132 }
133 switch (uri->scheme) {
135 break;
137 if (!coap_dtls_is_supported()) {
138 coap_log_err("coaps URI scheme not supported in this version of libcoap\n");
139 return -1;
140 }
141 break;
143 if (!coap_tcp_is_supported()) {
144 coap_log_err("coap+tcp URI scheme not supported in this version of libcoap\n");
145 return -1;
146 }
147 break;
149 if (!coap_tls_is_supported()) {
150 coap_log_err("coaps+tcp URI scheme not supported in this version of libcoap\n");
151 return -1;
152 }
153 break;
155 if (!coap_ws_is_supported()) {
156 coap_log_err("coap+ws URI scheme not supported in this version of libcoap\n");
157 return -1;
158 }
159 break;
161 if (!coap_wss_is_supported()) {
162 coap_log_err("coaps+ws URI scheme not supported in this version of libcoap\n");
163 return -1;
164 }
165 break;
168 /* Not proxy, caught above. For proxy, assume app is doing CoAP <> HTTP mapping. */
169 break;
171 default:
172 coap_log_warn("Unsupported URI type %d\n", uri->scheme);
173 return -1;
174 }
175 /* skip :// */
176 p += 3;
177 len -= 3;
178
179 /* p points to beginning of Uri-Host */
180 q = p;
181 if (len && *p == '[') {
182 /* IPv6 address reference */
183 ++p;
184 ++q;
185 --len;
186
187 while (len && *q != ']' && (isxdigit(*q) || *q == ':')) {
188 ++q;
189 --len;
190 }
191
192 if (!len || *q != ']' || p == q) {
193 res = -3;
194 goto error;
195 }
196
197 COAP_SET_STR(&uri->host, q - p, p);
198 ++q;
199 --len;
200 } else {
201 /* IPv4 address, FQDN or Unix domain socket */
202 if (len >= 3 && p[0] == '%' && p[1] == '2' &&
203 (p[2] == 'F' || p[2] == 'f')) {
204 /* Unix domain definition */
205 uri->port = 0;
206 is_unix_domain = 1;
207 }
208 while (len && *q != ':' && *q != '/' && *q != '?') {
209 ++q;
210 --len;
211 }
212
213 if (p == q) {
214 res = -3;
215 goto error;
216 }
217
218 if ((int)(q - p) > 255) {
219 coap_log_warn("Host name length too long (%d > 255)\n", (int)(q - p));
220 res = -6;
221 goto error;
222 }
223
224 COAP_SET_STR(&uri->host, q - p, p);
225 }
226
227 /* check for Uri-Port (invalid for Unix) */
228 if (len && *q == ':') {
229 if (is_unix_domain) {
230 res = -5;
231 goto error;
232 }
233 p = ++q;
234 --len;
235
236 while (len && isdigit(*q)) {
237 ++q;
238 --len;
239 }
240
241 if (p < q) { /* explicit port number given */
242 long uri_port = 0;
243
244 while ((p < q) && (uri_port <= UINT16_MAX))
245 uri_port = uri_port * 10 + (*p++ - '0');
246
247 /* check if port number is in allowed range */
248 if (uri_port > UINT16_MAX) {
249 coap_log_warn("Port number too big (%ld > 65535)\n", uri_port);
250 res = -4;
251 goto error;
252 }
253
254 uri->port = (uint16_t)uri_port;
255 }
256 }
257
258path: /* at this point, p must point to an absolute path */
259
260 if (!len)
261 goto end;
262
263 if (*q == '/') {
264 p = ++q;
265 --len;
266
267 while (len && *q != '?') {
268 ++q;
269 --len;
270 }
271
272 if (p < q) {
273 COAP_SET_STR(&uri->path, q - p, p);
274 p = q;
275 }
276 }
277
278 /* Uri_Query */
279 if (len && *p == '?') {
280 ++p;
281 --len;
282 COAP_SET_STR(&uri->query, len, p);
283 len = 0;
284 }
285
286end:
287 return len ? -1 : 0;
288
289error:
290 return res;
291}
292
293int
294coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
295 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_URI);
296}
297
298int
299coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
300 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_PROXY);
301}
302
303static void
305 size_t i;
306
307 for (i = 0; i < optlist->length; i++) {
308 if (optlist->data[i] >= 'A' && optlist->data[i] <= 'Z') {
309 optlist->data[i] += 'a' - 'A';
310 }
311 }
312}
313
314int
316 coap_optlist_t **optlist_chain, int create_port_host_opt,
317 uint8_t *_buf COAP_UNUSED, size_t buflen COAP_UNUSED) {
318 return !coap_uri_into_optlist(uri, dst, optlist_chain, create_port_host_opt) ? -1 : 0;
319}
320
321int
323 coap_optlist_t **optlist_chain, int create_port_host_opt) {
324 if (create_port_host_opt && !coap_host_is_unix_domain(&uri->host)) {
325 int add_option = 0;
326
327 if (dst && uri->host.length) {
328#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
329 char addr[INET6_ADDRSTRLEN];
330#else /* WITH_LWIP || WITH_CONTIKI */
331 char addr[40];
332#endif /* WITH_LWIP || WITH_CONTIKI */
333 coap_optlist_t *optlist;
334
335 /* Add in Uri-Host if not match (need to strip off %iface) */
336 size_t uri_host_len = uri->host.length;
337 const uint8_t *cp = uri->host.s;
338
339 /* Unfortunately not null terminated */
340 for (size_t i = 0; i < uri_host_len; i++) {
341 if (cp[i] == '%') {
342 /* %iface specified in host name */
343 uri_host_len = i;
344 break;
345 }
346 }
347
348 if (coap_print_ip_addr(dst, addr, sizeof(addr)) &&
349 (strlen(addr) != uri_host_len ||
350 strncasecmp(addr, (const char *)uri->host.s, uri_host_len) != 0)) {
351 /* add Uri-Host */
352 optlist = coap_new_optlist(COAP_OPTION_URI_HOST, uri_host_len,
353 uri->host.s);
354 if (!coap_host_is_unix_domain(&uri->host)) {
355 coap_replace_percents(optlist);
357 }
358 if (!coap_insert_optlist(optlist_chain, optlist)) {
359 return 0;
360 }
361 }
362 }
363 /* Add in UriPort if not default */
364 switch ((int)uri->scheme) {
367 if (uri->port != 80)
368 add_option = 1;
369 break;
372 if (uri->port != 443)
373 add_option = 1;
374 break;
375 default:
378 add_option = 1;
379 break;
380 }
381 if (add_option) {
382 uint8_t tbuf[4];
383
384 coap_insert_optlist(optlist_chain,
386 coap_encode_var_safe(tbuf, 4,
387 (uri->port & 0xffff)),
388 tbuf));
389 }
390 }
391
392 if (uri->path.length) {
394 optlist_chain))
395 return 0;
396 }
397
398 if (uri->query.length) {
400 optlist_chain))
401 return 0;
402 }
403 return 1;
404}
405
406int
408 if (host->length >= 3 && host->s[0] == '%' &&
409 host->s[1] == '2' &&
410 (host->s[2] == 'F' || host->s[2] == 'f')) {
411 return 1;
412 }
413 if (host->length >= 1 && host->s[0] == '/')
414 return 1;
415 return 0;
416}
417
425#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
426
439static void
440decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
441
442 while (length--) {
443
444 if (*seg == '%') {
445 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
446
447 seg += 2;
448 length -= 2;
449 } else {
450 *buf = *seg;
451 }
452
453 ++buf;
454 ++seg;
455 }
456}
457
463static int
464check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
465 size_t n = 0;
466
467 while (length) {
468 if (*s == '%') {
469 if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
470 return -1;
471
472 s += 2;
473 length -= 2;
474 }
475
476 ++s;
477 ++n;
478 --length;
479 }
480
481 *segment_size = n;
482
483 return 0;
484}
485
506static int
507make_decoded_option(const uint8_t *s, size_t length,
508 unsigned char *buf, size_t buflen, size_t *optionsize) {
509 int res;
510 size_t segmentlen;
511 size_t written;
512
513 if (!buflen) {
514 coap_log_debug("make_decoded_option(): buflen is 0!\n");
515 return -1;
516 }
517
518 res = check_segment(s, length, &segmentlen);
519 if (res < 0)
520 return -1;
521
522 /* write option header using delta 0 and length res */
523 written = coap_opt_setheader(buf, buflen, 0, segmentlen);
524
525 assert(written <= buflen);
526
527 if (!written) /* encoding error */
528 return -1;
529
530 buf += written; /* advance past option type/length */
531 buflen -= written;
532
533 if (buflen < segmentlen) {
534 coap_log_debug("buffer too small for option\n");
535 return -1;
536 }
537
538 decode_segment(s, length, buf);
539
540 *optionsize = written + segmentlen;
541
542 return 0;
543}
544
545
546#ifndef min
547#define min(a,b) ((a) < (b) ? (a) : (b))
548#endif
549
550typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
551
557static int
558dots(const uint8_t *s, size_t len) {
559 uint8_t p;
560
561 if (!len)
562 return 0;
563
564 p = *s;
565
566 /* Check 'first' char */
567 if (p == '%' && len >=3) {
568 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
569 s += 2;
570 len -= 2;
571 }
572 p = '.';
573 }
574 if (p != '.')
575 return 0;
576 if (len == 1)
577 return 1;
578
579 /* Check 'second' char, first is '.' */
580 s++;
581 len--;
582 assert(len);
583 p = *s;
584 if (p == '%' && len >=3) {
585 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
586 len -= 2;
587 }
588 p = '.';
589 }
590 if (p != '.')
591 return 0;
592 if (len == 1)
593 return 2;
594
595 return 0;
596}
597
603
604static void
605backup_segment(void *data) {
606 struct cnt_str *state = (struct cnt_str *)data;
607 int i;
608 uint8_t *buf;
609
610 if (state->n == 0)
611 return;
612
613 state->n--;
614 buf = state->base_buf.s;
615 for (i = 0; i < state->n; i++) {
617 }
618 state->buf.s = buf;
619 state->buf.length = state->base_buf.length - (buf - state->base_buf.s);
620}
621
633static size_t
634coap_split_path_impl(const uint8_t *path, size_t len,
635 segment_handler_t h, void *data) {
636 const uint8_t *p, *q;
637 size_t length = len;
638 int num_dots;
639
640 p = q = path;
641 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
642 if (*q == '/') {
643 /* start new segment */
644 num_dots = dots(p, q - p);
645 switch (num_dots) {
646 case 1:
647 /* drop segment */
648 break;
649 case 2:
650 /* backup segment */
651 backup_segment(data);
652 break;
653 case 0:
654 default:
655 /* add segment */
656 h(p, q - p, data);
657 break;
658 }
659
660 p = q + 1;
661 }
662
663 q++;
664 length--;
665 }
666
667 /* write last segment */
668 num_dots = dots(p, q - p);
669 switch (num_dots) {
670 case 1:
671 /* drop segment */
672 break;
673 case 2:
674 /* backup segment */
675 backup_segment(data);
676 break;
677 case 0:
678 default:
679 /* add segment */
680 h(p, q - p, data);
681 break;
682 }
683
684 return q - path;
685}
686
687static void
688write_option(const uint8_t *s, size_t len, void *data) {
689 struct cnt_str *state = (struct cnt_str *)data;
690 int res;
691 size_t optionsize;
692 assert(state);
693
694 res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
695 if (res == 0) {
696 state->buf.s += optionsize;
697 state->buf.length -= optionsize;
698 state->n++;
699 }
700}
701
702int
703coap_split_path(const uint8_t *s, size_t length,
704 unsigned char *buf, size_t *buflen) {
705 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
706
707 coap_split_path_impl(s, length, write_option, &tmp);
708
709 *buflen = *buflen - tmp.buf.length;
710
711 return tmp.n;
712}
713
714void
716 size_t i;
717 size_t o = 0;
718
719 for (i = 0; i < optlist->length; i++) {
720 if (optlist->data[i] == '%' && optlist->length - i >= 3) {
721 optlist->data[o] = (hexchar_to_dec(optlist->data[i+1]) << 4) +
722 hexchar_to_dec(optlist->data[i+2]);
723 i+= 2;
724 } else if (o != i) {
725 optlist->data[o] = optlist->data[i];
726 }
727 o++;
728 }
729 optlist->length = o;
730}
731
732static void
734 coap_optlist_t *last = NULL;
735 coap_optlist_t *cur = *optlist_begin;
736
737 if (!cur)
738 return;
739
740 while (cur) {
741 if (!cur->next)
742 break;
743 last = cur;
744 cur = cur->next;
745 }
747 if (last) {
748 last->next = NULL;
749 } else {
750 *optlist_begin = NULL;
751 }
752}
753
754int
755coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
756 coap_optlist_t **optlist_chain) {
757 const uint8_t *p = s;
758 coap_optlist_t *optlist;
759 int num_dots;
760 coap_optlist_t **optlist_start;
761
762 if (*optlist_chain) {
763 /* Something previously in optlist_chain. Need to make that the start */
764 optlist_start = &((*optlist_chain)->next);
765 } else {
766 optlist_start = optlist_chain;
767 }
768
769 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *s)) {
770 if (*s == '/') { /* start of new path element */
771 /* start new segment */
772 num_dots = dots(p, s - p);
773 switch (num_dots) {
774 case 1:
775 /* drop segment */
776 break;
777 case 2:
778 /* backup segment */
779 backup_optlist(optlist_start);
780 break;
781 case 0:
782 default:
783 /* add segment */
784 optlist = coap_new_optlist(optnum, s - p, p);
785 coap_replace_percents(optlist);
786 if (!coap_insert_optlist(optlist_chain, optlist)) {
787 return 0;
788 }
789 break;
790 }
791 p = s + 1;
792 }
793 s++;
794 length--;
795
796 }
797 /* add last path element */
798 num_dots = dots(p, s - p);
799 switch (num_dots) {
800 case 1:
801 /* drop segment */
802 break;
803 case 2:
804 /* backup segment */
805 backup_optlist(optlist_start);
806 break;
807 case 0:
808 default:
809 /* add segment */
810 optlist = coap_new_optlist(optnum, s - p, p);
811 coap_replace_percents(optlist);
812 if (!coap_insert_optlist(optlist_chain, optlist)) {
813 return 0;
814 }
815 break;
816 }
817 return 1;
818}
819
820int
821coap_split_query(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 const uint8_t *p;
825
826 p = s;
827 while (length > 0 && *s != '#') {
828 if (*s == '&') { /* start new query element */
829 write_option(p, s - p, &tmp);
830 p = s + 1;
831 }
832
833 s++;
834 length--;
835 }
836
837 /* write last query element */
838 write_option(p, s - p, &tmp);
839
840 *buflen = *buflen - tmp.buf.length;
841 return tmp.n;
842}
843
844int
845coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
846 coap_optlist_t **optlist_chain) {
847 const uint8_t *p = s;
848 coap_optlist_t *optlist;
849
850 while (length > 0 && *s != '#') {
851 if (*s == '&') { /* start of new query element */
852 /* add previous query element */
853 optlist = coap_new_optlist(optnum, s - p, p);
854 coap_replace_percents(optlist);
855 if (!coap_insert_optlist(optlist_chain, optlist)) {
856 return 0;
857 }
858 p = s + 1;
859 }
860 s++;
861 length--;
862 }
863 /* add last query element */
864 optlist = coap_new_optlist(optnum, s - p, p);
865 coap_replace_percents(optlist);
866 if (!coap_insert_optlist(optlist_chain, optlist)) {
867 return 0;
868 }
869 return 1;
870}
871
872#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
873
875coap_new_uri(const uint8_t *uri, unsigned int length) {
876 uint8_t *result;
877 coap_uri_t *out_uri;
878
879 out_uri = (coap_uri_t *)coap_malloc_type(COAP_STRING, length + 1 + sizeof(coap_uri_t));
880
881 if (!out_uri)
882 return NULL;
883
884 result = (uint8_t *)out_uri;
885 memcpy(URI_DATA(result), uri, length);
886 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
887
888 if (coap_split_uri(URI_DATA(result), length, out_uri) < 0) {
889 coap_free_type(COAP_STRING, out_uri);
890 return NULL;
891 }
892 return out_uri;
893}
894
897 coap_uri_t *result;
898 uint8_t *p;
899
900 if (!uri)
901 return NULL;
902
904 uri->path.length + sizeof(coap_uri_t) + 1);
905
906 if (!result)
907 return NULL;
908
909 memset(result, 0, sizeof(coap_uri_t));
910
911 result->port = uri->port;
912
913 if (uri->host.length) {
914 result->host.s = p = URI_DATA(result);
915 result->host.length = uri->host.length;
916
917 memcpy(p, uri->host.s, uri->host.length);
918 }
919
920 if (uri->path.length) {
921 result->path.s = p = URI_DATA(result) + uri->host.length;
922 result->path.length = uri->path.length;
923
924 memcpy(p, uri->path.s, uri->path.length);
925 }
926
927 if (uri->query.length) {
928 result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
929 result->query.length = uri->query.length;
930
931 memcpy(p, uri->query.s, uri->query.length);
932 }
933
934 return result;
935}
936
937void
941
942static int
943is_unescaped_in_path(const uint8_t c) {
944 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
945 (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' ||
946 c == '~' || c == '!' || c == '$' || c == '\'' || c == '(' ||
947 c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
948 c=='=' || c==':' || c=='@' || c == '&';
949}
950
951static int
952is_unescaped_in_query(const uint8_t c) {
953 return is_unescaped_in_path(c) || c=='/' || c=='?';
954}
955
957coap_get_query(const coap_pdu_t *request) {
958 coap_opt_iterator_t opt_iter;
960 coap_opt_t *q;
961 coap_string_t *query = NULL;
962 size_t length = 0;
963 static const uint8_t hex[] = "0123456789ABCDEF";
964
967 coap_option_iterator_init(request, &opt_iter, &f);
968 while ((q = coap_option_next(&opt_iter))) {
969 uint16_t seg_len = coap_opt_length(q), i;
970 const uint8_t *seg= coap_opt_value(q);
971 for (i = 0; i < seg_len; i++) {
972 if (is_unescaped_in_query(seg[i]))
973 length += 1;
974 else
975 length += 3;
976 }
977 length += 1;
978 }
979 if (length > 0)
980 length -= 1;
981 if (length > 0) {
982 query = coap_new_string(length);
983 if (query) {
984 query->length = length;
985 unsigned char *s = query->s;
986 coap_option_iterator_init(request, &opt_iter, &f);
987 while ((q = coap_option_next(&opt_iter))) {
988 if (s != query->s)
989 *s++ = '&';
990 uint16_t seg_len = coap_opt_length(q), i;
991 const uint8_t *seg= coap_opt_value(q);
992 for (i = 0; i < seg_len; i++) {
993 if (is_unescaped_in_query(seg[i])) {
994 *s++ = seg[i];
995 } else {
996 *s++ = '%';
997 *s++ = hex[seg[i]>>4];
998 *s++ = hex[seg[i]&0x0F];
999 }
1000 }
1001 }
1002 }
1003 }
1004 return query;
1005}
1006
1009 coap_opt_iterator_t opt_iter;
1011 coap_opt_t *q;
1012 coap_string_t *uri_path = NULL;
1013 size_t length = 0;
1014 static const uint8_t hex[] = "0123456789ABCDEF";
1015
1016 q = coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter);
1017 if (q) {
1018 coap_uri_t uri;
1019
1021 coap_opt_length(q), &uri) < 0) {
1022 return NULL;
1023 }
1024 uri_path = coap_new_string(uri.path.length);
1025 if (uri_path) {
1026 memcpy(uri_path->s, uri.path.s, uri.path.length);
1027 }
1028 return uri_path;
1029 }
1030
1033 coap_option_iterator_init(request, &opt_iter, &f);
1034 while ((q = coap_option_next(&opt_iter))) {
1035 uint16_t seg_len = coap_opt_length(q), i;
1036 const uint8_t *seg= coap_opt_value(q);
1037 for (i = 0; i < seg_len; i++) {
1038 if (is_unescaped_in_path(seg[i]))
1039 length += 1;
1040 else
1041 length += 3;
1042 }
1043 /* bump for the leading "/" */
1044 length += 1;
1045 }
1046 /* The first entry does not have a leading "/" */
1047 if (length > 0)
1048 length -= 1;
1049
1050 /* if 0, either no URI_PATH Option, or the first one was empty */
1051 uri_path = coap_new_string(length);
1052 if (uri_path) {
1053 uri_path->length = length;
1054 unsigned char *s = uri_path->s;
1055 int n = 0;
1056 coap_option_iterator_init(request, &opt_iter, &f);
1057 while ((q = coap_option_next(&opt_iter))) {
1058 if (n++) {
1059 *s++ = '/';
1060 }
1061 uint16_t seg_len = coap_opt_length(q), i;
1062 const uint8_t *seg= coap_opt_value(q);
1063 for (i = 0; i < seg_len; i++) {
1064 if (is_unescaped_in_path(seg[i])) {
1065 *s++ = seg[i];
1066 } else {
1067 *s++ = '%';
1068 *s++ = hex[seg[i]>>4];
1069 *s++ = hex[seg[i]&0x0F];
1070 }
1071 }
1072 }
1073 }
1074 return uri_path;
1075}
#define INET6_ADDRSTRLEN
Definition coap_debug.c:234
Library specific build wrapper for coap_internal.h.
@ COAP_STRING
Definition coap_mem.h:48
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.
uint16_t coap_option_num_t
Definition coap_option.h:24
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:30
static void coap_replace_upper_lower(coap_optlist_t *optlist)
Definition coap_uri.c:304
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:558
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:315
static void backup_optlist(coap_optlist_t **optlist_begin)
Definition coap_uri.c:733
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:440
static int is_unescaped_in_query(const uint8_t c)
Definition coap_uri.c:952
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:44
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:464
static void write_option(const uint8_t *s, size_t len, void *data)
Definition coap_uri.c:688
static void backup_segment(void *data)
Definition coap_uri.c:605
void coap_delete_uri(coap_uri_t *uri)
Removes the specified coap_uri_t object.
Definition coap_uri.c:938
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:634
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:77
#define hexchar_to_dec(c)
Calculates decimal value from hexadecimal ASCII character given in c.
Definition coap_uri.c:425
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:507
static int is_unescaped_in_path(const uint8_t c)
Definition coap_uri.c:943
coap_uri_check_t
Definition coap_uri.c:51
@ COAP_URI_CHECK_URI
Definition coap_uri.c:52
@ COAP_URI_CHECK_PROXY
Definition coap_uri.c:53
coap_uri_t * coap_clone_uri(const coap_uri_t *uri)
Clones the specified coap_uri_t object.
Definition coap_uri.c:896
#define URI_DATA(uriobj)
Definition coap_uri.c:872
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:875
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:407
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition coap_uri.c:550
static int coap_uri_scheme_is_secure(const coap_uri_t *uri)
Definition coap_uri.h:88
@ COAP_URI_SCHEME_COAPS_WS
Definition coap_uri.h:40
@ COAP_URI_SCHEME_COAPS_TCP
Definition coap_uri.h:36
@ COAP_URI_SCHEME_COAPS
Definition coap_uri.h:34
@ COAP_URI_SCHEME_COAP_TCP
Definition coap_uri.h:35
@ COAP_URI_SCHEME_COAP_WS
Definition coap_uri.h:39
@ COAP_URI_SCHEME_HTTPS
Definition coap_uri.h:38
@ COAP_URI_SCHEME_COAP
Definition coap_uri.h:33
@ COAP_URI_SCHEME_LAST
Definition coap_uri.h:41
@ COAP_URI_SCHEME_HTTP
Definition coap_uri.h:37
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
#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:417
#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:124
#define COAP_DEFAULT_PORT
Definition coap_pdu.h:41
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:136
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:131
#define COAPS_DEFAULT_PORT
Definition coap_pdu.h:42
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:128
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:146
#define COAP_SET_STR(st, l, v)
Definition coap_str.h:54
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.
Definition coap_tcp.c:29
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:933
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:938
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition coap_uri.c:1008
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:703
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:845
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:294
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:755
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:299
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:322
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:821
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:957
coap_uri_info_t coap_uri_scheme[COAP_URI_SCHEME_LAST]
Definition coap_uri.c:56
void coap_replace_percents(coap_optlist_t *optlist)
replace any % hex definitions with the actual character.
Definition coap_uri.c:715
#define COAP_UNUSED
Definition libcoap.h:74
#define COAP_STATIC_INLINE
Definition libcoap.h:57
int n
Definition coap_uri.c:601
coap_string_t base_buf
Definition coap_uri.c:599
coap_string_t buf
Definition coap_uri.c:600
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:49
const uint8_t * s
read-only string data
Definition coap_str.h:51
size_t length
length of string
Definition coap_str.h:50
CoAP string data definition.
Definition coap_str.h:41
uint8_t * s
string data
Definition coap_str.h:43
size_t length
length of string
Definition coap_str.h:42
coap_uri_scheme_t scheme
scheme
uint16_t port
default scheme port
Representation of parsed URI.
Definition coap_uri.h:72
enum coap_uri_scheme_t scheme
The parsed scheme specifier.
Definition coap_uri.h:84
coap_str_const_t path
The complete path if present or {0, NULL}.
Definition coap_uri.h:75
uint16_t port
The port in host byte order.
Definition coap_uri.h:74
coap_str_const_t query
The complete query if present or {0, NULL}.
Definition coap_uri.h:79
coap_str_const_t host
The host part of the URI.
Definition coap_uri.h:73