• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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