]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
share: add sharing of HSTS cache among handles
authorDaniel Stenberg <daniel@haxx.se>
Tue, 27 Dec 2022 10:50:20 +0000 (11:50 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 27 Dec 2022 14:22:01 +0000 (15:22 +0100)
Closes #10138

docs/libcurl/opts/CURLSHOPT_SHARE.3
docs/libcurl/symbols-in-versions
include/curl/curl.h
lib/hsts.c
lib/hsts.h
lib/setopt.c
lib/share.c
lib/share.h
lib/transfer.c
lib/url.c
lib/urldata.h

index 72079d8fbafce08a75822ebcea4e845ce0d2fb84..78593b63293a884574bd868358b298246924d10f 100644 (file)
@@ -78,6 +78,10 @@ Added in 7.61.0.
 
 Note that when you use the multi interface, all easy handles added to the same
 multi handle will share PSL cache by default without using this option.
+.IP CURL_LOCK_DATA_HSTS
+The in-memory HSTS cache.
+
+Added in 7.88.0
 .SH PROTOCOLS
 All
 .SH EXAMPLE
index 6de01a08ccf5e20a4c6ce29ac3bff06669633c43..54605eed000db4dc7b513856b8a8da9cd92186ed 100644 (file)
@@ -73,6 +73,7 @@ CURL_LOCK_ACCESS_SINGLE         7.10.3
 CURL_LOCK_DATA_CONNECT          7.10.3
 CURL_LOCK_DATA_COOKIE           7.10.3
 CURL_LOCK_DATA_DNS              7.10.3
+CURL_LOCK_DATA_HSTS             7.88.0
 CURL_LOCK_DATA_NONE             7.10.3
 CURL_LOCK_DATA_PSL              7.61.0
 CURL_LOCK_DATA_SHARE            7.10.4
index 139df99950bcc9b70cfdb06328a6651bac9f2a2b..5758e3b21fb48b2fd3f6d6a1a38c554a58c4fef4 100644 (file)
@@ -2953,6 +2953,7 @@ typedef enum {
   CURL_LOCK_DATA_SSL_SESSION,
   CURL_LOCK_DATA_CONNECT,
   CURL_LOCK_DATA_PSL,
+  CURL_LOCK_DATA_HSTS,
   CURL_LOCK_DATA_LAST
 } curl_lock_data;
 
index c449120f3148bad309a71149273f39ceb9f8e0ff..339237be1c621aa1c5bd0b8d5df87378d6f3b088 100644 (file)
@@ -39,6 +39,7 @@
 #include "parsedate.h"
 #include "fopen.h"
 #include "rename.h"
+#include "share.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -551,4 +552,18 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
   return CURLE_OK;
 }
 
+void Curl_hsts_loadfiles(struct Curl_easy *data)
+{
+  struct curl_slist *l = data->set.hstslist;
+  if(l) {
+    Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE);
+
+    while(l) {
+      (void)Curl_hsts_loadfile(data, data->hsts, l->data);
+      l = l->next;
+    }
+    Curl_share_unlock(data, CURL_LOCK_DATA_HSTS);
+  }
+}
+
 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
index 0e36a7756bdb2649b6b388dd22bd8a7e5fea9b1e..3da7574e249d67102cc4a6a7ecb1a9d5767f2cfd 100644 (file)
@@ -59,9 +59,11 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
                             struct hsts *h, const char *file);
 CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
                           struct hsts *h);
+void Curl_hsts_loadfiles(struct Curl_easy *data);
 #else
 #define Curl_hsts_cleanup(x)
 #define Curl_hsts_loadcb(x,y) CURLE_OK
 #define Curl_hsts_save(x,y,z)
+#define Curl_hsts_loadfiles(x)
 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
 #endif /* HEADER_CURL_HSTS_H */
index f6083dceb7651024517f423d74bdf109bf01e4b7..ebe24f95c055058c32f637f09d1bfcefcfff199e 100644 (file)
@@ -2262,9 +2262,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         data->cookies = NULL;
 #endif
 
+#ifndef CURL_DISABLE_HSTS
+      if(data->share->hsts == data->hsts)
+        data->hsts = NULL;
+#endif
+#ifdef USE_SSL
       if(data->share->sslsession == data->state.session)
         data->state.session = NULL;
-
+#endif
 #ifdef USE_LIBPSL
       if(data->psl == &data->share->psl)
         data->psl = data->multi? &data->multi->psl: NULL;
@@ -2298,10 +2303,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         data->cookies = data->share->cookies;
       }
 #endif   /* CURL_DISABLE_HTTP */
+#ifndef CURL_DISABLE_HSTS
+      if(data->share->hsts) {
+        /* first free the private one if any */
+        Curl_hsts_cleanup(&data->hsts);
+        data->hsts = data->share->hsts;
+      }
+#endif   /* CURL_DISABLE_HTTP */
+#ifdef USE_SSL
       if(data->share->sslsession) {
         data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
         data->state.session = data->share->sslsession;
       }
+#endif
 #ifdef USE_LIBPSL
       if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
         data->psl = &data->share->psl;
@@ -3053,19 +3067,39 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
   case CURLOPT_HSTSWRITEDATA:
     data->set.hsts_write_userp = va_arg(param, void *);
     break;
-  case CURLOPT_HSTS:
+  case CURLOPT_HSTS: {
+    struct curl_slist *h;
     if(!data->hsts) {
       data->hsts = Curl_hsts_init();
       if(!data->hsts)
         return CURLE_OUT_OF_MEMORY;
     }
     argptr = va_arg(param, char *);
-    result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
-    if(result)
-      return result;
-    if(argptr)
-      (void)Curl_hsts_loadfile(data, data->hsts, argptr);
+    if(argptr) {
+      result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
+      if(result)
+        return result;
+      /* this needs to build a list of file names to read from, so that it can
+         read them later, as we might get a shared HSTS handle to load them
+         into */
+      h = curl_slist_append(data->set.hstslist, argptr);
+      if(!h) {
+        curl_slist_free_all(data->set.hstslist);
+        data->set.hstslist = NULL;
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->set.hstslist = h; /* store the list for later use */
+    }
+    else {
+      /* clear the list of HSTS files */
+      curl_slist_free_all(data->set.hstslist);
+      data->set.hstslist = NULL;
+      if(!data->share || !data->share->hsts)
+        /* throw away the HSTS cache unless shared */
+        Curl_hsts_cleanup(&data->hsts);
+    }
     break;
+  }
   case CURLOPT_HSTS_CTRL:
     arg = va_arg(param, long);
     if(arg & CURLHSTS_ENABLE) {
index 1a083e72a085f2160dcc7fbe828331318e359149..69ee00bf827f9d7661cdccd081b1170934061f43 100644 (file)
 #include "share.h"
 #include "psl.h"
 #include "vtls/vtls.h"
-#include "curl_memory.h"
+#include "hsts.h"
 
-/* The last #include file should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
 #include "memdebug.h"
 
 struct Curl_share *
@@ -89,6 +91,18 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 #endif
       break;
 
+    case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+      if(!share->hsts) {
+        share->hsts = Curl_hsts_init();
+        if(!share->hsts)
+          res = CURLSHE_NOMEM;
+      }
+#else   /* CURL_DISABLE_HSTS */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
     case CURL_LOCK_DATA_SSL_SESSION:
 #ifdef USE_SSL
       if(!share->sslsession) {
@@ -141,6 +155,16 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 #endif
       break;
 
+    case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+      if(share->hsts) {
+        Curl_hsts_cleanup(&share->hsts);
+      }
+#else   /* CURL_DISABLE_HSTS */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
     case CURL_LOCK_DATA_SSL_SESSION:
 #ifdef USE_SSL
       Curl_safefree(share->sslsession);
@@ -207,6 +231,10 @@ curl_share_cleanup(struct Curl_share *share)
   Curl_cookie_cleanup(share->cookies);
 #endif
 
+#ifndef CURL_DISABLE_HSTS
+  Curl_hsts_cleanup(&share->hsts);
+#endif
+
 #ifdef USE_SSL
   if(share->sslsession) {
     size_t i;
index 32be41691a2f974785d0c4f5062df50283761001..24497305556ffc5febccdcc23d049996780bde61 100644 (file)
@@ -59,10 +59,14 @@ struct Curl_share {
 #ifdef USE_LIBPSL
   struct PslCache psl;
 #endif
-
+#ifndef CURL_DISABLE_HSTS
+  struct hsts *hsts;
+#endif
+#ifdef USE_SSL
   struct Curl_ssl_session *sslsession;
   size_t max_ssl_sessions;
   long sessionage;
+#endif
 };
 
 CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,
index 90d9c7b1846abb35308080bf78c027c23b41420e..e58619a84c3d5abb892c445d0129e2d53f963880 100644 (file)
@@ -1396,6 +1396,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
   if(data->state.resolve)
     result = Curl_loadhostpairs(data);
 
+  /* If there is a list of hsts files to read */
+  Curl_hsts_loadfiles(data);
+
   if(!result) {
     /* Allow data->set.use_port to set which port to use. This needs to be
      * disabled for example when we follow Location: headers to URLs using
index 6a18022bd076969b373fb2a88516032f6308b638..815c33fec6fad72b39b65c3169784e6390c6cfc9 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -437,7 +437,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
   Curl_altsvc_cleanup(&data->asi);
   Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
-  Curl_hsts_cleanup(&data->hsts);
+#ifndef CURL_DISABLE_HSTS
+  if(!data->share || !data->share->hsts)
+    Curl_hsts_cleanup(&data->hsts);
+  curl_slist_free_all(data->set.hstslist); /* clean up list */
+#endif
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
   Curl_http_auth_cleanup_digest(data);
 #endif
index 54e4863429e680d7920c1d6cb14ef02fb7f42e17..82cc340d11af3bc87c573253ebd22955e66b6e0b 100644 (file)
@@ -1659,6 +1659,8 @@ struct UserDefined {
                                     curl_easy_setopt(COOKIEFILE) calls */
 #endif
 #ifndef CURL_DISABLE_HSTS
+  struct curl_slist *hstslist; /* list of HSTS files set by
+                                  curl_easy_setopt(HSTS) calls */
   curl_hstsread_callback hsts_read;
   void *hsts_read_userp;
   curl_hstswrite_callback hsts_write;