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