| /*************************************************************************** | 
 |  *                                  _   _ ____  _ | 
 |  *  Project                     ___| | | |  _ \| | | 
 |  *                             / __| | | | |_) | | | 
 |  *                            | (__| |_| |  _ <| |___ | 
 |  *                             \___|\___/|_| \_\_____| | 
 |  * | 
 |  * Copyright (C) 2020 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. | 
 |  * | 
 |  * This software is licensed as described in the file COPYING, which | 
 |  * you should have received as part of this distribution. The terms | 
 |  * are also available at https://curl.se/docs/copyright.html. | 
 |  * | 
 |  * You may opt to use, copy, modify, merge, publish, distribute and/or sell | 
 |  * copies of the Software, and permit persons to whom the Software is | 
 |  * furnished to do so, under the terms of the COPYING file. | 
 |  * | 
 |  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | 
 |  * KIND, either express or implied. | 
 |  * | 
 |  * SPDX-License-Identifier: curl | 
 |  * | 
 |  ***************************************************************************/ | 
 | #include "curlcheck.h" | 
 |  | 
 | #include "urldata.h" | 
 | #include "hsts.h" | 
 |  | 
 | static CURLcode | 
 | unit_setup(void) | 
 | { | 
 |   return CURLE_OK; | 
 | } | 
 |  | 
 | static void | 
 | unit_stop(void) | 
 | { | 
 |   curl_global_cleanup(); | 
 | } | 
 |  | 
 | #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_HSTS) | 
 | UNITTEST_START | 
 | { | 
 |   return 0; /* nothing to do when HTTP or HSTS are disabled */ | 
 | } | 
 | UNITTEST_STOP | 
 | #else | 
 |  | 
 | struct testit { | 
 |   const char *host; | 
 |   const char *chost; /* if non-NULL, use to lookup with */ | 
 |   const char *hdr; /* if NULL, just do the lookup */ | 
 |   const CURLcode result; /* parse result */ | 
 | }; | 
 |  | 
 | static const struct testit headers[] = { | 
 |   /* two entries read from disk cache, verify first */ | 
 |   { "-", "readfrom.example", NULL, CURLE_OK}, | 
 |   { "-", "old.example", NULL, CURLE_OK}, | 
 |   /* delete the remaining one read from disk */ | 
 |   { "readfrom.example", NULL, "max-age=\"0\"", CURLE_OK}, | 
 |  | 
 |   { "example.com", NULL, "max-age=\"31536000\"\r\n", CURLE_OK }, | 
 |   { "example.com", NULL, "max-age=\"21536000\"\r\n", CURLE_OK }, | 
 |   { "example.com", NULL, "max-age=\"21536000\"; \r\n", CURLE_OK }, | 
 |   { "example.com", NULL, "max-age=\"21536000\"; includeSubDomains\r\n", | 
 |     CURLE_OK }, | 
 |   { "example.org", NULL, "max-age=\"31536000\"\r\n", CURLE_OK }, | 
 |   { "this.example", NULL, "max=\"31536\";", CURLE_BAD_FUNCTION_ARGUMENT }, | 
 |   { "this.example", NULL, "max-age=\"31536", CURLE_BAD_FUNCTION_ARGUMENT }, | 
 |   { "this.example", NULL, "max-age=31536\"", CURLE_OK }, | 
 |   /* max-age=0 removes the entry */ | 
 |   { "this.example", NULL, "max-age=0", CURLE_OK }, | 
 |   { "another.example", NULL, "includeSubDomains; ", | 
 |     CURLE_BAD_FUNCTION_ARGUMENT }, | 
 |  | 
 |   /* Two max-age is illegal */ | 
 |   { "example.com", NULL, | 
 |     "max-age=\"21536000\"; includeSubDomains; max-age=\"3\";", | 
 |     CURLE_BAD_FUNCTION_ARGUMENT }, | 
 |   /* Two includeSubDomains is illegal */ | 
 |   { "2.example.com", NULL, | 
 |     "max-age=\"21536000\"; includeSubDomains; includeSubDomains;", | 
 |     CURLE_BAD_FUNCTION_ARGUMENT }, | 
 |   /* use a unknown directive "include" that should be ignored */ | 
 |   { "3.example.com", NULL, "max-age=\"21536000\"; include; includeSubDomains;", | 
 |     CURLE_OK }, | 
 |   /* remove the "3.example.com" one, should still match the example.com */ | 
 |   { "3.example.com", NULL, "max-age=\"0\"; includeSubDomains;", | 
 |     CURLE_OK }, | 
 |   { "-", "foo.example.com", NULL, CURLE_OK}, | 
 |   { "-", "foo.xample.com", NULL, CURLE_OK}, | 
 |  | 
 |   /* should not match */ | 
 |   { "example.net", "forexample.net", "max-age=\"31536000\"\r\n", CURLE_OK }, | 
 |  | 
 |   /* should not match either, since forexample.net is not in the example.net | 
 |      domain */ | 
 |   { "example.net", "forexample.net", | 
 |     "max-age=\"31536000\"; includeSubDomains\r\n", CURLE_OK }, | 
 |   /* remove example.net again */ | 
 |   { "example.net", NULL, "max-age=\"0\"; includeSubDomains\r\n", CURLE_OK }, | 
 |  | 
 |   /* make this live for 7 seconds */ | 
 |   { "expire.example", NULL, "max-age=\"7\"\r\n", CURLE_OK }, | 
 |   { NULL, NULL, NULL, CURLE_OK } | 
 | }; | 
 |  | 
 | static void showsts(struct stsentry *e, const char *chost) | 
 | { | 
 |   if(!e) | 
 |     printf("'%s' is not HSTS\n", chost); | 
 |   else { | 
 |     printf("%s [%s]: %" CURL_FORMAT_CURL_OFF_T "%s\n", | 
 |            chost, e->host, e->expires, | 
 |            e->includeSubDomains ? " includeSubDomains" : ""); | 
 |   } | 
 | } | 
 |  | 
 | UNITTEST_START | 
 | { | 
 |   CURLcode result; | 
 |   struct stsentry *e; | 
 |   struct hsts *h = Curl_hsts_init(); | 
 |   int i; | 
 |   const char *chost; | 
 |   CURL *easy; | 
 |   if(!h) | 
 |     return 1; | 
 |  | 
 |   curl_global_init(CURL_GLOBAL_ALL); | 
 |   easy = curl_easy_init(); | 
 |   if(!easy) { | 
 |     Curl_hsts_cleanup(&h); | 
 |     curl_global_cleanup(); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   Curl_hsts_loadfile(easy, h, "log/input1660"); | 
 |  | 
 |   for(i = 0; headers[i].host ; i++) { | 
 |     if(headers[i].hdr) { | 
 |       result = Curl_hsts_parse(h, headers[i].host, headers[i].hdr); | 
 |  | 
 |       if(result != headers[i].result) { | 
 |         fprintf(stderr, "Curl_hsts_parse(%s) failed: %d\n", | 
 |                 headers[i].hdr, result); | 
 |         unitfail++; | 
 |         continue; | 
 |       } | 
 |       else if(result) { | 
 |         printf("Input %u: error %d\n", i, (int) result); | 
 |         continue; | 
 |       } | 
 |     } | 
 |  | 
 |     chost = headers[i].chost ? headers[i].chost : headers[i].host; | 
 |     e = Curl_hsts(h, chost, TRUE); | 
 |     showsts(e, chost); | 
 |   } | 
 |  | 
 |   printf("Number of entries: %zu\n", h->list.size); | 
 |  | 
 |   /* verify that it is exists for 7 seconds */ | 
 |   chost = "expire.example"; | 
 |   for(i = 100; i < 110; i++) { | 
 |     e = Curl_hsts(h, chost, TRUE); | 
 |     showsts(e, chost); | 
 |     deltatime++; /* another second passed */ | 
 |   } | 
 |  | 
 |   (void)Curl_hsts_save(easy, h, "log/hsts1660"); | 
 |   Curl_hsts_cleanup(&h); | 
 |   curl_easy_cleanup(easy); | 
 |   curl_global_cleanup(); | 
 |   return unitfail; | 
 | } | 
 | UNITTEST_STOP | 
 | #endif |