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