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