|  | @@ -1875,6 +1875,8 @@ typedef struct x509 X509;
 | 
	
		
			
				|  |  |  #define SSL_TLSEXT_ERR_ALERT_FATAL (2)
 | 
	
		
			
				|  |  |  #define SSL_TLSEXT_ERR_NOACK (3)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define SSL_SESS_CACHE_BOTH (3)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  enum ssl_func_category {
 | 
	
		
			
				|  |  |  	TLS_Mandatory, /* required for HTTPS */
 | 
	
		
			
				|  |  |  	TLS_ALPN,      /* required for Application Layer Protocol Negotiation */
 | 
	
	
		
			
				|  | @@ -1971,6 +1973,11 @@ typedef int (*tSSL_next_protos_advertised_cb)(SSL *ssl,
 | 
	
		
			
				|  |  |  	(*(void (*)(SSL_CTX *, tSSL_next_protos_advertised_cb, void *))ssl_sw[41]  \
 | 
	
		
			
				|  |  |  	      .ptr)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define SSL_CTX_set_session_cache_mode                                         \
 | 
	
		
			
				|  |  | +	(*(long (*)(SSL_CTX *, long))ssl_sw[42].ptr)
 | 
	
		
			
				|  |  | +#define SSL_CTX_sess_set_cache_size (*(long (*)(SSL_CTX *, long))ssl_sw[43].ptr)
 | 
	
		
			
				|  |  | +#define SSL_CTX_set_timeout (*(long (*)(SSL_CTX *, long))ssl_sw[44].ptr)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #define SSL_CTX_clear_options(ctx, op)                                         \
 | 
	
		
			
				|  |  |  	SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
 | 
	
		
			
				|  |  |  #define SSL_CTX_set_ecdh_auto(ctx, onoff)                                      \
 | 
	
	
		
			
				|  | @@ -2067,6 +2074,9 @@ static struct ssl_func ssl_sw[] = {
 | 
	
		
			
				|  |  |      {"SSL_CTX_set_alpn_protos", TLS_ALPN, NULL},
 | 
	
		
			
				|  |  |      {"SSL_CTX_set_alpn_select_cb", TLS_ALPN, NULL},
 | 
	
		
			
				|  |  |      {"SSL_CTX_set_next_protos_advertised_cb", TLS_ALPN, NULL},
 | 
	
		
			
				|  |  | +    {"SSL_CTX_set_session_cache_mode", TLS_Mandatory, NULL},
 | 
	
		
			
				|  |  | +    {"SSL_CTX_sess_set_cache_size", TLS_Mandatory, NULL},
 | 
	
		
			
				|  |  | +    {"SSL_CTX_set_timeout", TLS_Mandatory, NULL},
 | 
	
		
			
				|  |  |      {NULL, TLS_END_OF_LIST, NULL}};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2165,6 +2175,11 @@ typedef int (*tSSL_next_protos_advertised_cb)(SSL *ssl,
 | 
	
		
			
				|  |  |  	(*(void (*)(SSL_CTX *, tSSL_next_protos_advertised_cb, void *))ssl_sw[41]  \
 | 
	
		
			
				|  |  |  	      .ptr)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define SSL_CTX_set_session_cache_mode                                         \
 | 
	
		
			
				|  |  | +	(*(long (*)(SSL_CTX *, long))ssl_sw[42].ptr)
 | 
	
		
			
				|  |  | +#define SSL_CTX_sess_set_cache_size (*(long (*)(SSL_CTX *, long))ssl_sw[43].ptr)
 | 
	
		
			
				|  |  | +#define SSL_CTX_set_timeout (*(long (*)(SSL_CTX *, long))ssl_sw[44].ptr)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define SSL_CTX_set_options(ctx, op)                                           \
 | 
	
		
			
				|  |  |  	SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
 | 
	
	
		
			
				|  | @@ -2279,6 +2294,9 @@ static struct ssl_func ssl_sw[] = {
 | 
	
		
			
				|  |  |      {"SSL_CTX_set_alpn_protos", TLS_ALPN, NULL},
 | 
	
		
			
				|  |  |      {"SSL_CTX_set_alpn_select_cb", TLS_ALPN, NULL},
 | 
	
		
			
				|  |  |      {"SSL_CTX_set_next_protos_advertised_cb", TLS_ALPN, NULL},
 | 
	
		
			
				|  |  | +    {"SSL_CTX_set_session_cache_mode", TLS_Mandatory, NULL},
 | 
	
		
			
				|  |  | +    {"SSL_CTX_sess_set_cache_size", TLS_Mandatory, NULL},
 | 
	
		
			
				|  |  | +    {"SSL_CTX_set_timeout", TLS_Mandatory, NULL},
 | 
	
		
			
				|  |  |      {NULL, TLS_END_OF_LIST, NULL}};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2486,6 +2504,7 @@ enum {
 | 
	
		
			
				|  |  |  	URL_REWRITE_PATTERN,
 | 
	
		
			
				|  |  |  	HIDE_FILES,
 | 
	
		
			
				|  |  |  	SSL_DO_VERIFY_PEER,
 | 
	
		
			
				|  |  | +	SSL_CACHE_TIMEOUT,
 | 
	
		
			
				|  |  |  	SSL_CA_PATH,
 | 
	
		
			
				|  |  |  	SSL_CA_FILE,
 | 
	
		
			
				|  |  |  	SSL_VERIFY_DEPTH,
 | 
	
	
		
			
				|  | @@ -2603,6 +2622,7 @@ static const struct mg_option config_options[] = {
 | 
	
		
			
				|  |  |      {"hide_files_patterns", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      {"ssl_verify_peer", MG_CONFIG_TYPE_YES_NO_OPTIONAL, "no"},
 | 
	
		
			
				|  |  | +    {"ssl_cache_timeout", MG_CONFIG_TYPE_NUMBER, "-1"},
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      {"ssl_ca_path", MG_CONFIG_TYPE_DIRECTORY, NULL},
 | 
	
		
			
				|  |  |      {"ssl_ca_file", MG_CONFIG_TYPE_FILE, NULL},
 | 
	
	
		
			
				|  | @@ -16474,6 +16494,7 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 | 
	
		
			
				|  |  |  	md5_byte_t ssl_context_id[16];
 | 
	
		
			
				|  |  |  	md5_state_t md5state;
 | 
	
		
			
				|  |  |  	int protocol_ver;
 | 
	
		
			
				|  |  | +	int ssl_cache_timeout;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(OPENSSL_API_1_1)
 | 
	
		
			
				|  |  |  	if ((dom_ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
 | 
	
	
		
			
				|  | @@ -16665,6 +16686,16 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* SSL session caching */
 | 
	
		
			
				|  |  | +	ssl_cache_timeout = ((dom_ctx->config[SSL_CACHE_TIMEOUT] != NULL)
 | 
	
		
			
				|  |  | +	                         ? atoi(dom_ctx->config[SSL_CACHE_TIMEOUT])
 | 
	
		
			
				|  |  | +	                         : 0);
 | 
	
		
			
				|  |  | +	if (ssl_cache_timeout > 0) {
 | 
	
		
			
				|  |  | +		SSL_CTX_set_session_cache_mode(dom_ctx->ssl_ctx, SSL_SESS_CACHE_BOTH);
 | 
	
		
			
				|  |  | +		/* SSL_CTX_sess_set_cache_size(dom_ctx->ssl_ctx, 10000);  ... use default */
 | 
	
		
			
				|  |  | +		SSL_CTX_set_timeout(dom_ctx->ssl_ctx, (long)ssl_cache_timeout);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	/* Initialize ALPN only of TLS library (OpenSSL version) supports ALPN */
 | 
	
		
			
				|  |  |  #if !defined(NO_SSL_DL)
 | 
	
		
			
				|  |  |  	if (!tls_feature_missing[TLS_ALPN])
 | 
	
	
		
			
				|  | @@ -16710,11 +16741,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 | 
	
		
			
				|  |  |  	                                                phys_ctx->user_data));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (callback_ret < 0) {
 | 
	
		
			
				|  |  | +		/* Callback exists and returns <0: Initializing failed. */
 | 
	
		
			
				|  |  |  		mg_cry_ctx_internal(phys_ctx,
 | 
	
		
			
				|  |  |  		                    "external_ssl_ctx callback returned error: %i",
 | 
	
		
			
				|  |  |  		                    callback_ret);
 | 
	
		
			
				|  |  |  		return 0;
 | 
	
		
			
				|  |  |  	} else if (callback_ret > 0) {
 | 
	
		
			
				|  |  | +		/* Callback exists and returns >0: Initializing complete,
 | 
	
		
			
				|  |  | +		 * civetweb should not modify the SSL context. */
 | 
	
		
			
				|  |  |  		dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
 | 
	
		
			
				|  |  |  		if (!initialize_ssl(ebuf, sizeof(ebuf))) {
 | 
	
		
			
				|  |  |  			mg_cry_ctx_internal(phys_ctx, "%s", ebuf);
 | 
	
	
		
			
				|  | @@ -16722,8 +16756,10 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		return 1;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	/* If the callback does not exist or return 0, civetweb must initialize
 | 
	
		
			
				|  |  | +	 * the SSL context. Handle "domain" callback next. */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/* Check for external domain SSL_CTX */
 | 
	
		
			
				|  |  | +	/* Check for external domain SSL_CTX callback. */
 | 
	
		
			
				|  |  |  	callback_ret = (phys_ctx->callbacks.external_ssl_ctx_domain == NULL)
 | 
	
		
			
				|  |  |  	                   ? 0
 | 
	
		
			
				|  |  |  	                   : (phys_ctx->callbacks.external_ssl_ctx_domain(
 | 
	
	
		
			
				|  | @@ -16732,12 +16768,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 | 
	
		
			
				|  |  |  	                         phys_ctx->user_data));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (callback_ret < 0) {
 | 
	
		
			
				|  |  | +		/* Callback < 0: Error. Abort init. */
 | 
	
		
			
				|  |  |  		mg_cry_ctx_internal(
 | 
	
		
			
				|  |  |  		    phys_ctx,
 | 
	
		
			
				|  |  |  		    "external_ssl_ctx_domain callback returned error: %i",
 | 
	
		
			
				|  |  |  		    callback_ret);
 | 
	
		
			
				|  |  |  		return 0;
 | 
	
		
			
				|  |  |  	} else if (callback_ret > 0) {
 | 
	
		
			
				|  |  | +		/* Callback > 0: Consider init done. */
 | 
	
		
			
				|  |  |  		dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
 | 
	
		
			
				|  |  |  		if (!initialize_ssl(ebuf, sizeof(ebuf))) {
 | 
	
		
			
				|  |  |  			mg_cry_ctx_internal(phys_ctx, "%s", ebuf);
 | 
	
	
		
			
				|  | @@ -16762,11 +16800,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 | 
	
		
			
				|  |  |  		return 0;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* If a certificate chain is configured, use it. */
 | 
	
		
			
				|  |  |  	chain = dom_ctx->config[SSL_CERTIFICATE_CHAIN];
 | 
	
		
			
				|  |  |  	if (chain == NULL) {
 | 
	
		
			
				|  |  | +		/* Default: certificate chain in PEM file */
 | 
	
		
			
				|  |  |  		chain = pem;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	if ((chain != NULL) && (*chain == 0)) {
 | 
	
		
			
				|  |  | +		/* If the chain is an empty string, don't use it. */
 | 
	
		
			
				|  |  |  		chain = NULL;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -18337,6 +18378,7 @@ init_connection(struct mg_connection *conn)
 | 
	
		
			
				|  |  |  	 * goes to crule42. */
 | 
	
		
			
				|  |  |  	conn->data_len = 0;
 | 
	
		
			
				|  |  |  	conn->handled_requests = 0;
 | 
	
		
			
				|  |  | +	conn->connection_type = CONNECTION_TYPE_INVALID;
 | 
	
		
			
				|  |  |  	mg_set_user_connection_data(conn, NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 |