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