share: add sharing of HSTS cache among handles

Closes #10138
This commit is contained in:
Daniel Stenberg 2022-12-27 11:50:20 +01:00
parent 692c73707a
commit 076a2f6291
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
11 changed files with 109 additions and 11 deletions

View 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 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. 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 .SH PROTOCOLS
All All
.SH EXAMPLE .SH EXAMPLE

View File

@ -73,6 +73,7 @@ CURL_LOCK_ACCESS_SINGLE 7.10.3
CURL_LOCK_DATA_CONNECT 7.10.3 CURL_LOCK_DATA_CONNECT 7.10.3
CURL_LOCK_DATA_COOKIE 7.10.3 CURL_LOCK_DATA_COOKIE 7.10.3
CURL_LOCK_DATA_DNS 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_NONE 7.10.3
CURL_LOCK_DATA_PSL 7.61.0 CURL_LOCK_DATA_PSL 7.61.0
CURL_LOCK_DATA_SHARE 7.10.4 CURL_LOCK_DATA_SHARE 7.10.4

View File

@ -2953,6 +2953,7 @@ typedef enum {
CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_DATA_SSL_SESSION,
CURL_LOCK_DATA_CONNECT, CURL_LOCK_DATA_CONNECT,
CURL_LOCK_DATA_PSL, CURL_LOCK_DATA_PSL,
CURL_LOCK_DATA_HSTS,
CURL_LOCK_DATA_LAST CURL_LOCK_DATA_LAST
} curl_lock_data; } curl_lock_data;

View File

@ -39,6 +39,7 @@
#include "parsedate.h" #include "parsedate.h"
#include "fopen.h" #include "fopen.h"
#include "rename.h" #include "rename.h"
#include "share.h"
/* The last 3 #include files should be in this order */ /* The last 3 #include files should be in this order */
#include "curl_printf.h" #include "curl_printf.h"
@ -551,4 +552,18 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
return CURLE_OK; 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 */ #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */

View File

@ -59,9 +59,11 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
struct hsts *h, const char *file); struct hsts *h, const char *file);
CURLcode Curl_hsts_loadcb(struct Curl_easy *data, CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
struct hsts *h); struct hsts *h);
void Curl_hsts_loadfiles(struct Curl_easy *data);
#else #else
#define Curl_hsts_cleanup(x) #define Curl_hsts_cleanup(x)
#define Curl_hsts_loadcb(x,y) CURLE_OK #define Curl_hsts_loadcb(x,y) CURLE_OK
#define Curl_hsts_save(x,y,z) #define Curl_hsts_save(x,y,z)
#define Curl_hsts_loadfiles(x)
#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
#endif /* HEADER_CURL_HSTS_H */ #endif /* HEADER_CURL_HSTS_H */

View File

@ -2262,9 +2262,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->cookies = NULL; data->cookies = NULL;
#endif #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) if(data->share->sslsession == data->state.session)
data->state.session = NULL; data->state.session = NULL;
#endif
#ifdef USE_LIBPSL #ifdef USE_LIBPSL
if(data->psl == &data->share->psl) if(data->psl == &data->share->psl)
data->psl = data->multi? &data->multi->psl: NULL; 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; data->cookies = data->share->cookies;
} }
#endif /* CURL_DISABLE_HTTP */ #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) { if(data->share->sslsession) {
data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
data->state.session = data->share->sslsession; data->state.session = data->share->sslsession;
} }
#endif
#ifdef USE_LIBPSL #ifdef USE_LIBPSL
if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
data->psl = &data->share->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: case CURLOPT_HSTSWRITEDATA:
data->set.hsts_write_userp = va_arg(param, void *); data->set.hsts_write_userp = va_arg(param, void *);
break; break;
case CURLOPT_HSTS: case CURLOPT_HSTS: {
struct curl_slist *h;
if(!data->hsts) { if(!data->hsts) {
data->hsts = Curl_hsts_init(); data->hsts = Curl_hsts_init();
if(!data->hsts) if(!data->hsts)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
argptr = va_arg(param, char *); argptr = va_arg(param, char *);
result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr); if(argptr) {
if(result) result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
return result; if(result)
if(argptr) return result;
(void)Curl_hsts_loadfile(data, data->hsts, argptr); /* 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; break;
}
case CURLOPT_HSTS_CTRL: case CURLOPT_HSTS_CTRL:
arg = va_arg(param, long); arg = va_arg(param, long);
if(arg & CURLHSTS_ENABLE) { if(arg & CURLHSTS_ENABLE) {

View File

@ -29,9 +29,11 @@
#include "share.h" #include "share.h"
#include "psl.h" #include "psl.h"
#include "vtls/vtls.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" #include "memdebug.h"
struct Curl_share * struct Curl_share *
@ -89,6 +91,18 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
#endif #endif
break; 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: case CURL_LOCK_DATA_SSL_SESSION:
#ifdef USE_SSL #ifdef USE_SSL
if(!share->sslsession) { if(!share->sslsession) {
@ -141,6 +155,16 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
#endif #endif
break; 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: case CURL_LOCK_DATA_SSL_SESSION:
#ifdef USE_SSL #ifdef USE_SSL
Curl_safefree(share->sslsession); Curl_safefree(share->sslsession);
@ -207,6 +231,10 @@ curl_share_cleanup(struct Curl_share *share)
Curl_cookie_cleanup(share->cookies); Curl_cookie_cleanup(share->cookies);
#endif #endif
#ifndef CURL_DISABLE_HSTS
Curl_hsts_cleanup(&share->hsts);
#endif
#ifdef USE_SSL #ifdef USE_SSL
if(share->sslsession) { if(share->sslsession) {
size_t i; size_t i;

View File

@ -59,10 +59,14 @@ struct Curl_share {
#ifdef USE_LIBPSL #ifdef USE_LIBPSL
struct PslCache psl; struct PslCache psl;
#endif #endif
#ifndef CURL_DISABLE_HSTS
struct hsts *hsts;
#endif
#ifdef USE_SSL
struct Curl_ssl_session *sslsession; struct Curl_ssl_session *sslsession;
size_t max_ssl_sessions; size_t max_ssl_sessions;
long sessionage; long sessionage;
#endif
}; };
CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,

View File

@ -1396,6 +1396,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
if(data->state.resolve) if(data->state.resolve)
result = Curl_loadhostpairs(data); result = Curl_loadhostpairs(data);
/* If there is a list of hsts files to read */
Curl_hsts_loadfiles(data);
if(!result) { if(!result) {
/* Allow data->set.use_port to set which port to use. This needs to be /* 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 * disabled for example when we follow Location: headers to URLs using

View File

@ -437,7 +437,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(&data->asi); Curl_altsvc_cleanup(&data->asi);
Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); 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) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
Curl_http_auth_cleanup_digest(data); Curl_http_auth_cleanup_digest(data);
#endif #endif

View File

@ -1659,6 +1659,8 @@ struct UserDefined {
curl_easy_setopt(COOKIEFILE) calls */ curl_easy_setopt(COOKIEFILE) calls */
#endif #endif
#ifndef CURL_DISABLE_HSTS #ifndef CURL_DISABLE_HSTS
struct curl_slist *hstslist; /* list of HSTS files set by
curl_easy_setopt(HSTS) calls */
curl_hstsread_callback hsts_read; curl_hstsread_callback hsts_read;
void *hsts_read_userp; void *hsts_read_userp;
curl_hstswrite_callback hsts_write; curl_hstswrite_callback hsts_write;