libcoap 4.3.5
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
15
17
18#if defined(HAVE_LIMITS_H)
19#include <limits.h>
20#endif
21
22#include <stdint.h>
23#include <stdio.h>
24#include <string.h>
25#include <ctype.h>
26
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
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
182 /* Sanity check the host length */
183 if ((size_t)(q - p) > 255) {
184 coap_log_warn("URI host name too long (%zu > 255)\n", (size_t)(q - p));
185 res = -4;
186 goto error;
187 }
188 COAP_SET_STR(&uri->host, q - p, p);
189 ++q;
190 --len;
191 } else {
192 /* IPv4 address, FQDN or Unix domain socket */
193 if (len >= 3 && p[0] == '%' && p[1] == '2' &&
194 (p[2] == 'F' || p[2] == 'f')) {
195 /* Unix domain definition */
196 uri->port = 0;
197 is_unix_domain = 1;
198 }
199 while (len && *q != ':' && *q != '/' && *q != '?') {
200 ++q;
201 --len;
202 }
203
204 if (p == q) {
205 res = -3;
206 goto error;
207 }
208
209
210 /* Sanity check the host length */
211 if ((size_t)(q - p) > 255) {
212 coap_log_warn("URI host name too long (%zu > 255)\n", (size_t)(q - p));
213 res = -4;
214 goto error;
215 }
216 COAP_SET_STR(&uri->host, q - p, p);
217 }
218
219 /* check for Uri-Port (invalid for Unix) */
220 if (len && *q == ':') {
221 if (is_unix_domain) {
222 res = -5;
223 goto error;
224 }
225 p = ++q;
226 --len;
227
228 while (len && isdigit(*q)) {
229 ++q;
230 --len;
231 }
232
233 if (p < q) { /* explicit port number given */
234 long uri_port = 0;
235
236 while ((p < q) && (uri_port <= UINT16_MAX))
237 uri_port = uri_port * 10 + (*p++ - '0');
238
239 /* check if port number is in allowed range */
240 if (uri_port > UINT16_MAX) {
241 res = -4;
242 goto error;
243 }
244
245 uri->port = (uint16_t)uri_port;
246 }
247 }
248
249path: /* at this point, p must point to an absolute path */
250
251 if (!len)
252 goto end;
253
254 if (*q == '/') {
255 p = ++q;
256 --len;
257
258 while (len && *q != '?') {
259 ++q;
260 --len;
261 }
262
263 if (p < q) {
264 COAP_SET_STR(&uri->path, q - p, p);
265 p = q;
266 }
267 }
268
269 /* Uri_Query */
270 if (len && *p == '?') {
271 ++p;
272 --len;
273 COAP_SET_STR(&uri->query, len, p);
274 len = 0;
275 }
276
277end:
278 return len ? -1 : 0;
279
280error:
281 return res;
282}
283
284int
285coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
286 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_URI);
287}
288
289int
290coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) {
291 return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_PROXY);
292}
293
294static void
296 size_t i;
297
298 for (i = 0; i < optlist->length; i++) {
299 if (optlist->data[i] >= 'A' && optlist->data[i] <= 'Z') {
300 optlist->data[i] += 'a' - 'A';
301 }
302 }
303}
304
305int
307 coap_optlist_t **optlist_chain, int create_port_host_opt,
308 uint8_t *_buf COAP_UNUSED, size_t buflen COAP_UNUSED) {
309 return !coap_uri_into_optlist(uri, dst, optlist_chain, create_port_host_opt) ? -1 : 0;
310}
311
312int
314 coap_optlist_t **optlist_chain, int create_port_host_opt) {
315 if (create_port_host_opt && !coap_host_is_unix_domain(&uri->host)) {
316 int add_option = 0;
317
318 if (dst && uri->host.length) {
319#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
320 char addr[INET6_ADDRSTRLEN];
321#else /* WITH_LWIP || WITH_CONTIKI */
322 char addr[40];
323#endif /* WITH_LWIP || WITH_CONTIKI */
324 coap_optlist_t *optlist;
325
326 /* Add in Uri-Host if not match (need to strip off %iface) */
327 size_t uri_host_len = uri->host.length;
328 const uint8_t *cp = uri->host.s;
329
330 /* Unfortunately not null terminated */
331 for (size_t i = 0; i < uri_host_len; i++) {
332 if (cp[i] == '%') {
333 /* %iface specified in host name */
334 uri_host_len = i;
335 break;
336 }
337 }
338
339 if (coap_print_ip_addr(dst, addr, sizeof(addr)) &&
340 (strlen(addr) != uri_host_len ||
341 memcmp(addr, uri->host.s, uri_host_len) != 0)) {
342 /* add Uri-Host */
344 uri->host.s);
345 if (!coap_host_is_unix_domain(&uri->host)) {
346 coap_replace_percents(optlist);
348 }
349 if (!coap_insert_optlist(optlist_chain, optlist)) {
350 return 0;
351 }
352 }
353 }
354 /* Add in UriPort if not default */
355 switch ((int)uri->scheme) {
358 if (uri->port != 80)
359 add_option = 1;
360 break;
363 if (uri->port != 443)
364 add_option = 1;
365 break;
366 default:
369 add_option = 1;
370 break;
371 }
372 if (add_option) {
373 uint8_t tbuf[4];
374
375 coap_insert_optlist(optlist_chain,
377 coap_encode_var_safe(tbuf, 4,
378 (uri->port & 0xffff)),
379 tbuf));
380 }
381 }
382
383 if (uri->path.length) {
385 optlist_chain))
386 return 0;
387 }
388
389 if (uri->query.length) {
391 optlist_chain))
392 return 0;
393 }
394 return 1;
395}
396
397int
399 if (host->length >= 3 && host->s[0] == '%' &&
400 host->s[1] == '2' &&
401 (host->s[2] == 'F' || host->s[2] == 'f')) {
402 return 1;
403 }
404 if (host->length >= 1 && host->s[0] == '/')
405 return 1;
406 return 0;
407}
408
416#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
417
430static void
431decode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
432
433 while (length--) {
434
435 if (*seg == '%') {
436 *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
437
438 seg += 2;
439 length -= 2;
440 } else {
441 *buf = *seg;
442 }
443
444 ++buf;
445 ++seg;
446 }
447}
448
454static int
455check_segment(const uint8_t *s, size_t length, size_t *segment_size) {
456 size_t n = 0;
457
458 while (length) {
459 if (*s == '%') {
460 if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
461 return -1;
462
463 s += 2;
464 length -= 2;
465 }
466
467 ++s;
468 ++n;
469 --length;
470 }
471
472 *segment_size = n;
473
474 return 0;
475}
476
497static int
498make_decoded_option(const uint8_t *s, size_t length,
499 unsigned char *buf, size_t buflen, size_t *optionsize) {
500 int res;
501 size_t segmentlen;
502 size_t written;
503
504 if (!buflen) {
505 coap_log_debug("make_decoded_option(): buflen is 0!\n");
506 return -1;
507 }
508
509 res = check_segment(s, length, &segmentlen);
510 if (res < 0)
511 return -1;
512
513 /* write option header using delta 0 and length res */
514 written = coap_opt_setheader(buf, buflen, 0, segmentlen);
515
516 assert(written <= buflen);
517
518 if (!written) /* encoding error */
519 return -1;
520
521 buf += written; /* advance past option type/length */
522 buflen -= written;
523
524 if (buflen < segmentlen) {
525 coap_log_debug("buffer too small for option\n");
526 return -1;
527 }
528
529 decode_segment(s, length, buf);
530
531 *optionsize = written + segmentlen;
532
533 return 0;
534}
535
536
537#ifndef min
538#define min(a,b) ((a) < (b) ? (a) : (b))
539#endif
540
541typedef void (*segment_handler_t)(const uint8_t *, size_t, void *);
542
548static int
549dots(const uint8_t *s, size_t len) {
550 uint8_t p;
551
552 if (!len)
553 return 0;
554
555 p = *s;
556
557 /* Check 'first' char */
558 if (p == '%' && len >=3) {
559 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
560 s += 2;
561 len -= 2;
562 }
563 p = '.';
564 }
565 if (p != '.')
566 return 0;
567 if (len == 1)
568 return 1;
569
570 /* Check 'second' char, first is '.' */
571 s++;
572 len--;
573 assert(len);
574 p = *s;
575 if (p == '%' && len >=3) {
576 if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) {
577 len -= 2;
578 }
579 p = '.';
580 }
581 if (p != '.')
582 return 0;
583 if (len == 1)
584 return 2;
585
586 return 0;
587}
588
594
595static void
596backup_segment(void *data) {
597 struct cnt_str *state = (struct cnt_str *)data;
598 int i;
599 uint8_t *buf;
600
601 if (state->n == 0)
602 return;
603
604 state->n--;
605 buf = state->base_buf.s;
606 for (i = 0; i < state->n; i++) {
608 }
609 state->buf.s = buf;
610 state->buf.length = state->base_buf.length - (buf - state->base_buf.s);
611}
612
624static size_t
625coap_split_path_impl(const uint8_t *path, size_t len,
626 segment_handler_t h, void *data) {
627 const uint8_t *p, *q;
628 size_t length = len;
629 int num_dots;
630
631 p = q = path;
632 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) {
633 if (*q == '/') {
634 /* start new segment */
635 num_dots = dots(p, q - p);
636 switch (num_dots) {
637 case 1:
638 /* drop segment */
639 break;
640 case 2:
641 /* backup segment */
642 backup_segment(data);
643 break;
644 case 0:
645 default:
646 /* add segment */
647 h(p, q - p, data);
648 break;
649 }
650
651 p = q + 1;
652 }
653
654 q++;
655 length--;
656 }
657
658 /* write last segment */
659 num_dots = dots(p, q - p);
660 switch (num_dots) {
661 case 1:
662 /* drop segment */
663 break;
664 case 2:
665 /* backup segment */
666 backup_segment(data);
667 break;
668 case 0:
669 default:
670 /* add segment */
671 h(p, q - p, data);
672 break;
673 }
674
675 return q - path;
676}
677
678static void
679write_option(const uint8_t *s, size_t len, void *data) {
680 struct cnt_str *state = (struct cnt_str *)data;
681 int res;
682 size_t optionsize;
683 assert(state);
684
685 res = make_decoded_option(s, len, state->buf.s, state->buf.length, &optionsize);
686 if (res == 0) {
687 state->buf.s += optionsize;
688 state->buf.length -= optionsize;
689 state->n++;
690 }
691}
692
693int
694coap_split_path(const uint8_t *s, size_t length,
695 unsigned char *buf, size_t *buflen) {
696 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
697
698 coap_split_path_impl(s, length, write_option, &tmp);
699
700 *buflen = *buflen - tmp.buf.length;
701
702 return tmp.n;
703}
704
705void
707 size_t i;
708 size_t o = 0;
709
710 for (i = 0; i < optlist->length; i++) {
711 if (optlist->data[i] == '%' && optlist->length - i >= 3) {
712 optlist->data[o] = (hexchar_to_dec(optlist->data[i+1]) << 4) +
713 hexchar_to_dec(optlist->data[i+2]);
714 i+= 2;
715 } else if (o != i) {
716 optlist->data[o] = optlist->data[i];
717 }
718 o++;
719 }
720 optlist->length = o;
721}
722
723static void
725 coap_optlist_t *last = NULL;
726 coap_optlist_t *cur = *optlist_begin;
727
728 if (!cur)
729 return;
730
731 while (cur) {
732 if (!cur->next)
733 break;
734 last = cur;
735 cur = cur->next;
736 }
738 if (last) {
739 last->next = NULL;
740 } else {
741 *optlist_begin = NULL;
742 }
743}
744
745int
746coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
747 coap_optlist_t **optlist_chain) {
748 const uint8_t *p = s;
749 coap_optlist_t *optlist;
750 int num_dots;
751 coap_optlist_t **optlist_start;
752
753 if (*optlist_chain) {
754 /* Something previously in optlist_chain. Need to make that the start */
755 optlist_start = &((*optlist_chain)->next);
756 } else {
757 optlist_start = optlist_chain;
758 }
759
760 while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *s)) {
761 if (*s == '/') { /* start of new path element */
762 /* start new segment */
763 num_dots = dots(p, s - p);
764 switch (num_dots) {
765 case 1:
766 /* drop segment */
767 break;
768 case 2:
769 /* backup segment */
770 backup_optlist(optlist_start);
771 break;
772 case 0:
773 default:
774 /* add segment */
775 optlist = coap_new_optlist(optnum, s - p, p);
776 coap_replace_percents(optlist);
777 if (!coap_insert_optlist(optlist_chain, optlist)) {
778 return 0;
779 }
780 break;
781 }
782 p = s + 1;
783 }
784 s++;
785 length--;
786
787 }
788 /* add last path element */
789 num_dots = dots(p, s - p);
790 switch (num_dots) {
791 case 1:
792 /* drop segment */
793 break;
794 case 2:
795 /* backup segment */
796 backup_optlist(optlist_start);
797 break;
798 case 0:
799 default:
800 /* add segment */
801 optlist = coap_new_optlist(optnum, s - p, p);
802 coap_replace_percents(optlist);
803 if (!coap_insert_optlist(optlist_chain, optlist)) {
804 return 0;
805 }
806 break;
807 }
808 return 1;
809}
810
811int
812coap_split_query(const uint8_t *s, size_t length,
813 unsigned char *buf, size_t *buflen) {
814 struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 };
815 const uint8_t *p;
816
817 p = s;
818 while (length > 0 && *s != '#') {
819 if (*s == '&') { /* start new query element */
820 write_option(p, s - p, &tmp);
821 p = s + 1;
822 }
823
824 s++;
825 length--;
826 }
827
828 /* write last query element */
829 write_option(p, s - p, &tmp);
830
831 *buflen = *buflen - tmp.buf.length;
832 return tmp.n;
833}
834
835int
836coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum,
837 coap_optlist_t **optlist_chain) {
838 const uint8_t *p = s;
839 coap_optlist_t *optlist;
840
841 while (length > 0 && *s != '#') {
842 if (*s == '&') { /* start of new query element */
843 /* add previous query element */
844 optlist = coap_new_optlist(optnum, s - p, p);
845 coap_replace_percents(optlist);
846 if (!coap_insert_optlist(optlist_chain, optlist)) {
847 return 0;
848 }
849 p = s + 1;
850 }
851 s++;
852 length--;
853 }
854 /* add last query element */
855 optlist = coap_new_optlist(optnum, s - p, p);
856 coap_replace_percents(optlist);
857 if (!coap_insert_optlist(optlist_chain, optlist)) {
858 return 0;
859 }
860 return 1;
861}
862
863#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
864
866coap_new_uri(const uint8_t *uri, unsigned int length) {
867 uint8_t *result;
868 coap_uri_t *out_uri;
869
870 out_uri = (coap_uri_t *)coap_malloc_type(COAP_STRING, length + 1 + sizeof(coap_uri_t));
871
872 if (!out_uri)
873 return NULL;
874
875 result = (uint8_t *)out_uri;
876 memcpy(URI_DATA(result), uri, length);
877 URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
878
879 if (coap_split_uri(URI_DATA(result), length, out_uri) < 0) {
880 coap_free_type(COAP_STRING, out_uri);
881 return NULL;
882 }
883 return out_uri;
884}
885
888 coap_uri_t *result;
889 uint8_t *p;
890
891 if (!uri)
892 return NULL;
893
895 uri->path.length + sizeof(coap_uri_t) + 1);
896
897 if (!result)
898 return NULL;
899
900 memset(result, 0, sizeof(coap_uri_t));
901
902 result->port = uri->port;
903
904 if (uri->host.length) {
905 result->host.s = p = URI_DATA(result);
906 result->host.length = uri->host.length;
907
908 memcpy(p, uri->host.s, uri->host.length);
909 }
910
911 if (uri->path.length) {
912 result->path.s = p = URI_DATA(result) + uri->host.length;
913 result->path.length = uri->path.length;
914
915 memcpy(p, uri->path.s, uri->path.length);
916 }
917
918 if (uri->query.length) {
919 result->query.s = p = URI_DATA(result) + uri->host.length + uri->path.length;
920 result->query.length = uri->query.length;
921
922 memcpy(p, uri->query.s, uri->query.length);
923 }
924
925 return result;
926}
927
928void
932
933static int
934is_unescaped_in_path(const uint8_t c) {
935 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
936 (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' ||
937 c == '~' || c == '!' || c == '$' || c == '\'' || c == '(' ||
938 c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
939 c=='=' || c==':' || c=='@' || c == '&';
940}
941
942static int
943is_unescaped_in_query(const uint8_t c) {
944 return is_unescaped_in_path(c) || c=='/' || c=='?';
945}
946
948coap_get_query(const coap_pdu_t *request) {
949 coap_opt_iterator_t opt_iter;
951 coap_opt_t *q;
952 coap_string_t *query = NULL;
953 size_t length = 0;
954 static const uint8_t hex[] = "0123456789ABCDEF";
955
958 coap_option_iterator_init(request, &opt_iter, &f);
959 while ((q = coap_option_next(&opt_iter))) {
960 uint16_t seg_len = coap_opt_length(q), i;
961 const uint8_t *seg= coap_opt_value(q);
962 for (i = 0; i < seg_len; i++) {
963 if (is_unescaped_in_query(seg[i]))
964 length += 1;
965 else
966 length += 3;
967 }
968 length += 1;
969 }
970 if (length > 0)
971 length -= 1;
972 if (length > 0) {
973 query = coap_new_string(length);
974 if (query) {
975 query->length = length;
976 unsigned char *s = query->s;
977 coap_option_iterator_init(request, &opt_iter, &f);
978 while ((q = coap_option_next(&opt_iter))) {
979 if (s != query->s)
980 *s++ = '&';
981 uint16_t seg_len = coap_opt_length(q), i;
982 const uint8_t *seg= coap_opt_value(q);
983 for (i = 0; i < seg_len; i++) {
984 if (is_unescaped_in_query(seg[i])) {
985 *s++ = seg[i];
986 } else {
987 *s++ = '%';
988 *s++ = hex[seg[i]>>4];
989 *s++ = hex[seg[i]&0x0F];
990 }
991 }
992 }
993 }
994 }
995 return query;
996}
997
1000 coap_opt_iterator_t opt_iter;
1002 coap_opt_t *q;
1003 coap_string_t *uri_path = NULL;
1004 size_t length = 0;
1005 static const uint8_t hex[] = "0123456789ABCDEF";
1006
1007 q = coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter);
1008 if (q) {
1009 coap_uri_t uri;
1010
1012 coap_opt_length(q), &uri) < 0) {
1013 return NULL;
1014 }
1015 uri_path = coap_new_string(uri.path.length);
1016 if (uri_path) {
1017 memcpy(uri_path->s, uri.path.s, uri.path.length);
1018 }
1019 return uri_path;
1020 }
1021
1024 coap_option_iterator_init(request, &opt_iter, &f);
1025 while ((q = coap_option_next(&opt_iter))) {
1026 uint16_t seg_len = coap_opt_length(q), i;
1027 const uint8_t *seg= coap_opt_value(q);
1028 for (i = 0; i < seg_len; i++) {
1029 if (is_unescaped_in_path(seg[i]))
1030 length += 1;
1031 else
1032 length += 3;
1033 }
1034 /* bump for the leading "/" */
1035 length += 1;
1036 }
1037 /* The first entry does not have a leading "/" */
1038 if (length > 0)
1039 length -= 1;
1040
1041 /* if 0, either no URI_PATH Option, or the first one was empty */
1042 uri_path = coap_new_string(length);
1043 if (uri_path) {
1044 uri_path->length = length;
1045 unsigned char *s = uri_path->s;
1046 int n = 0;
1047 coap_option_iterator_init(request, &opt_iter, &f);
1048 while ((q = coap_option_next(&opt_iter))) {
1049 if (n++) {
1050 *s++ = '/';
1051 }
1052 uint16_t seg_len = coap_opt_length(q), i;
1053 const uint8_t *seg= coap_opt_value(q);
1054 for (i = 0; i < seg_len; i++) {
1055 if (is_unescaped_in_path(seg[i])) {
1056 *s++ = seg[i];
1057 } else {
1058 *s++ = '%';
1059 *s++ = hex[seg[i]>>4];
1060 *s++ = hex[seg[i]&0x0F];
1061 }
1062 }
1063 }
1064 }
1065 return uri_path;
1066}
#define INET6_ADDRSTRLEN
Definition coap_debug.c:226
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:295
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:549
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:306
static void backup_optlist(coap_optlist_t **optlist_begin)
Definition coap_uri.c:724
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:431
static int is_unescaped_in_query(const uint8_t c)
Definition coap_uri.c:943
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:455
static void write_option(const uint8_t *s, size_t len, void *data)
Definition coap_uri.c:679
static void backup_segment(void *data)
Definition coap_uri.c:596
void coap_delete_uri(coap_uri_t *uri)
Removes the specified coap_uri_t object.
Definition coap_uri.c:929
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:625
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:416
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:498
static int is_unescaped_in_path(const uint8_t c)
Definition coap_uri.c:934
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:887
#define URI_DATA(uriobj)
Definition coap_uri.c:863
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:866
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:398
void(* segment_handler_t)(const uint8_t *, size_t, void *)
Definition coap_uri.c:541
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:409
#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:999
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:694
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:836
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:285
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:746
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:290
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:313
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:812
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:948
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:706
#define COAP_UNUSED
Definition libcoap.h:70
#define COAP_STATIC_INLINE
Definition libcoap.h:53
int n
Definition coap_uri.c:592
coap_string_t base_buf
Definition coap_uri.c:590
coap_string_t buf
Definition coap_uri.c:591
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
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