LCOV - code coverage report
Current view: top level - lib/util/tests - rfc1738.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 84 92 91.3 %
Date: 2024-04-21 15:09:00 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include <stdarg.h>
       2             : #include <stddef.h>
       3             : #include <setjmp.h>
       4             : #include <stdint.h>
       5             : #include <cmocka.h>
       6             : #include "lib/replace/replace.h"
       7             : 
       8             : #include <errno.h>
       9             : #include <unistd.h>
      10             : #include <talloc.h>
      11             : #include <ctype.h>
      12             : #include <string.h>
      13             : #include "lib/util/samba_util.h"
      14             : 
      15             : /* These flags say what can be asserted about a relationship between a string
      16             :    and its supposedly escaped equivalent.
      17             : 
      18             :    The first part of the flag name indicates the direction of transformation;
      19             :    the second part is the expected result. For example, ESCAPE_EQ means the
      20             :    escape is expected to succeed and result is expected to be equal to the
      21             :    given answer. ESCAPE_EQ_CASECMP is only equal when compared
      22             :    case-insensitively. UNESCAPE_ERR means unescaping the escaped string should
      23             :    result in an error.
      24             : */
      25             : #define UNESCAPE_ERR 1
      26             : #define ESCAPE_ERR 2
      27             : #define ESCAPE_EQ 4
      28             : #define UNESCAPE_EQ 8
      29             : #define ESCAPE_NE 16
      30             : #define UNESCAPE_NE 32
      31             : #define ESCAPE_EQ_CASECMP 64
      32             : 
      33             : struct rfc1738_test {
      34             :         const char *escaped;   /* original for unescape; result for escape  */
      35             :         const char *unescaped; /* result in unescape; original for escape */
      36             :         uint32_t flags;   /* see above */
      37             :         int unesc_len;    /* end - start will be this */
      38             :         int unesc_strlen; /* strlen() will say this */
      39             :         int esc_len;      /* escaped string length */
      40             : };
      41             : 
      42             : /* unreserved = ALPHA DIGIT - . _ ~       */
      43             : 
      44             : char spectrum[255 + 1];
      45             : char spectrum_escaped[255 * 3 + 1];
      46             : 
      47             : struct rfc1738_test examples[] = {
      48             : 
      49             : #define SIMPLE1 "this_is_a_simple-string._With_no_escapes~" /* maps to self */
      50             :         {
      51             :                 SIMPLE1,
      52             :                 SIMPLE1,
      53             :                 ESCAPE_EQ | UNESCAPE_EQ, /* round trip should work */
      54             :                 sizeof(SIMPLE1) - 1,
      55             :                 sizeof(SIMPLE1) - 1,
      56             :                 sizeof(SIMPLE1) - 1,
      57             :         },
      58             : #define SIMPLE2 "no escapes, but\n non-printables \xc5\x8d\x99"
      59             : #define SIMPLE2_ESC "no%20escapes%2C%20but%0A%20non-printables%20%C5%8D%99"
      60             :         {
      61             :                 SIMPLE2_ESC,
      62             :                 SIMPLE2,
      63             :                 ESCAPE_EQ | UNESCAPE_EQ,
      64             :                 sizeof(SIMPLE2) - 1,
      65             :                 sizeof(SIMPLE2) - 1,
      66             :                 sizeof(SIMPLE2_ESC) - 1,
      67             :         },
      68             : #define SIMPLE3 "this @#$^&*()_+{}:;"
      69             : #define SIMPLE3_ESC "this%20%40%23%24%5E%26%2A%28%29_%2B%7B%7D%3A%3B"
      70             :         {
      71             :                 SIMPLE3_ESC,
      72             :                 SIMPLE3,
      73             :                 ESCAPE_EQ | UNESCAPE_EQ,
      74             :                 sizeof(SIMPLE3) - 1,
      75             :                 sizeof(SIMPLE3) - 1,
      76             :                 sizeof(SIMPLE3_ESC) - 1,
      77             :         },
      78             : 
      79             : #define ESCAPE1 "%/\x06this string has expected escapes"
      80             : #define ESCAPE1_ESC "%25%2F%06this%20string%20has%20expected%20escapes"
      81             : #define ESCAPE1_ESC_ESC "%2525%252F%2506this%2520string%2520has%2520expected"\
      82             :         "%2520escapes"
      83             :         {
      84             :                 ESCAPE1_ESC,
      85             :                 ESCAPE1,
      86             :                 ESCAPE_EQ | UNESCAPE_EQ,
      87             :                 sizeof(ESCAPE1) - 1,
      88             :                 sizeof(ESCAPE1) - 1,
      89             :                 sizeof(ESCAPE1_ESC) - 1,
      90             :         },
      91             :         {
      92             :                 ESCAPE1_ESC_ESC, /*re-escaping */
      93             :                 ESCAPE1_ESC,
      94             :                 ESCAPE_EQ | UNESCAPE_EQ,
      95             :                 sizeof(ESCAPE1_ESC) - 1,
      96             :                 sizeof(ESCAPE1_ESC) - 1,
      97             :                 sizeof(ESCAPE1_ESC_ESC) - 1,
      98             :         },
      99             : #define ESCAPE2 "%25%2f%06-this-string-has-expected-lowercase-escapes-%ab"
     100             : #define ESCAPE2_UNESC "%/\x06-this-string-has-expected-lowercase-escapes-\xab"
     101             :         {
     102             :                 ESCAPE2,
     103             :                 ESCAPE2_UNESC,
     104             :                 ESCAPE_EQ_CASECMP | UNESCAPE_EQ, /* escape won't match case */
     105             :                 sizeof(ESCAPE2_UNESC) - 1,
     106             :                 sizeof(ESCAPE2_UNESC) - 1,
     107             :                 sizeof(ESCAPE2) - 1,
     108             :         },
     109             : #define ESCAPE3 "%25%2f%06 %32 %44 %6a%AA THIS string h%61s random escapes %ab"
     110             : #define ESCAPE3_UNESC "%/\x06 2 D j\xAA THIS string has random escapes \xab"
     111             :         {
     112             :                 ESCAPE3,
     113             :                 ESCAPE3_UNESC,
     114             :                 ESCAPE_NE | UNESCAPE_EQ, /* escape will have escaped spaces */
     115             :                 sizeof(ESCAPE3_UNESC) - 1,
     116             :                 sizeof(ESCAPE3_UNESC) - 1,
     117             :                 sizeof(ESCAPE3) - 1,
     118             :         },
     119             : #define ESCAPE4 "%25%25%25" /*  */
     120             : #define ESCAPE4_UNESC "%%%" /*  */
     121             : #define ESCAPE4_ESC "%2525%2525%2525"
     122             :         {
     123             :                 ESCAPE4,
     124             :                 ESCAPE4_UNESC,
     125             :                 ESCAPE_EQ | UNESCAPE_EQ,
     126             :                 sizeof(ESCAPE4_UNESC) - 1,
     127             :                 sizeof(ESCAPE4_UNESC) - 1,
     128             :                 sizeof(ESCAPE4) - 1,
     129             :         },
     130             :         {
     131             :                 ESCAPE4_ESC,
     132             :                 ESCAPE4,
     133             :                 ESCAPE_EQ | UNESCAPE_EQ,
     134             :                 sizeof(ESCAPE4) - 1,
     135             :                 sizeof(ESCAPE4) - 1,
     136             :                 sizeof(ESCAPE4_ESC) - 1,
     137             :         },
     138             : #define BAD1 "trailing percent is bad %"
     139             : #define BAD1_ESC "trailing%20percent%20is%20bad%20%25"
     140             :         {
     141             :                 BAD1_ESC,
     142             :                 BAD1,
     143             :                 UNESCAPE_EQ |ESCAPE_EQ,
     144             :                 sizeof(BAD1) - 1,
     145             :                 sizeof(BAD1) - 1,
     146             :                 sizeof(BAD1_ESC) - 1,
     147             :         },
     148             :         {
     149             :                 BAD1,
     150             :                 NULL,
     151             :                 UNESCAPE_ERR,
     152             :                 0,
     153             :                 0,
     154             :                 sizeof(BAD1) - 1,
     155             :         },
     156             : #define BAD2 "trailing percent is bad %1"
     157             : #define BAD3 "bad characters %1 "
     158             :         {
     159             :                 BAD2,
     160             :                 NULL,
     161             :                 UNESCAPE_ERR,
     162             :                 0,
     163             :                 0,
     164             :                 sizeof(BAD2) - 1,
     165             :         },
     166             :         {
     167             :                 BAD3,
     168             :                 NULL,
     169             :                 UNESCAPE_ERR,
     170             :                 0,
     171             :                 0,
     172             :                 sizeof(BAD3) - 1,
     173             :         },
     174             : #define BAD4 "bad characters %1 "
     175             :         {
     176             :                 BAD4,
     177             :                 NULL,
     178             :                 UNESCAPE_ERR,
     179             :                 0,
     180             :                 0,
     181             :                 sizeof(BAD4) - 1,
     182             :         },
     183             : #define BAD5 "bad characters %1- "
     184             :         {
     185             :                 BAD5,
     186             :                 NULL,
     187             :                 UNESCAPE_ERR,
     188             :                 0,
     189             :                 0,
     190             :                 sizeof(BAD5) - 1,
     191             :         },
     192             : #define BAD6 "bad characters %1G "
     193             :         {
     194             :                 BAD6,
     195             :                 NULL,
     196             :                 UNESCAPE_ERR,
     197             :                 0,
     198             :                 0,
     199             :                 sizeof(BAD6) - 1,
     200             :         },
     201             : #define BAD7 "bad characters %%1 "
     202             :         {
     203             :                 BAD7,
     204             :                 NULL,
     205             :                 UNESCAPE_ERR,
     206             :                 0,
     207             :                 0,
     208             :                 sizeof(BAD7) - 1,
     209             :         },
     210             : #define BAD8 "bad characters %sb "
     211             :         {
     212             :                 BAD8,
     213             :                 NULL,
     214             :                 UNESCAPE_ERR,
     215             :                 0,
     216             :                 0,
     217             :                 sizeof(BAD8) - 1,
     218             :         },
     219             : #define BAD_SSCANF "sscanf would be happy with this\n"
     220             : #define BAD_SSCANF_ESC "sscanf would be happy with this% a"
     221             :         {
     222             :                 BAD_SSCANF_ESC,
     223             :                 BAD_SSCANF,
     224             :                 ESCAPE_NE | UNESCAPE_ERR,
     225             :                 sizeof(BAD_SSCANF) - 1,
     226             :                 sizeof(BAD_SSCANF) - 1,
     227             :                 sizeof(BAD_SSCANF_ESC) - 1,
     228             :         },
     229             :         /* now try some with zeros in. escaping can't see past zeros, and the result is truncated */
     230             : #define ZERO "%00"
     231             : #define ZERO_UNESC "\0"
     232             :         {
     233             :                 ESCAPE4 ZERO ESCAPE4,
     234             :                 ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC,
     235             :                 ESCAPE_NE | UNESCAPE_EQ,
     236             :                 sizeof(ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC) - 1,
     237             :                 sizeof(ESCAPE4_UNESC) - 1,
     238             :                 sizeof(ESCAPE4 ZERO ESCAPE4) - 1,
     239             :         },
     240             :         {
     241             :                 ZERO ESCAPE4,
     242             :                 ZERO_UNESC ESCAPE4_UNESC,
     243             :                 ESCAPE_NE | UNESCAPE_EQ,
     244             :                 sizeof(ZERO_UNESC ESCAPE4_UNESC) - 1,
     245             :                 0,
     246             :                 sizeof(ZERO ESCAPE4) - 1,
     247             :         },
     248             :         {
     249             :                 ZERO,
     250             :                 ZERO_UNESC,
     251             :                 ESCAPE_NE | UNESCAPE_EQ,
     252             :                 sizeof(ZERO_UNESC) - 1,
     253             :                 0,
     254             :                 sizeof(ZERO) - 1,
     255             :         },
     256             :         {
     257             :                 spectrum_escaped,
     258             :                 spectrum,
     259             :                 ESCAPE_EQ | UNESCAPE_EQ,
     260             :                 255,
     261             :                 255,
     262             :                 255 * 3,
     263             :         },
     264             : };
     265             : 
     266          38 : static struct rfc1738_test * dup_test(struct rfc1738_test *src)
     267             : {
     268          38 :         struct rfc1738_test *dest = malloc(sizeof(*dest));
     269          38 :         char *esc = NULL, *unesc = NULL;
     270          38 :         if (dest == NULL) {
     271             :                 return NULL;
     272             :         }
     273          38 :         *dest = *src;
     274          38 :         if (src->esc_len) {
     275          38 :                 esc = malloc(src->esc_len + 1);
     276          38 :                 if (esc == NULL) {
     277           0 :                         free(dest);
     278           0 :                         return NULL;
     279             :                 }
     280          38 :                 memcpy(esc, src->escaped, src->esc_len + 1);
     281          38 :                 dest->escaped = esc;
     282             :         }
     283             : 
     284          38 :         if (src->unesc_len) {
     285          30 :                 unesc = malloc(src->unesc_len + 1);
     286          30 :                 if (unesc == NULL) {
     287           0 :                         free(esc);
     288           0 :                         free(dest);
     289           0 :                         return NULL;
     290             :                 }
     291          30 :                 memcpy(unesc, src->unescaped, src->unesc_len + 1);
     292          30 :                 dest->unescaped = unesc;
     293             :         }
     294             : 
     295             :         return dest;
     296             : }
     297             : 
     298          38 : static void free_test(struct rfc1738_test *t)
     299             : {
     300          38 :         free(discard_const_p(char, t->escaped));
     301          38 :         free(discard_const_p(char, t->unescaped));
     302          38 :         free(t);
     303          38 : }
     304             : 
     305             : 
     306           1 : static void test_unescape(void **state)
     307             : {
     308           1 :         uint i;
     309           1 :         char *s, *e;
     310           1 :         struct rfc1738_test *test, *orig;
     311          24 :         for (i = 0; i < ARRAY_SIZE(examples); i++) {
     312          23 :                 orig = &examples[i];
     313          23 :                 if ((orig->flags & (UNESCAPE_ERR |
     314             :                                     UNESCAPE_EQ |
     315             :                                     UNESCAPE_NE)) == 0) {
     316           0 :                         continue;
     317             :                 }
     318          23 :                 test = dup_test(&examples[i]);
     319          23 :                 s = discard_const_p(char, test->escaped);
     320          23 :                 e = rfc1738_unescape(s);
     321          23 :                 if (test->flags & UNESCAPE_ERR) {
     322           9 :                         assert_null(e);
     323           9 :                         free_test(test);
     324           9 :                         continue;
     325             :                 }
     326          14 :                 assert_non_null(e);
     327          14 :                 assert_int_equal(e - s, test->unesc_len);
     328             : 
     329          14 :                 if (test->flags & UNESCAPE_EQ) {
     330          14 :                         assert_memory_equal(s,
     331             :                                             orig->unescaped,
     332             :                                             orig->unesc_len);
     333          14 :                         assert_int_equal(strlen(s),
     334             :                                          orig->unesc_strlen);
     335             :                 } else {
     336           0 :                         assert_memory_not_equal(s,
     337             :                                                 orig->unescaped,
     338             :                                                 orig->unesc_len);
     339           0 :                         assert_int_equal(strlen(s),
     340             :                                          orig->unesc_strlen);
     341             :                 }
     342          14 :                 free_test(test);
     343             :         }
     344           1 : }
     345             : 
     346           1 : static void test_escape(void **state)
     347             : {
     348           1 :         uint i;
     349           1 :         char *s, *e;
     350           1 :         struct rfc1738_test *test, *orig;
     351          24 :         for (i = 0; i < ARRAY_SIZE(examples); i++) {
     352          23 :                 orig = &examples[i];
     353          23 :                 if ((orig->flags & (ESCAPE_EQ |
     354             :                                     ESCAPE_EQ_CASECMP |
     355             :                                     ESCAPE_NE)) == 0) {
     356           8 :                         continue;
     357             :                 }
     358          15 :                 test = dup_test(&examples[i]);
     359          15 :                 s = discard_const_p(char, test->unescaped);
     360          15 :                 e = rfc1738_escape_part(NULL, s);
     361          15 :                 if (test->flags & ESCAPE_EQ) {
     362           9 :                         assert_memory_equal(e, test->escaped,
     363             :                                             test->esc_len + 1);
     364           6 :                 } else if (test->flags & ESCAPE_EQ_CASECMP) {
     365           1 :                         int cmp = strcasecmp(e, test->escaped);
     366           1 :                         assert_int_equal(cmp, 0);
     367           1 :                         assert_string_not_equal(e, test->escaped);
     368             :                 } else {
     369           5 :                         assert_string_not_equal(e, test->escaped);
     370             :                 }
     371          15 :                 free_test(test);
     372             :         }
     373           1 : }
     374             : 
     375             : 
     376           1 : static void gen_spectrum(void)
     377             : {
     378           1 :         int i, j = 0;
     379           1 :         const char *lut = "0123456789ABCDEF";
     380         256 :         for (i = 1; i < 256; i++) {
     381         255 :                 spectrum[i - 1] = i;
     382         255 :                 if (isalnum(i) ||
     383         193 :                     i == '-'   ||
     384             :                     i == '.'   ||
     385         191 :                     i == '_'   ||
     386         190 :                     i == '-'   ||
     387             :                     i == '~') {
     388          66 :                         spectrum_escaped[j] = i;
     389          66 :                         j++;
     390             :                 } else {
     391         189 :                         spectrum_escaped[j] = '%';
     392         189 :                         spectrum_escaped[j + 1] = lut[i >> 4];
     393         189 :                         spectrum_escaped[j + 2] = lut[i & 15];
     394         189 :                         j += 3;
     395             :                 }
     396             :         }
     397           1 :         spectrum[i - 1] = '\0';
     398           1 :         spectrum_escaped[j] = '\0';
     399           1 : }
     400             : 
     401           1 : int main(int argc, const char **argv)
     402             : {
     403           1 :         const struct CMUnitTest tests[] = {
     404             :                 cmocka_unit_test(test_escape),
     405             :                 cmocka_unit_test(test_unescape),
     406             :         };
     407             : 
     408           1 :         gen_spectrum();
     409           1 :         cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
     410           1 :         return cmocka_run_group_tests(tests, NULL, NULL);
     411             : }

Generated by: LCOV version 1.14