1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24#include "curlcheck.h" 25 26#include "urldata.h" 27#include "hsts.h" 28 29static CURLcode 30unit_setup(void) 31{ 32 return CURLE_OK; 33} 34 35static void 36unit_stop(void) 37{ 38 curl_global_cleanup(); 39} 40 41#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_HSTS) 42UNITTEST_START 43{ 44 return 0; /* nothing to do when HTTP or HSTS are disabled */ 45} 46UNITTEST_STOP 47#else 48 49struct testit { 50 const char *host; 51 const char *chost; /* if non-NULL, use to lookup with */ 52 const char *hdr; /* if NULL, just do the lookup */ 53 const CURLcode result; /* parse result */ 54}; 55 56static const struct testit headers[] = { 57 /* two entries read from disk cache, verify first */ 58 { "-", "readfrom.example", NULL, CURLE_OK}, 59 { "-", "old.example", NULL, CURLE_OK}, 60 /* delete the remaining one read from disk */ 61 { "readfrom.example", NULL, "max-age=\"0\"", CURLE_OK}, 62 63 { "example.com", NULL, "max-age=\"31536000\"\r\n", CURLE_OK }, 64 { "example.com", NULL, "max-age=\"21536000\"\r\n", CURLE_OK }, 65 { "example.com", NULL, "max-age=\"21536000\"; \r\n", CURLE_OK }, 66 { "example.com", NULL, "max-age=\"21536000\"; includeSubDomains\r\n", 67 CURLE_OK }, 68 { "example.org", NULL, "max-age=\"31536000\"\r\n", CURLE_OK }, 69 { "this.example", NULL, "max=\"31536\";", CURLE_BAD_FUNCTION_ARGUMENT }, 70 { "this.example", NULL, "max-age=\"31536", CURLE_BAD_FUNCTION_ARGUMENT }, 71 { "this.example", NULL, "max-age=31536\"", CURLE_OK }, 72 /* max-age=0 removes the entry */ 73 { "this.example", NULL, "max-age=0", CURLE_OK }, 74 { "another.example", NULL, "includeSubDomains; ", 75 CURLE_BAD_FUNCTION_ARGUMENT }, 76 77 /* Two max-age is illegal */ 78 { "example.com", NULL, 79 "max-age=\"21536000\"; includeSubDomains; max-age=\"3\";", 80 CURLE_BAD_FUNCTION_ARGUMENT }, 81 /* Two includeSubDomains is illegal */ 82 { "2.example.com", NULL, 83 "max-age=\"21536000\"; includeSubDomains; includeSubDomains;", 84 CURLE_BAD_FUNCTION_ARGUMENT }, 85 /* use a unknown directive "include" that should be ignored */ 86 { "3.example.com", NULL, "max-age=\"21536000\"; include; includeSubDomains;", 87 CURLE_OK }, 88 /* remove the "3.example.com" one, should still match the example.com */ 89 { "3.example.com", NULL, "max-age=\"0\"; includeSubDomains;", 90 CURLE_OK }, 91 { "-", "foo.example.com", NULL, CURLE_OK}, 92 { "-", "foo.xample.com", NULL, CURLE_OK}, 93 94 /* should not match */ 95 { "example.net", "forexample.net", "max-age=\"31536000\"\r\n", CURLE_OK }, 96 97 /* should not match either, since forexample.net is not in the example.net 98 domain */ 99 { "example.net", "forexample.net", 100 "max-age=\"31536000\"; includeSubDomains\r\n", CURLE_OK }, 101 /* remove example.net again */ 102 { "example.net", NULL, "max-age=\"0\"; includeSubDomains\r\n", CURLE_OK }, 103 104 /* make this live for 7 seconds */ 105 { "expire.example", NULL, "max-age=\"7\"\r\n", CURLE_OK }, 106 { NULL, NULL, NULL, CURLE_OK } 107}; 108 109static void showsts(struct stsentry *e, const char *chost) 110{ 111 if(!e) 112 printf("'%s' is not HSTS\n", chost); 113 else { 114 printf("%s [%s]: %" CURL_FORMAT_CURL_OFF_T "%s\n", 115 chost, e->host, e->expires, 116 e->includeSubDomains ? " includeSubDomains" : ""); 117 } 118} 119 120UNITTEST_START 121 CURLcode result; 122 struct stsentry *e; 123 struct hsts *h = Curl_hsts_init(); 124 int i; 125 const char *chost; 126 CURL *easy; 127 char savename[256]; 128 129 abort_unless(h, "Curl_hsts_init()"); 130 131 curl_global_init(CURL_GLOBAL_ALL); 132 easy = curl_easy_init(); 133 if(!easy) { 134 Curl_hsts_cleanup(&h); 135 curl_global_cleanup(); 136 abort_unless(easy, "curl_easy_init()"); 137 } 138 139 Curl_hsts_loadfile(easy, h, arg); 140 141 for(i = 0; headers[i].host ; i++) { 142 if(headers[i].hdr) { 143 result = Curl_hsts_parse(h, headers[i].host, headers[i].hdr); 144 145 if(result != headers[i].result) { 146 fprintf(stderr, "Curl_hsts_parse(%s) failed: %d\n", 147 headers[i].hdr, result); 148 unitfail++; 149 continue; 150 } 151 else if(result) { 152 printf("Input %u: error %d\n", i, (int) result); 153 continue; 154 } 155 } 156 157 chost = headers[i].chost ? headers[i].chost : headers[i].host; 158 e = Curl_hsts(h, chost, TRUE); 159 showsts(e, chost); 160 } 161 162 printf("Number of entries: %zu\n", h->list.size); 163 164 /* verify that it is exists for 7 seconds */ 165 chost = "expire.example"; 166 for(i = 100; i < 110; i++) { 167 e = Curl_hsts(h, chost, TRUE); 168 showsts(e, chost); 169 deltatime++; /* another second passed */ 170 } 171 172 msnprintf(savename, sizeof(savename), "%s.save", arg); 173 (void)Curl_hsts_save(easy, h, savename); 174 Curl_hsts_cleanup(&h); 175 curl_easy_cleanup(easy); 176 curl_global_cleanup(); 177 178UNITTEST_STOP 179#endif 180