# HG changeset patch
# User Pavel Pautov <p.pautov@f5.com>
# Date 1653379618 25200
#      Tue May 24 01:06:58 2022 -0700
# Node ID 9df5f780ce292b2cc338cd991b256f275dbe18f3
# Parent  35afae4b3dffff6718c0cab3ceb16b9de207c20a
SSL: reuse parent location context (ticket #1234).

diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -125,6 +125,7 @@ typedef struct {
     ngx_str_t                      ssl_trusted_certificate;
     ngx_str_t                      ssl_crl;
     ngx_array_t                   *ssl_conf_commands;
+    ngx_ssl_t                     *ssl_ctx;
 #endif
 } ngx_http_proxy_loc_conf_t;
 
@@ -3432,6 +3433,66 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
 }
 
 
+#if (NGX_HTTP_SSL)
+
+static void
+ngx_http_proxy_merge_ssl_conf(ngx_http_proxy_loc_conf_t *conf,
+                              ngx_http_proxy_loc_conf_t *prev)
+{
+    ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
+                              prev->upstream.ssl_session_reuse, 1);
+
+    ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
+                                 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
+                                  |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+
+    ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
+                             "DEFAULT");
+
+    ngx_conf_merge_ptr_value(conf->upstream.ssl_name,
+                              prev->upstream.ssl_name, NULL);
+    ngx_conf_merge_value(conf->upstream.ssl_server_name,
+                              prev->upstream.ssl_server_name, 0);
+    ngx_conf_merge_value(conf->upstream.ssl_verify,
+                              prev->upstream.ssl_verify, 0);
+    ngx_conf_merge_uint_value(conf->ssl_verify_depth,
+                              prev->ssl_verify_depth, 1);
+    ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
+                              prev->ssl_trusted_certificate, "");
+    ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
+
+    ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate,
+                              prev->upstream.ssl_certificate, NULL);
+    ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
+                              prev->upstream.ssl_certificate_key, NULL);
+    ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords,
+                              prev->upstream.ssl_passwords, NULL);
+
+    ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
+                              prev->ssl_conf_commands, NULL);
+}
+
+
+/* TODO: implement this directly, without ngx_http_proxy_set_ssl() */
+static ngx_ssl_t *
+ngx_http_proxy_create_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf)
+{
+    ngx_ssl_t  *ssl;
+
+    if (ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
+        conf->upstream.ssl = NULL;
+        return NULL;
+    }
+
+    ssl = conf->upstream.ssl;
+    conf->upstream.ssl = NULL;
+
+    return ssl;
+}
+
+#endif
+
+
 static char *
 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 {
@@ -3440,6 +3501,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
     u_char                     *p;
     size_t                      size;
+    unsigned                    reuse_ssl_ctx;
     ngx_int_t                   rc;
     ngx_hash_init_t             hash;
     ngx_http_core_loc_conf_t   *clcf;
@@ -3720,42 +3782,41 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
 #if (NGX_HTTP_SSL)
 
-    ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
-                              prev->upstream.ssl_session_reuse, 1);
-
-    ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
-                                 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                                  |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
-
-    ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
-                             "DEFAULT");
-
-    ngx_conf_merge_ptr_value(conf->upstream.ssl_name,
-                              prev->upstream.ssl_name, NULL);
-    ngx_conf_merge_value(conf->upstream.ssl_server_name,
-                              prev->upstream.ssl_server_name, 0);
-    ngx_conf_merge_value(conf->upstream.ssl_verify,
-                              prev->upstream.ssl_verify, 0);
-    ngx_conf_merge_uint_value(conf->ssl_verify_depth,
-                              prev->ssl_verify_depth, 1);
-    ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
-                              prev->ssl_trusted_certificate, "");
-    ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
-
-    ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate,
-                              prev->upstream.ssl_certificate, NULL);
-    ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
-                              prev->upstream.ssl_certificate_key, NULL);
-    ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords,
-                              prev->upstream.ssl_passwords, NULL);
-
-    ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
-                              prev->ssl_conf_commands, NULL);
-
-    if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
+    reuse_ssl_ctx = conf->upstream.ssl_session_reuse == NGX_CONF_UNSET
+        && conf->ssl_protocols == 0
+        && conf->ssl_ciphers.data == NULL
+        && conf->upstream.ssl_verify == NGX_CONF_UNSET
+        && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT
+        && conf->ssl_trusted_certificate.data == NULL
+        && conf->ssl_crl.data == NULL
+        && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR
+        && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR
+        && conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR
+        && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR;
+
+    ngx_http_proxy_merge_ssl_conf(conf, prev);
+
+    /* ensure SSL context for "http" section */
+    if (prev->ssl_ctx == NULL) {
+        /* ensure all values are set */
+        ngx_http_proxy_merge_ssl_conf(prev, prev);
+
+        prev->ssl_ctx = ngx_http_proxy_create_ssl(cf, prev);
+        if (prev->ssl_ctx == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    conf->ssl_ctx = reuse_ssl_ctx ? prev->ssl_ctx :
+                                    ngx_http_proxy_create_ssl(cf, conf);
+    if (conf->ssl_ctx == NULL) {
         return NGX_CONF_ERROR;
     }
 
+    if (conf->ssl) {
+        conf->upstream.ssl = conf->ssl_ctx;
+    }
+
 #endif
 
     ngx_conf_merge_ptr_value(conf->method, prev->method, NULL);
