xref: /third_party/curl/tests/unit/unit1660.c (revision 13498266)
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