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