1 /* libcoap unit tests
2 *
3 * Copyright (C) 2012,2015 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
11 #include "test_common.h"
12 #include "test_uri.h"
13
14 #include <stdio.h>
15
16 static void
t_parse_uri1(void)17 t_parse_uri1(void) {
18 char teststr[] = "coap://[::1]/.well-known/core";
19
20 int result;
21 coap_uri_t uri;
22
23 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
24 if (result == 0) {
25 CU_ASSERT(uri.host.length == 3);
26 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "::1", 3);
27
28 CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
29
30 CU_ASSERT(uri.path.length == 16);
31 CU_ASSERT_NSTRING_EQUAL(uri.path.s, ".well-known/core", 16);
32
33 CU_ASSERT(uri.query.length == 0);
34 CU_ASSERT(uri.query.s == NULL);
35 } else {
36 CU_FAIL("uri parser error");
37 }
38 }
39
40 static void
t_parse_uri2(void)41 t_parse_uri2(void) {
42 char teststr[] = "coap://[::1]:8000/.well-known/core";
43 int result;
44 coap_uri_t uri;
45
46 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
47 if (result == 0) {
48 CU_ASSERT(uri.host.length == 3);
49 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "::1", 3);
50
51 CU_ASSERT(uri.port == 8000);
52
53 CU_ASSERT(uri.path.length == 16);
54 CU_ASSERT_NSTRING_EQUAL(uri.path.s, ".well-known/core", 16);
55
56 CU_ASSERT(uri.query.length == 0);
57 CU_ASSERT(uri.query.s == NULL);
58 } else {
59 CU_FAIL("uri parser error");
60 }
61 }
62
63 static void
t_parse_uri3(void)64 t_parse_uri3(void) {
65 char teststr[] = "coap://localhost/?foo&bla=fasel";
66 int result;
67 coap_uri_t uri;
68
69 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
70 if (result == 0) {
71 CU_ASSERT(uri.host.length == 9);
72 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "localhost", 9);
73
74 CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
75
76 CU_ASSERT(uri.path.length == 0);
77
78 CU_ASSERT(uri.query.length == 13);
79 CU_ASSERT_NSTRING_EQUAL(uri.query.s, "foo&bla=fasel", 13);
80 } else {
81 CU_FAIL("uri parser error");
82 }
83 }
84
85 static void
t_parse_uri4(void)86 t_parse_uri4(void) {
87 char teststr[] = "coap://:100000";
88 int result;
89 coap_uri_t uri;
90
91 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
92 CU_ASSERT(result < 0);
93 }
94
95 static void
t_parse_uri5(void)96 t_parse_uri5(void) {
97 char teststr[] = "coap://foo:100000";
98 int result;
99 coap_uri_t uri;
100
101 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
102 if (result == 0) {
103 CU_ASSERT(uri.host.length == 3);
104 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "foo", 3);
105
106 CU_ASSERT(uri.path.length == 0);
107 CU_ASSERT(uri.path.s == NULL);
108
109 CU_ASSERT(uri.query.length == 0);
110 CU_ASSERT(uri.query.s == NULL);
111
112 CU_FAIL("invalid port not detected");
113 } else {
114 CU_PASS("detected invalid port");
115 }
116 }
117
118 static void
t_parse_uri6(void)119 t_parse_uri6(void) {
120 char teststr[] = "coap://134.102.218.2/.well-known/core";
121 int result;
122 coap_uri_t uri;
123
124 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
125 if (result == 0) {
126 CU_ASSERT(uri.host.length == 13);
127 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "134.102.218.2", 13);
128
129 CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
130
131 CU_ASSERT(uri.path.length == 16);
132 CU_ASSERT_NSTRING_EQUAL(uri.path.s, ".well-known/core", 16);
133
134 CU_ASSERT(uri.query.length == 0);
135 CU_ASSERT(uri.query.s == NULL);
136 } else {
137 CU_FAIL("uri parser error");
138 }
139 }
140
141 static void
t_parse_uri7(void)142 t_parse_uri7(void) {
143 char teststr[] = "coap://foo.bar:5683/some_resource/with/multiple/segments";
144 int result;
145 coap_uri_t uri;
146 unsigned char buf[40];
147 size_t buflen = sizeof(buf);
148
149 /* The list of path segments to check against. Each segment is
150 preceded by a dummy option indicating that holds the (dummy)
151 delta value 0 and the actual segment length. */
152 const uint8_t checkbuf[] = {
153 0x0d, 0x00, 's', 'o', 'm', 'e', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e',
154 0x04, 'w', 'i', 't', 'h',
155 0x08, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e',
156 0x08, 's', 'e', 'g', 'm', 'e', 'n', 't', 's'
157 };
158
159 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
160 if (result == 0) {
161 CU_ASSERT(uri.host.length == 7);
162 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "foo.bar", 7);
163
164 CU_ASSERT(uri.port == 5683);
165
166 CU_ASSERT(uri.path.length == 36);
167 CU_ASSERT_NSTRING_EQUAL(uri.path.s, "some_resource/with/multiple/segments", 36);
168
169 CU_ASSERT(uri.query.length == 0);
170 CU_ASSERT(uri.query.s == NULL);
171
172 /* check path segments */
173 result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
174 CU_ASSERT(result == 4);
175 CU_ASSERT(buflen == sizeof(checkbuf));
176 CU_ASSERT_NSTRING_EQUAL(buf, checkbuf, buflen);
177 } else {
178 CU_FAIL("uri parser error");
179 }
180 }
181
182 static void
t_parse_uri8(void)183 t_parse_uri8(void) {
184 char teststr[] = "http://example.com/%7E%AB%13";
185 int result;
186 coap_uri_t uri;
187
188 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
189 if (result < 0) {
190 CU_PASS("detected non-coap URI");
191 } else {
192 CU_FAIL("non-coap URI not recognized");
193 }
194 }
195
196 static void
t_parse_uri9(void)197 t_parse_uri9(void) {
198 char teststr[] = "http://example.com/%x";
199 int result;
200 coap_uri_t uri;
201
202 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
203 if (result < 0) {
204 CU_PASS("detected non-coap URI");
205 } else {
206 CU_FAIL("non-coap URI not recognized");
207 }
208 }
209
210 static void
t_parse_uri10(void)211 t_parse_uri10(void) {
212 char teststr[] = "/absolute/path";
213 int result;
214 coap_uri_t uri;
215
216 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
217 if (result == 0) {
218 CU_ASSERT(uri.host.length == 0);
219 CU_ASSERT(uri.host.s == NULL);
220
221 CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
222
223 CU_ASSERT(uri.path.length == 13);
224 CU_ASSERT_NSTRING_EQUAL(uri.path.s, "absolute/path", 13);
225
226 CU_ASSERT(uri.query.length == 0);
227 CU_ASSERT(uri.query.s == NULL);
228 } else {
229 CU_FAIL("uri parser error");
230 }
231 }
232
233 static void
t_parse_uri11(void)234 t_parse_uri11(void) {
235 char teststr[] =
236 "coap://xn--18j4d.example/%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF";
237 int result;
238 coap_uri_t uri;
239 unsigned char buf[40];
240 size_t buflen = sizeof(buf);
241
242 /* The list of path segments to check against. Each segment is
243 preceded by a dummy option indicating that holds the (dummy)
244 delta value 0 and the actual segment length. */
245 const uint8_t checkbuf[] = {
246 0x0d, 0x02, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93,
247 0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xA1, 0xE3, 0x81,
248 0xAF
249 };
250
251 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
252 if (result == 0) {
253 CU_ASSERT(uri.host.length == 17);
254 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "xn--18j4d.example", 17);
255
256 CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
257
258 CU_ASSERT(uri.path.length == 45);
259 CU_ASSERT_NSTRING_EQUAL(uri.path.s,
260 "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF", 45);
261
262 CU_ASSERT(uri.query.length == 0);
263 CU_ASSERT(uri.query.s == NULL);
264
265 /* check path segments */
266 result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
267 CU_ASSERT(result == 1);
268 CU_ASSERT(buflen == sizeof(checkbuf));
269 CU_ASSERT_NSTRING_EQUAL(buf, checkbuf, buflen);
270 } else {
271 CU_FAIL("uri parser error");
272 }
273 }
274
275 static void
t_parse_uri12(void)276 t_parse_uri12(void) {
277 char teststr[] = "coap://198.51.100.1:61616//%2F//?%2F%2F&?%26";
278 int result;
279 coap_uri_t uri;
280 unsigned char buf[40];
281 size_t buflen = sizeof(buf);
282
283 /* The list of path segments to check against. Each segment is
284 preceded by a dummy option indicating that holds the (dummy)
285 delta value 0 and the actual segment length. */
286 const uint8_t uricheckbuf[] = { 0x00, 0x01, 0x2f, 0x00, 0x00 };
287 const uint8_t querycheckbuf[] = { 0x02, 0x2f, 0x2f, 0x02, 0x3f, 0x26 };
288
289 result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
290 if (result == 0) {
291 CU_ASSERT(uri.host.length == 12);
292 CU_ASSERT_NSTRING_EQUAL(uri.host.s, "198.51.100.1", 12);
293
294 CU_ASSERT(uri.port == 61616);
295
296 CU_ASSERT(uri.path.length == 6);
297 CU_ASSERT_NSTRING_EQUAL(uri.path.s, "/%2F//", 6);
298
299 CU_ASSERT(uri.query.length == 11);
300 CU_ASSERT_NSTRING_EQUAL(uri.query.s, "%2F%2F&?%26", 11);
301
302 /* check path segments */
303 result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
304 CU_ASSERT(result == 4);
305 CU_ASSERT(buflen == sizeof(uricheckbuf));
306 CU_ASSERT_NSTRING_EQUAL(buf, uricheckbuf, buflen);
307
308 /* check query segments */
309 buflen = sizeof(buf);
310 result = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
311 CU_ASSERT(result == 2);
312 CU_ASSERT(buflen == sizeof(querycheckbuf));
313 CU_ASSERT_NSTRING_EQUAL(buf, querycheckbuf, buflen);
314 } else {
315 CU_FAIL("uri parser error");
316 }
317 }
318
319 #ifdef _MSC_VER
320 # define ALIGNED(x)
321 #else
322 # define ALIGNED(x) __attribute__ ((aligned (x)))
323 #endif
324
325 static void
t_parse_uri13(void)326 t_parse_uri13(void) {
327 uint8_t teststr[] ALIGNED(8) = {
328 0x80, 0x03, 'f', 'o',
329 'o', 0x3b, '.', 'w', 'e', 'l', 'l', '-',
330 'k', 'n', 'o', 'w', 'n', 0x04, 'c', 'o',
331 'r', 'e'
332 };
333
334 coap_pdu_t pdu = {
335 .max_size = sizeof(teststr),
336 .token_length = 0,
337 .token = teststr,
338 .used_size = sizeof(teststr)
339 };
340
341 coap_string_t *uri_path = coap_get_uri_path(&pdu);
342
343 CU_ASSERT(uri_path->length == sizeof(COAP_DEFAULT_URI_WELLKNOWN)-1);
344 CU_ASSERT_NSTRING_EQUAL(uri_path->s, COAP_DEFAULT_URI_WELLKNOWN,
345 sizeof(COAP_DEFAULT_URI_WELLKNOWN)-1);
346 coap_delete_string (uri_path);
347 }
348
349 static void
t_parse_uri14(void)350 t_parse_uri14(void) {
351 char teststr[] =
352 "longerthan13lessthan270=0123456789012345678901234567890123456789";
353 int result;
354
355 /* buf is large enough to hold sizeof(teststr) - 1 bytes content and
356 * 2 bytes for the option header. */
357 unsigned char buf[sizeof(teststr) + 1];
358 size_t buflen = sizeof(buf);
359
360 result = coap_split_query((unsigned char *)teststr, strlen(teststr),
361 buf, &buflen);
362 if (result >= 0) {
363 CU_ASSERT(buf[0] == 0x0d);
364 CU_ASSERT(buf[1] == strlen(teststr) - 13);
365
366 CU_ASSERT_NSTRING_EQUAL(buf+2, teststr, strlen(teststr));
367 } else {
368 CU_FAIL("uri parser error");
369 }
370 }
371
372 static void
t_parse_uri15(void)373 t_parse_uri15(void) {
374 char teststr[] =
375 "longerthan13lessthan270=0123456789012345678901234567890123456789";
376 int result;
377
378 /* buf is too small to hold sizeof(teststr) - 1 bytes content and 2
379 * bytes for the option header. */
380 unsigned char buf[sizeof(teststr) - 1];
381 size_t buflen = sizeof(buf);
382
383 result = coap_split_query((unsigned char *)teststr, strlen(teststr),
384 buf, &buflen);
385 CU_ASSERT(result == 0);
386 }
387
388 static void
t_parse_uri16(void)389 t_parse_uri16(void) {
390 char teststr[] =
391 "longerthan13lessthan270=0123456789012345678901234567890123456789";
392 int result;
393
394 /* buf is too small to hold the option header. */
395 unsigned char buf[1];
396 size_t buflen = sizeof(buf);
397
398 result = coap_split_query((unsigned char *)teststr, strlen(teststr),
399 buf, &buflen);
400 CU_ASSERT(result == 0);
401 }
402
403 static void
t_parse_uri17(void)404 t_parse_uri17(void) {
405 char teststr[] =
406 "thisislongerthan269="
407 "01234567890123456789012345678901234567890123456789"
408 "01234567890123456789012345678901234567890123456789"
409 "01234567890123456789012345678901234567890123456789"
410 "01234567890123456789012345678901234567890123456789"
411 "01234567890123456789012345678901234567890123456789";
412 int result;
413
414 /* buf is large enough to hold sizeof(teststr) - 1 bytes content and
415 * 3 bytes for the option header. */
416 unsigned char buf[sizeof(teststr) + 2];
417 size_t buflen = sizeof(buf);
418
419 result = coap_split_query((unsigned char *)teststr, strlen(teststr),
420 buf, &buflen);
421 if (result >= 0) {
422 CU_ASSERT(buf[0] == 0x0e);
423 CU_ASSERT(buf[1] == (((strlen(teststr) - 269) >> 8) & 0xff));
424 CU_ASSERT(buf[2] == ((strlen(teststr) - 269) & 0xff));
425
426 CU_ASSERT_NSTRING_EQUAL(buf+3, teststr, strlen(teststr));
427 } else {
428 CU_FAIL("uri parser error");
429 }
430 }
431
432 static void
t_parse_uri18(void)433 t_parse_uri18(void) {
434 uint8_t token[1] = "";
435 coap_pdu_t pdu = {
436 .max_size = 0,
437 .token_length = 0,
438 .token = token,
439 .used_size = 0
440 };
441
442 coap_string_t *uri_path = coap_get_uri_path(&pdu);
443
444 CU_ASSERT(uri_path->length == 0);
445 #if 0
446 /* Currently this is not the case - Issue #167 */
447 /* strings are stored with terminating zero */
448 CU_ASSERT_NSTRING_EQUAL(uri_path->s, "", 1);
449 #endif
450 coap_delete_string (uri_path);
451 }
452
453 static void
t_parse_uri19(void)454 t_parse_uri19(void) {
455 uint8_t teststr[] ALIGNED(8) = {
456 0xb3, 'f', 'o', 'o',
457 0x00 /* "foo/" as Uri-Path options */
458 };
459
460 coap_pdu_t pdu = {
461 .max_size = sizeof(teststr),
462 .token_length = 0,
463 .token = teststr,
464 .used_size = sizeof(teststr)
465 };
466
467 coap_string_t *uri_path = coap_get_uri_path(&pdu);
468
469 CU_ASSERT(uri_path->length == 4);
470 CU_ASSERT_NSTRING_EQUAL(uri_path->s, "foo/", 4);
471 coap_delete_string (uri_path);
472 }
473
474 static void
t_parse_uri20(void)475 t_parse_uri20(void) {
476 uint8_t teststr[] ALIGNED(8) = {
477 0xb0, 0x00 /* "//" as Uri-Path options */
478 };
479
480 coap_pdu_t pdu = {
481 .max_size = sizeof(teststr),
482 .token_length = 0,
483 .token = teststr,
484 .used_size = sizeof(teststr)
485 };
486
487 coap_string_t *uri_path = coap_get_uri_path(&pdu);
488
489 /* The leading '/' is stripped hence only one '/' remains. */
490 CU_ASSERT(uri_path->length == 1);
491 CU_ASSERT_NSTRING_EQUAL(uri_path->s, "/", 1);
492 coap_delete_string (uri_path);
493 }
494
495 static void
t_parse_uri21(void)496 t_parse_uri21(void) {
497 uint8_t teststr[] ALIGNED(8) = {
498 0xb0, 0x03, 'f', 'o', 'o' /* "//foo" as Uri-Path options */
499 };
500
501 coap_pdu_t pdu = {
502 .max_size = sizeof(teststr),
503 .token_length = 0,
504 .token = teststr,
505 .used_size = sizeof(teststr)
506 };
507
508 coap_string_t *uri_path = coap_get_uri_path(&pdu);
509
510 /* The leading '/' is stripped hence only one '/' remains. */
511 CU_ASSERT(uri_path->length == 4);
512 CU_ASSERT_NSTRING_EQUAL(uri_path->s, "/foo", 4);
513 coap_delete_string (uri_path);
514 }
515
516 static void
t_parse_uri22(void)517 t_parse_uri22(void) {
518 uint8_t teststr[] ALIGNED(8) = {
519 /* characters that are not percent-encoded in a path segment */
520 0xba, '-', '.', '_', '~', '!', '$', '&', '\'', '(', ')',
521 0x05, '*', '+', ',', ';', '='
522 };
523
524 coap_pdu_t pdu = {
525 .max_size = sizeof(teststr),
526 .token_length = 0,
527 .token = teststr,
528 .used_size = sizeof(teststr)
529 };
530
531 coap_string_t *uri_path = coap_get_uri_path(&pdu);
532
533 CU_ASSERT(uri_path->length == 16);
534 CU_ASSERT_NSTRING_EQUAL(uri_path->s, "-._~!$&'()/*+,;=", 16);
535 coap_delete_string (uri_path);
536 }
537
538 static void
t_parse_uri23(void)539 t_parse_uri23(void) {
540 uint8_t teststr[] ALIGNED(8) = {
541 /* characters that must be percent-encoded in a path segment */
542 0xb5, '%', ' ', '#', '[', ']'
543 };
544
545 coap_pdu_t pdu = {
546 .max_size = sizeof(teststr),
547 .token_length = 0,
548 .token = teststr,
549 .used_size = sizeof(teststr)
550 };
551
552 coap_string_t *uri_path = coap_get_uri_path(&pdu);
553
554 CU_ASSERT(uri_path->length == 15);
555 CU_ASSERT_NSTRING_EQUAL(uri_path->s, "%25%20%23%5B%5D", 15);
556 coap_delete_string (uri_path);
557 }
558
559 /*
560 * To test Issue #212 which reads off the end of the input buffer when looking
561 * for . or .. in the path.
562 * Credit to OSS-Fuzz for finding this, work done by Bhargava Shastry
563 */
564 static void
t_parse_uri24(void)565 t_parse_uri24(void) {
566 /* coap://\206cap:// */
567 uint8_t teststr[] = { 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x86, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f };
568 int result;
569 unsigned char buf[40];
570 size_t buflen = sizeof(buf);
571
572 result = coap_split_path(teststr, sizeof(teststr), buf, &buflen);
573 CU_ASSERT(result == 5);
574 CU_ASSERT(buflen == 16);
575 }
576
577
578 CU_pSuite
t_init_uri_tests(void)579 t_init_uri_tests(void) {
580 CU_pSuite suite;
581
582 suite = CU_add_suite("uri parser", NULL, NULL);
583 if (!suite) { /* signal error */
584 fprintf(stderr, "W: cannot add uri parser test suite (%s)\n",
585 CU_get_error_msg());
586
587 return NULL;
588 }
589
590 #define URI_TEST(s,t) \
591 if (!CU_ADD_TEST(s,t)) { \
592 fprintf(stderr, "W: cannot add uri parser test (%s)\n", \
593 CU_get_error_msg()); \
594 }
595
596 URI_TEST(suite, t_parse_uri1);
597 URI_TEST(suite, t_parse_uri2);
598 URI_TEST(suite, t_parse_uri3);
599 URI_TEST(suite, t_parse_uri4);
600 URI_TEST(suite, t_parse_uri5);
601 URI_TEST(suite, t_parse_uri6);
602 URI_TEST(suite, t_parse_uri7);
603 URI_TEST(suite, t_parse_uri8);
604 URI_TEST(suite, t_parse_uri9);
605 URI_TEST(suite, t_parse_uri10);
606 URI_TEST(suite, t_parse_uri11);
607 URI_TEST(suite, t_parse_uri12);
608 URI_TEST(suite, t_parse_uri13);
609 URI_TEST(suite, t_parse_uri14);
610 URI_TEST(suite, t_parse_uri15);
611 URI_TEST(suite, t_parse_uri16);
612 URI_TEST(suite, t_parse_uri17);
613 URI_TEST(suite, t_parse_uri18);
614 URI_TEST(suite, t_parse_uri19);
615 URI_TEST(suite, t_parse_uri20);
616 URI_TEST(suite, t_parse_uri21);
617 URI_TEST(suite, t_parse_uri22);
618 URI_TEST(suite, t_parse_uri23);
619 URI_TEST(suite, t_parse_uri24);
620
621 return suite;
622 }
623
624