blob: 4ef7faa732f92c7a384af2d5a997e68dc058d214 [file] [log] [blame]
xf.li6c8fc1e2023-08-12 00:11:09 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2020 - 2022, 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{
122 CURLcode result;
123 struct stsentry *e;
124 struct hsts *h = Curl_hsts_init();
125 int i;
126 const char *chost;
127 CURL *easy;
128 if(!h)
129 return 1;
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 return 1;
137 }
138
139 Curl_hsts_loadfile(easy, h, "log/input1660");
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 (void)Curl_hsts_save(easy, h, "log/hsts1660");
173 Curl_hsts_cleanup(&h);
174 curl_easy_cleanup(easy);
175 curl_global_cleanup();
176 return unitfail;
177}
178UNITTEST_STOP
179#endif