• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From 076a2f629119222aeeb50f5a03bf9f9052fabb9a Mon Sep 17 00:00:00 2001
2From: Daniel Stenberg <daniel@haxx.se>
3Date: Tue, 27 Dec 2022 11:50:20 +0100
4Subject: [PATCH] share: add sharing of HSTS cache among handles
5
6Closes #10138
7
8Conflict: remove docs/libcurl/opts/CURLSHOPT_SHARE.3
9Reference: https://github.com/curl/curl/commit/076a2f629119222aeeb50f5a03bf9f9052fabb9a
10---
11 docs/libcurl/symbols-in-versions |  1 +
12 include/curl/curl.h              |  1 +
13 lib/hsts.c                       | 15 ++++++++++
14 lib/hsts.h                       |  2 ++
15 lib/setopt.c                     | 48 +++++++++++++++++++++++++++-----
16 lib/share.c                      | 32 +++++++++++++++++++--
17 lib/share.h                      |  6 +++-
18 lib/transfer.c                   |  3 ++
19 lib/url.c                        |  6 +++-
20 lib/urldata.h                    |  2 ++
21 10 files changed, 105 insertions(+), 11 deletions(-)
22
23diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
24index 55f25b6..fcb79f4 100644
25--- a/docs/libcurl/symbols-in-versions
26+++ b/docs/libcurl/symbols-in-versions
27@@ -943,6 +943,7 @@ CURL_LOCK_ACCESS_SINGLE         7.10.3
28 CURL_LOCK_DATA_CONNECT          7.10.3
29 CURL_LOCK_DATA_COOKIE           7.10.3
30 CURL_LOCK_DATA_DNS              7.10.3
31+CURL_LOCK_DATA_HSTS             7.88.0
32 CURL_LOCK_DATA_NONE             7.10.3
33 CURL_LOCK_DATA_PSL              7.61.0
34 CURL_LOCK_DATA_SHARE            7.10.4
35diff --git a/include/curl/curl.h b/include/curl/curl.h
36index 835c3d8..4835003 100644
37--- a/include/curl/curl.h
38+++ b/include/curl/curl.h
39@@ -2821,6 +2821,7 @@ typedef enum {
40   CURL_LOCK_DATA_SSL_SESSION,
41   CURL_LOCK_DATA_CONNECT,
42   CURL_LOCK_DATA_PSL,
43+  CURL_LOCK_DATA_HSTS,
44   CURL_LOCK_DATA_LAST
45 } curl_lock_data;
46
47diff --git a/lib/hsts.c b/lib/hsts.c
48index f51859a..0253049 100644
49--- a/lib/hsts.c
50+++ b/lib/hsts.c
51@@ -37,6 +37,7 @@
52 #include "parsedate.h"
53 #include "fopen.h"
54 #include "rename.h"
55+#include "share.h"
56 #include "strtoofft.h"
57
58 /* The last 3 #include files should be in this order */
59@@ -531,4 +532,18 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
60   return CURLE_OK;
61 }
62
63+void Curl_hsts_loadfiles(struct Curl_easy *data)
64+{
65+  struct curl_slist *l = data->set.hstslist;
66+  if(l) {
67+    Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE);
68+
69+    while(l) {
70+      (void)Curl_hsts_loadfile(data, data->hsts, l->data);
71+      l = l->next;
72+    }
73+    Curl_share_unlock(data, CURL_LOCK_DATA_HSTS);
74+  }
75+}
76+
77 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
78diff --git a/lib/hsts.h b/lib/hsts.h
79index 653c053..ab3fec2 100644
80--- a/lib/hsts.h
81+++ b/lib/hsts.h
82@@ -57,9 +57,11 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
83                             struct hsts *h, const char *file);
84 CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
85                           struct hsts *h);
86+void Curl_hsts_loadfiles(struct Curl_easy *data);
87 #else
88 #define Curl_hsts_cleanup(x)
89 #define Curl_hsts_loadcb(x,y) CURLE_OK
90 #define Curl_hsts_save(x,y,z)
91+#define Curl_hsts_loadfiles(x)
92 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
93 #endif /* HEADER_CURL_HSTS_H */
94diff --git a/lib/setopt.c b/lib/setopt.c
95index a0eeac2..f6eb3bc 100644
96--- a/lib/setopt.c
97+++ b/lib/setopt.c
98@@ -2230,9 +2230,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
99         data->cookies = NULL;
100 #endif
101
102+#ifndef CURL_DISABLE_HSTS
103+      if(data->share->hsts == data->hsts)
104+        data->hsts = NULL;
105+#endif
106+#ifdef USE_SSL
107       if(data->share->sslsession == data->state.session)
108         data->state.session = NULL;
109-
110+#endif
111 #ifdef USE_LIBPSL
112       if(data->psl == &data->share->psl)
113         data->psl = data->multi? &data->multi->psl: NULL;
114@@ -2266,10 +2271,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
115         data->cookies = data->share->cookies;
116       }
117 #endif   /* CURL_DISABLE_HTTP */
118+#ifndef CURL_DISABLE_HSTS
119+      if(data->share->hsts) {
120+        /* first free the private one if any */
121+        Curl_hsts_cleanup(&data->hsts);
122+        data->hsts = data->share->hsts;
123+      }
124+#endif   /* CURL_DISABLE_HTTP */
125+#ifdef USE_SSL
126       if(data->share->sslsession) {
127         data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
128         data->state.session = data->share->sslsession;
129       }
130+#endif
131 #ifdef USE_LIBPSL
132       if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
133         data->psl = &data->share->psl;
134@@ -2958,19 +2972,39 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
135   case CURLOPT_HSTSWRITEDATA:
136     data->set.hsts_write_userp = va_arg(param, void *);
137     break;
138-  case CURLOPT_HSTS:
139+  case CURLOPT_HSTS: {
140+    struct curl_slist *h;
141     if(!data->hsts) {
142       data->hsts = Curl_hsts_init();
143       if(!data->hsts)
144         return CURLE_OUT_OF_MEMORY;
145     }
146     argptr = va_arg(param, char *);
147-    result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
148-    if(result)
149-      return result;
150-    if(argptr)
151-      (void)Curl_hsts_loadfile(data, data->hsts, argptr);
152+    if(argptr) {
153+      result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
154+      if(result)
155+        return result;
156+      /* this needs to build a list of file names to read from, so that it can
157+         read them later, as we might get a shared HSTS handle to load them
158+         into */
159+      h = curl_slist_append(data->set.hstslist, argptr);
160+      if(!h) {
161+        curl_slist_free_all(data->set.hstslist);
162+        data->set.hstslist = NULL;
163+        return CURLE_OUT_OF_MEMORY;
164+      }
165+      data->set.hstslist = h; /* store the list for later use */
166+    }
167+    else {
168+      /* clear the list of HSTS files */
169+      curl_slist_free_all(data->set.hstslist);
170+      data->set.hstslist = NULL;
171+      if(!data->share || !data->share->hsts)
172+        /* throw away the HSTS cache unless shared */
173+        Curl_hsts_cleanup(&data->hsts);
174+    }
175     break;
176+  }
177   case CURLOPT_HSTS_CTRL:
178     arg = va_arg(param, long);
179     if(arg & CURLHSTS_ENABLE) {
180diff --git a/lib/share.c b/lib/share.c
181index 9c43c8f..8681ac2 100644
182--- a/lib/share.c
183+++ b/lib/share.c
184@@ -27,9 +27,11 @@
185 #include "share.h"
186 #include "psl.h"
187 #include "vtls/vtls.h"
188-#include "curl_memory.h"
189+#include "hsts.h"
190
191-/* The last #include file should be: */
192+/* The last 3 #include files should be in this order */
193+#include "curl_printf.h"
194+#include "curl_memory.h"
195 #include "memdebug.h"
196
197 struct Curl_share *
198@@ -91,6 +93,18 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
199 #endif
200       break;
201
202+    case CURL_LOCK_DATA_HSTS:
203+#ifndef CURL_DISABLE_HSTS
204+      if(!share->hsts) {
205+        share->hsts = Curl_hsts_init();
206+        if(!share->hsts)
207+          res = CURLSHE_NOMEM;
208+      }
209+#else   /* CURL_DISABLE_HSTS */
210+      res = CURLSHE_NOT_BUILT_IN;
211+#endif
212+      break;
213+
214     case CURL_LOCK_DATA_SSL_SESSION:
215 #ifdef USE_SSL
216       if(!share->sslsession) {
217@@ -143,6 +157,16 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
218 #endif
219       break;
220
221+    case CURL_LOCK_DATA_HSTS:
222+#ifndef CURL_DISABLE_HSTS
223+      if(share->hsts) {
224+        Curl_hsts_cleanup(&share->hsts);
225+      }
226+#else   /* CURL_DISABLE_HSTS */
227+      res = CURLSHE_NOT_BUILT_IN;
228+#endif
229+      break;
230+
231     case CURL_LOCK_DATA_SSL_SESSION:
232 #ifdef USE_SSL
233       Curl_safefree(share->sslsession);
234@@ -209,6 +233,10 @@ curl_share_cleanup(struct Curl_share *share)
235   Curl_cookie_cleanup(share->cookies);
236 #endif
237
238+#ifndef CURL_DISABLE_HSTS
239+  Curl_hsts_cleanup(&share->hsts);
240+#endif
241+
242 #ifdef USE_SSL
243   if(share->sslsession) {
244     size_t i;
245diff --git a/lib/share.h b/lib/share.h
246index 222e34b..97b820b 100644
247--- a/lib/share.h
248+++ b/lib/share.h
249@@ -57,10 +57,14 @@ struct Curl_share {
250 #ifdef USE_LIBPSL
251   struct PslCache psl;
252 #endif
253-
254+#ifndef CURL_DISABLE_HSTS
255+  struct hsts *hsts;
256+#endif
257+#ifdef USE_SSL
258   struct Curl_ssl_session *sslsession;
259   size_t max_ssl_sessions;
260   long sessionage;
261+#endif
262 };
263
264 CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,
265diff --git a/lib/transfer.c b/lib/transfer.c
266index 6d23eae..970ef35 100644
267--- a/lib/transfer.c
268+++ b/lib/transfer.c
269@@ -1468,6 +1468,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
270   if(data->state.resolve)
271     result = Curl_loadhostpairs(data);
272
273+  /* If there is a list of hsts files to read */
274+  Curl_hsts_loadfiles(data);
275+
276   if(!result) {
277     /* Allow data->set.use_port to set which port to use. This needs to be
278      * disabled for example when we follow Location: headers to URLs using
279diff --git a/lib/url.c b/lib/url.c
280index 6df1de4..02c74f9 100644
281--- a/lib/url.c
282+++ b/lib/url.c
283@@ -427,7 +427,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
284   Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
285   Curl_altsvc_cleanup(&data->asi);
286   Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
287-  Curl_hsts_cleanup(&data->hsts);
288+#ifndef CURL_DISABLE_HSTS
289+  if(!data->share || !data->share->hsts)
290+    Curl_hsts_cleanup(&data->hsts);
291+  curl_slist_free_all(data->set.hstslist); /* clean up list */
292+#endif
293 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
294   Curl_http_auth_cleanup_digest(data);
295 #endif
296diff --git a/lib/urldata.h b/lib/urldata.h
297index 23bc588..5c178cc 100644
298--- a/lib/urldata.h
299+++ b/lib/urldata.h
300@@ -1670,6 +1670,8 @@ struct UserDefined {
301   /* function to convert from UTF-8 encoding: */
302   curl_conv_callback convfromutf8;
303 #ifndef CURL_DISABLE_HSTS
304+  struct curl_slist *hstslist; /* list of HSTS files set by
305+                                  curl_easy_setopt(HSTS) calls */
306   curl_hstsread_callback hsts_read;
307   void *hsts_read_userp;
308   curl_hstswrite_callback hsts_write;
309--
3102.33.0
311
312