|
diff --git a/auto/sources b/auto/sources |
|
index 3d89e2d..8969d61 100644 |
|
--- a/auto/sources |
|
+++ b/auto/sources |
|
@@ -86,7 +86,8 @@ REGEX_SRCS=src/core/ngx_regex.c |
|
OPENSSL_MODULE=ngx_openssl_module |
|
OPENSSL_DEPS=src/event/ngx_event_openssl.h |
|
OPENSSL_SRCS="src/event/ngx_event_openssl.c \ |
|
- src/event/ngx_event_openssl_stapling.c" |
|
+ src/event/ngx_event_openssl_stapling.c \ |
|
+ src/event/ngx_event_scache_sync.c" |
|
|
|
|
|
EVENT_MODULES="ngx_events_module ngx_event_core_module" |
|
@@ -419,9 +420,10 @@ HTTP_REWRITE_MODULE=ngx_http_rewrite_module |
|
HTTP_REWRITE_SRCS=src/http/modules/ngx_http_rewrite_module.c |
|
|
|
|
|
-HTTP_SSL_MODULE=ngx_http_ssl_module |
|
+HTTP_SSL_MODULE="ngx_http_ssl_module ngx_http_scache_sync_module" |
|
HTTP_SSL_DEPS=src/http/modules/ngx_http_ssl_module.h |
|
-HTTP_SSL_SRCS=src/http/modules/ngx_http_ssl_module.c |
|
+HTTP_SSL_SRCS="src/http/modules/ngx_http_ssl_module.c \ |
|
+ src/http/modules/ngx_http_scache_sync_module.c" |
|
|
|
|
|
HTTP_PROXY_MODULE=ngx_http_proxy_module |
|
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c |
|
index 1b789e6..a562674 100644 |
|
--- a/src/event/ngx_event_openssl.c |
|
+++ b/src/event/ngx_event_openssl.c |
|
@@ -41,8 +41,6 @@ static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, |
|
static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, |
|
u_char *id, int len, int *copy); |
|
static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); |
|
-static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, |
|
- ngx_slab_pool_t *shpool, ngx_uint_t n); |
|
static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, |
|
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
|
|
|
@@ -103,6 +101,7 @@ int ngx_ssl_session_cache_index; |
|
int ngx_ssl_session_ticket_keys_index; |
|
int ngx_ssl_certificate_index; |
|
int ngx_ssl_stapling_index; |
|
+int ngx_ssl_scache_sync_index; |
|
|
|
|
|
ngx_int_t |
|
@@ -184,6 +183,13 @@ ngx_ssl_init(ngx_log_t *log) |
|
return NGX_ERROR; |
|
} |
|
|
|
+ ngx_ssl_scache_sync_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); |
|
+ if (ngx_ssl_scache_sync_index == -1) { |
|
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0, |
|
+ "SSL_CTX_get_ex_new_index() failed"); |
|
+ return NGX_ERROR; |
|
+ } |
|
+ |
|
return NGX_OK; |
|
} |
|
|
|
@@ -2401,6 +2407,14 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) |
|
|
|
ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node); |
|
|
|
+ { |
|
+ SSL_SESSION_set_app_data(sess, (char*)ssl_conn); |
|
+ |
|
+ ngx_str_t key = { session_id_length, id }; |
|
+ ngx_str_t value = { len, cached_sess }; |
|
+ ngx_ssl_scache_sync_add_session(ssl_conn, &key, &value); |
|
+ } |
|
+ |
|
ngx_shmtx_unlock(&shpool->mutex); |
|
|
|
return 0; |
|
@@ -2497,6 +2511,8 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, |
|
p = buf; |
|
sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); |
|
|
|
+ SSL_SESSION_set_app_data(sess, (char*)ssl_conn); |
|
+ |
|
return sess; |
|
} |
|
|
|
@@ -2617,11 +2633,19 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) |
|
|
|
done: |
|
|
|
+ { |
|
+ ngx_ssl_conn_t* ssl_conn = (ngx_ssl_conn_t*)SSL_SESSION_get_app_data(sess); |
|
+ if (ssl_conn != NULL) { |
|
+ ngx_str_t key = { len, id }; |
|
+ ngx_ssl_scache_sync_remove_session(ssl_conn, &key); |
|
+ } |
|
+ } |
|
+ |
|
ngx_shmtx_unlock(&shpool->mutex); |
|
} |
|
|
|
|
|
-static void |
|
+void |
|
ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, |
|
ngx_slab_pool_t *shpool, ngx_uint_t n) |
|
{ |
|
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h |
|
index 08eff64..d5d11cf 100644 |
|
--- a/src/event/ngx_event_openssl.h |
|
+++ b/src/event/ngx_event_openssl.h |
|
@@ -145,6 +145,15 @@ ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, |
|
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); |
|
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, |
|
ngx_uint_t flags); |
|
+void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, |
|
+ ngx_slab_pool_t *shpool, ngx_uint_t n); |
|
+ngx_int_t ngx_ssl_scache_sync_init(ngx_conf_t *cf, SSL_CTX *ssl_ctx); |
|
+ngx_int_t ngx_ssl_scache_sync_add_peer(ngx_conf_t *cf, SSL_CTX *ssl_ctx, |
|
+ ngx_str_t *peer_url); |
|
+void ngx_ssl_scache_sync_add_session(ngx_ssl_conn_t *ssl_conn, ngx_str_t *key, |
|
+ ngx_str_t *value); |
|
+void ngx_ssl_scache_sync_remove_session(ngx_ssl_conn_t *ssl_conn, |
|
+ ngx_str_t *key); |
|
|
|
void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); |
|
ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); |
|
@@ -210,6 +219,7 @@ extern int ngx_ssl_session_cache_index; |
|
extern int ngx_ssl_session_ticket_keys_index; |
|
extern int ngx_ssl_certificate_index; |
|
extern int ngx_ssl_stapling_index; |
|
+extern int ngx_ssl_scache_sync_index; |
|
|
|
|
|
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */ |
|
diff --git a/src/event/ngx_event_scache_sync.c b/src/event/ngx_event_scache_sync.c |
|
new file mode 100644 |
|
index 0000000..2a4e94b |
|
--- /dev/null |
|
+++ b/src/event/ngx_event_scache_sync.c |
|
@@ -0,0 +1,947 @@ |
|
+#include <ngx_config.h> |
|
+#include <ngx_core.h> |
|
+#include <ngx_event.h> |
|
+#include <ngx_event_connect.h> |
|
+ |
|
+ |
|
+typedef enum { |
|
+ NGX_SSL_SCACHE_SYNC_OP_UNKNOWN, |
|
+ NGX_SSL_SCACHE_SYNC_OP_ADD, |
|
+ NGX_SSL_SCACHE_SYNC_OP_REMOVE, |
|
+} ngx_ssl_scache_sync_operation_t; |
|
+ |
|
+ |
|
+typedef struct ngx_ssl_scache_sync_peer_s ngx_ssl_scache_sync_peer_t; |
|
+ |
|
+ |
|
+typedef struct { |
|
+ ngx_ssl_scache_sync_peer_t *sp; |
|
+ |
|
+ ngx_buf_t *request; |
|
+ ngx_buf_t *response; |
|
+ |
|
+ ngx_pool_t *pool; |
|
+ ngx_log_t *log; |
|
+} ngx_ssl_scache_sync_ctx_t; |
|
+ |
|
+ |
|
+typedef struct { |
|
+ ngx_ssl_scache_sync_operation_t op; |
|
+ in_addr_t addr; |
|
+ in_port_t port; |
|
+ ngx_str_t server; |
|
+ ngx_str_t key; |
|
+ ngx_str_t value; |
|
+ |
|
+ ngx_queue_t queue; |
|
+ |
|
+ ngx_pool_t *pool; |
|
+ ngx_log_t *log; |
|
+} ngx_ssl_scache_sync_command_t; |
|
+ |
|
+ |
|
+struct ngx_ssl_scache_sync_peer_s { |
|
+ ngx_addr_t *addrs; |
|
+ ngx_str_t host; |
|
+ ngx_str_t uri; |
|
+ in_port_t port; |
|
+ ngx_msec_t timeout; |
|
+ |
|
+ ngx_peer_connection_t peer; |
|
+ |
|
+ ngx_queue_t commands; |
|
+ size_t n_commands; |
|
+ size_t max_commands; |
|
+ |
|
+ ngx_queue_t queue; |
|
+}; |
|
+ |
|
+ |
|
+typedef struct { |
|
+ ngx_queue_t peers; |
|
+} ngx_ssl_scache_sync_t; |
|
+ |
|
+ |
|
+static void ngx_ssl_scache_sync_start(ngx_ssl_conn_t *ssl_conn, ngx_str_t *key, |
|
+ ngx_str_t *value, ngx_ssl_scache_sync_operation_t op); |
|
+static ngx_ssl_scache_sync_command_t * ngx_ssl_scache_sync_create_command(void); |
|
+static ngx_ssl_scache_sync_ctx_t * ngx_ssl_scache_sync_create_context( |
|
+ ngx_ssl_scache_sync_peer_t* sp); |
|
+static u_char * ngx_ssl_scache_sync_log_error(ngx_log_t *log, u_char *buf, |
|
+ size_t len); |
|
+static ngx_int_t ngx_ssl_scache_sync_create_request( |
|
+ ngx_ssl_scache_sync_ctx_t *ctx); |
|
+static void ngx_ssl_scache_sync_post_request(ngx_ssl_scache_sync_peer_t *sp); |
|
+static void ngx_ssl_scache_sync_connect(ngx_ssl_scache_sync_ctx_t *ctx); |
|
+static void ngx_ssl_scache_sync_setup_connection(ngx_ssl_scache_sync_ctx_t *ctx); |
|
+static void ngx_ssl_scache_sync_write_handler(ngx_event_t *wev); |
|
+static void ngx_ssl_scache_sync_read_handler(ngx_event_t *rev); |
|
+static ngx_int_t ngx_ssl_scache_sync_process_response( |
|
+ ngx_ssl_scache_sync_ctx_t *ctx); |
|
+static void ngx_ssl_scache_sync_keep_connection(ngx_ssl_scache_sync_peer_t *sp); |
|
+static void ngx_ssl_scache_sync_dummy_handler(ngx_event_t *ev); |
|
+static int ngx_ssl_scache_sync_is_closed(ngx_connection_t *c); |
|
+static void ngx_ssl_scache_sync_close_check_handler(ngx_event_t *ev); |
|
+static void ngx_ssl_scache_sync_error(ngx_ssl_scache_sync_ctx_t *ctx); |
|
+static void ngx_ssl_scache_sync_destroy_command( |
|
+ ngx_ssl_scache_sync_command_t *cmd); |
|
+static void ngx_ssl_scache_sync_destroy_context(ngx_ssl_scache_sync_ctx_t *ctx); |
|
+static void ngx_ssl_scache_sync_close_connection( |
|
+ ngx_ssl_scache_sync_peer_t *sp); |
|
+ |
|
+ |
|
+ngx_int_t |
|
+ngx_ssl_scache_sync_init(ngx_conf_t *cf, SSL_CTX *ssl_ctx) |
|
+{ |
|
+ ngx_ssl_scache_sync_t *scache; |
|
+ |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cf->log, 0, |
|
+ "ngx_ssl_scache_sync_init"); |
|
+ |
|
+ scache = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_scache_sync_t)); |
|
+ if (scache == NULL) |
|
+ return NGX_ERROR; |
|
+ |
|
+ ngx_queue_init(&scache->peers); |
|
+ |
|
+ if (SSL_CTX_set_ex_data(ssl_ctx, ngx_ssl_scache_sync_index, scache) == 0) { |
|
+ ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, |
|
+ "SSL_CTX_set_ex_data() failed"); |
|
+ return NGX_ERROR; |
|
+ } |
|
+ |
|
+ return NGX_OK; |
|
+} |
|
+ |
|
+ |
|
+ngx_int_t |
|
+ngx_ssl_scache_sync_add_peer(ngx_conf_t *cf, SSL_CTX *ssl_ctx, ngx_str_t *peer_url) |
|
+{ |
|
+ ngx_ssl_scache_sync_t *scache; |
|
+ ngx_url_t url; |
|
+ ngx_ssl_scache_sync_peer_t *sp; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cf->log, 0, |
|
+ "ngx_ssl_scache_sync_add_peer: %V", |
|
+ peer_url); |
|
+ |
|
+ scache = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_scache_sync_index); |
|
+ |
|
+ ngx_memzero(&url, sizeof(ngx_url_t)); |
|
+ |
|
+ url.url = *peer_url; |
|
+ url.default_port = 80; |
|
+ |
|
+ if (ngx_parse_url(cf->pool, &url) != NGX_OK) { |
|
+ ngx_log_error(NGX_LOG_ERR, cf->log, 0, |
|
+ "failed to parse URL in scache_sync_peer: \"%V\"", |
|
+ &url.url); |
|
+ return NGX_ERROR; |
|
+ } |
|
+ |
|
+ sp = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_scache_sync_peer_t)); |
|
+ if (sp == NULL) |
|
+ return NGX_ERROR; |
|
+ |
|
+ sp->addrs = url.addrs; |
|
+ sp->host = url.host; |
|
+ sp->uri = url.uri; |
|
+ sp->port = url.port; |
|
+ sp->timeout = 1000; |
|
+ sp->max_commands = 1000; |
|
+ |
|
+ if (sp->uri.len == 0) { |
|
+ ngx_str_set(&sp->uri, "/"); |
|
+ } |
|
+ |
|
+ ngx_queue_init(&sp->commands); |
|
+ ngx_queue_insert_tail(&scache->peers, &sp->queue); |
|
+ |
|
+ return NGX_OK; |
|
+} |
|
+ |
|
+ |
|
+void |
|
+ngx_ssl_scache_sync_add_session(ngx_ssl_conn_t *ssl_conn, |
|
+ ngx_str_t *key, |
|
+ ngx_str_t *value) |
|
+{ |
|
+ ngx_ssl_scache_sync_start(ssl_conn, key, value, |
|
+ NGX_SSL_SCACHE_SYNC_OP_ADD); |
|
+} |
|
+ |
|
+ |
|
+void |
|
+ngx_ssl_scache_sync_remove_session(ngx_ssl_conn_t *ssl_conn, |
|
+ ngx_str_t *key) |
|
+{ |
|
+ ngx_str_t value = ngx_null_string; |
|
+ ngx_ssl_scache_sync_start(ssl_conn, key, &value, |
|
+ NGX_SSL_SCACHE_SYNC_OP_REMOVE); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_start(ngx_ssl_conn_t *ssl_conn, |
|
+ ngx_str_t *key, |
|
+ ngx_str_t *value, |
|
+ ngx_ssl_scache_sync_operation_t op) |
|
+{ |
|
+ SSL_CTX *ssl_ctx; |
|
+ ngx_ssl_scache_sync_t *scache; |
|
+ ngx_ssl_scache_sync_peer_t *sp; |
|
+ ngx_queue_t *q; |
|
+ ngx_str_t servername; |
|
+ ngx_connection_t *c; |
|
+ ngx_ssl_scache_sync_command_t *cmd; |
|
+ |
|
+ ssl_ctx = SSL_get_SSL_CTX(ssl_conn); |
|
+ scache = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_scache_sync_index); |
|
+ if (scache == NULL) |
|
+ return; |
|
+ |
|
+ /* Get address:port */ |
|
+ c = ngx_ssl_get_connection(ssl_conn); |
|
+ if (c->local_sockaddr->sa_family != AF_INET) |
|
+ return; |
|
+ struct sockaddr_in *sockaddr = (struct sockaddr_in *)c->local_sockaddr; |
|
+ in_addr_t addr = sockaddr->sin_addr.s_addr; |
|
+ in_port_t port = sockaddr->sin_port; |
|
+ |
|
+ /* Get server name */ |
|
+ servername.data = (u_char *)SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); |
|
+ if (servername.data != NULL) |
|
+ servername.len = ngx_strlen(servername.data); |
|
+ else |
|
+ servername.len = 0; |
|
+ |
|
+ /* Post request */ |
|
+ for (q = ngx_queue_head(&scache->peers); |
|
+ q != ngx_queue_sentinel(&scache->peers); |
|
+ q = ngx_queue_next(q)) |
|
+ { |
|
+ sp = ngx_queue_data(q, ngx_ssl_scache_sync_peer_t, queue); |
|
+ |
|
+ if (sp->n_commands == sp->max_commands) { |
|
+ ngx_log_error(NGX_LOG_WARN, c->log, 0, |
|
+ "Dropping scache sync command: queue is full"); |
|
+ continue; |
|
+ } |
|
+ |
|
+ cmd = ngx_ssl_scache_sync_create_command(); |
|
+ if (cmd == NULL) |
|
+ continue; |
|
+ |
|
+ cmd->op = op; |
|
+ |
|
+ cmd->addr = addr; |
|
+ cmd->port = port; |
|
+ |
|
+ cmd->server.len = servername.len; |
|
+ cmd->server.data = ngx_pstrdup(cmd->pool, &servername); |
|
+ if (cmd->server.data == NULL) { |
|
+ ngx_ssl_scache_sync_destroy_command(cmd); |
|
+ return; |
|
+ } |
|
+ |
|
+ cmd->key.len = key->len; |
|
+ cmd->key.data = ngx_pstrdup(cmd->pool, key); |
|
+ if (cmd->key.data == NULL) { |
|
+ ngx_ssl_scache_sync_destroy_command(cmd); |
|
+ return; |
|
+ } |
|
+ |
|
+ cmd->value.len = value->len; |
|
+ cmd->value.data = ngx_pstrdup(cmd->pool, value); |
|
+ if (cmd->value.data == NULL) { |
|
+ ngx_ssl_scache_sync_destroy_command(cmd); |
|
+ return; |
|
+ } |
|
+ |
|
+ ngx_queue_insert_tail(&sp->commands, &cmd->queue); |
|
+ sp->n_commands += 1; |
|
+ ngx_ssl_scache_sync_post_request(sp); |
|
+ } |
|
+} |
|
+ |
|
+ |
|
+static ngx_ssl_scache_sync_command_t * |
|
+ngx_ssl_scache_sync_create_command(void) |
|
+{ |
|
+ ngx_pool_t *pool; |
|
+ ngx_log_t *log; |
|
+ ngx_ssl_scache_sync_command_t *cmd; |
|
+ |
|
+ pool = ngx_create_pool(1024, ngx_cycle->log); |
|
+ if (pool == NULL) |
|
+ return NULL; |
|
+ |
|
+ cmd = ngx_pcalloc(pool, sizeof(ngx_ssl_scache_sync_command_t)); |
|
+ if (cmd == NULL) { |
|
+ ngx_destroy_pool(pool); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ log = ngx_palloc(pool, sizeof(ngx_log_t)); |
|
+ if (log == NULL) { |
|
+ ngx_destroy_pool(pool); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ cmd->pool = pool; |
|
+ |
|
+ *log = *cmd->pool->log; |
|
+ |
|
+ cmd->pool->log = log; |
|
+ cmd->log = log; |
|
+ |
|
+ log->handler = ngx_ssl_scache_sync_log_error; |
|
+ log->data = cmd; |
|
+ log->action = "ssl session cache sync"; |
|
+ |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cmd->log, 0, |
|
+ "ngx_ssl_scache_sync_create_command"); |
|
+ return cmd; |
|
+} |
|
+ |
|
+ |
|
+static u_char * |
|
+ngx_ssl_scache_sync_log_error(ngx_log_t *log, u_char *buf, size_t len) |
|
+{ |
|
+ u_char *p = buf; |
|
+ |
|
+ if (log->action) { |
|
+ p = ngx_snprintf(buf, len, " while %s", log->action); |
|
+ } |
|
+ |
|
+ return p; |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_post_request(ngx_ssl_scache_sync_peer_t *sp) |
|
+{ |
|
+ ngx_ssl_scache_sync_ctx_t *ctx; |
|
+ |
|
+ if (ngx_queue_empty(&sp->commands)) { |
|
+ /* No commands */ |
|
+ return; |
|
+ } |
|
+ |
|
+ if (sp->peer.connection == NULL) { |
|
+ /* peer is not connected */ |
|
+ |
|
+ ctx = ngx_ssl_scache_sync_create_context(sp); |
|
+ if (ctx == NULL) |
|
+ return; |
|
+ ngx_ssl_scache_sync_connect(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (sp->peer.connection->idle) { |
|
+ /* peer.connection is inactive */ |
|
+ |
|
+ ctx = ngx_ssl_scache_sync_create_context(sp); |
|
+ if (ctx == NULL) |
|
+ return; |
|
+ |
|
+ ngx_connection_t *c = sp->peer.connection; |
|
+ |
|
+ c->idle = 0; |
|
+ ngx_ssl_scache_sync_setup_connection(ctx); |
|
+ ngx_ssl_scache_sync_write_handler(c->write); |
|
+ return; |
|
+ } |
|
+ |
|
+ /* Here, peer.connection is active. |
|
+ * Nothing to do */ |
|
+ return; |
|
+} |
|
+ |
|
+ |
|
+static ngx_ssl_scache_sync_ctx_t * |
|
+ngx_ssl_scache_sync_create_context(ngx_ssl_scache_sync_peer_t* sp) |
|
+{ |
|
+ ngx_pool_t *pool; |
|
+ ngx_log_t *log; |
|
+ ngx_ssl_scache_sync_ctx_t *ctx; |
|
+ |
|
+ pool = ngx_create_pool(1024, ngx_cycle->log); |
|
+ if (pool == NULL) |
|
+ return NULL; |
|
+ |
|
+ ctx = ngx_pcalloc(pool, sizeof(ngx_ssl_scache_sync_ctx_t)); |
|
+ if (ctx == NULL) { |
|
+ ngx_destroy_pool(pool); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ log = ngx_palloc(pool, sizeof(ngx_log_t)); |
|
+ if (log == NULL) { |
|
+ ngx_destroy_pool(pool); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ ctx->pool = pool; |
|
+ |
|
+ *log = *ctx->pool->log; |
|
+ |
|
+ ctx->pool->log = log; |
|
+ ctx->log = log; |
|
+ |
|
+ log->handler = ngx_ssl_scache_sync_log_error; |
|
+ log->data = ctx; |
|
+ log->action = "ssl session cache sync"; |
|
+ |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
|
+ "ngx_ssl_scache_sync_create_context"); |
|
+ |
|
+ ctx->sp = sp; |
|
+ |
|
+ if (ngx_ssl_scache_sync_create_request(ctx) != NGX_OK) { |
|
+ ngx_destroy_pool(pool); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return ctx; |
|
+} |
|
+ |
|
+ |
|
+static size_t |
|
+ngx_num_digits(size_t n) |
|
+{ |
|
+ size_t d = 1; |
|
+ while (n >= 10) { |
|
+ n /= 10; |
|
+ ++d; |
|
+ } |
|
+ return d; |
|
+} |
|
+ |
|
+ |
|
+static ngx_int_t |
|
+ngx_ssl_scache_sync_create_request(ngx_ssl_scache_sync_ctx_t *ctx) |
|
+{ |
|
+ static const char REQUEST_LINE[] = "POST / HTTP/1.1"; |
|
+ static const char HOST[] = "Host: "; |
|
+ static const char CONTENT_LENGTH[] = "Content-Length: "; |
|
+ |
|
+ ngx_ssl_scache_sync_peer_t *sp = ctx->sp; |
|
+ ngx_str_t *host = &sp->host; |
|
+ u_char *p; |
|
+ ngx_buf_t *buf; |
|
+ ngx_queue_t *q; |
|
+ ngx_ssl_scache_sync_command_t *cmd; |
|
+ size_t body_len, request_len; |
|
+ |
|
+ /* Calculate length */ |
|
+ body_len = 0; |
|
+ for (q = ngx_queue_head(&sp->commands); |
|
+ q != ngx_queue_sentinel(&sp->commands); |
|
+ q = ngx_queue_next(q)) |
|
+ { |
|
+ cmd = ngx_queue_data(q, ngx_ssl_scache_sync_command_t, queue); |
|
+ |
|
+ ngx_log_debug5(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
|
+ "ngx_ssl_scache_sync_create_request: " |
|
+ "op=%d, addr=%uxD, port=%d, server=\"%V\", key=\"%V\"", |
|
+ (int)cmd->op, cmd->addr, (int)cmd->port, |
|
+ &cmd->server, &cmd->key); |
|
+ |
|
+ body_len += 1; /* opcode */ |
|
+ body_len += 4; /* addr */ |
|
+ body_len += 2; /* port */ |
|
+ body_len += 4; /* server_len */ |
|
+ body_len += 4; /* key_len */ |
|
+ body_len += 4; /* value_len */ |
|
+ body_len += cmd->server.len; |
|
+ body_len += cmd->key.len; |
|
+ body_len += cmd->value.len; |
|
+ } |
|
+ |
|
+ request_len = 0; |
|
+ request_len += sizeof(REQUEST_LINE) - 1 + sizeof(CRLF) - 1; |
|
+ request_len += sizeof(HOST) - 1 + host->len + sizeof(CRLF) - 1; |
|
+ request_len += sizeof(CONTENT_LENGTH) - 1 + ngx_num_digits(body_len) + sizeof(CRLF) - 1; |
|
+ request_len += sizeof(CRLF) - 1; |
|
+ request_len += body_len; |
|
+ |
|
+ buf = ngx_create_temp_buf(ctx->pool, request_len); |
|
+ if (buf == NULL) |
|
+ return NGX_ERROR; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
|
+ "ngx_ssl_scache_sync_create_request: body_len=%uz", |
|
+ body_len); |
|
+ |
|
+ p = buf->last; |
|
+ |
|
+ /* Request line */ |
|
+ p = ngx_cpymem(p, REQUEST_LINE, sizeof(REQUEST_LINE) - 1); |
|
+ *p++ = CR; *p++ = LF; |
|
+ |
|
+ /* Host */ |
|
+ p = ngx_cpymem(p, HOST, sizeof(HOST) - 1); |
|
+ p = ngx_cpymem(p, host->data, host->len); |
|
+ *p++ = CR; *p++ = LF; |
|
+ |
|
+ /* Content-Length */ |
|
+ p = ngx_cpymem(p, CONTENT_LENGTH, sizeof(CONTENT_LENGTH) - 1); |
|
+ p = ngx_sprintf(p, "%uz", body_len); |
|
+ *p++ = CR; *p++ = LF; |
|
+ |
|
+ /* End Of Header */ |
|
+ *p++ = CR; *p++ = LF; |
|
+ |
|
+ /* Body */ |
|
+ for (q = ngx_queue_head(&sp->commands); |
|
+ q != ngx_queue_sentinel(&sp->commands); |
|
+ q = ngx_queue_next(q)) |
|
+ { |
|
+ ngx_ssl_scache_sync_command_t *cmd; |
|
+ cmd = ngx_queue_data(q, ngx_ssl_scache_sync_command_t, queue); |
|
+ uint32_t n; |
|
+ |
|
+ *p++ = (uint8_t)cmd->op; |
|
+ |
|
+ n = htonl(cmd->addr); |
|
+ p = ngx_cpymem(p, &n, sizeof(uint32_t)); |
|
+ |
|
+ p = ngx_cpymem(p, &cmd->port, sizeof(uint16_t)); |
|
+ |
|
+ n = htonl(cmd->server.len); |
|
+ p = ngx_cpymem(p, &n, sizeof(uint32_t)); |
|
+ |
|
+ n = htonl(cmd->key.len); |
|
+ p = ngx_cpymem(p, &n, sizeof(uint32_t)); |
|
+ |
|
+ n = htonl(cmd->value.len); |
|
+ p = ngx_cpymem(p, &n, sizeof(uint32_t)); |
|
+ |
|
+ p = ngx_cpymem(p, cmd->server.data, cmd->server.len); |
|
+ p = ngx_cpymem(p, cmd->key.data, cmd->key.len); |
|
+ p = ngx_cpymem(p, cmd->value.data, cmd->value.len); |
|
+ } |
|
+ |
|
+ buf->last = p; |
|
+ ctx->request = buf; |
|
+ |
|
+ /* Remove commands */ |
|
+ q = ngx_queue_head(&sp->commands); |
|
+ while (q != ngx_queue_sentinel(&sp->commands)) { |
|
+ ngx_ssl_scache_sync_command_t *cmd; |
|
+ cmd = ngx_queue_data(q, ngx_ssl_scache_sync_command_t, queue); |
|
+ q = ngx_queue_next(q); |
|
+ ngx_ssl_scache_sync_destroy_command(cmd); |
|
+ } |
|
+ ngx_queue_init(&sp->commands); |
|
+ sp->n_commands = 0; |
|
+ |
|
+ return NGX_OK; |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_connect(ngx_ssl_scache_sync_ctx_t *ctx) |
|
+{ |
|
+ ngx_int_t rc; |
|
+ ngx_ssl_scache_sync_peer_t *sp = ctx->sp; |
|
+ |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
|
+ "ngx_ssl_scache_sync_connect"); |
|
+ |
|
+ ngx_memzero(&sp->peer, sizeof(sp->peer)); |
|
+ sp->peer.sockaddr = sp->addrs[0].sockaddr; |
|
+ sp->peer.socklen = sp->addrs[0].socklen; |
|
+ sp->peer.name = &sp->addrs[0].name; |
|
+ sp->peer.get = ngx_event_get_peer; |
|
+ sp->peer.log = ctx->log; |
|
+ sp->peer.log_error = NGX_ERROR_ERR; |
|
+ |
|
+ rc = ngx_event_connect_peer(&sp->peer); |
|
+ |
|
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
|
+ "ngx_ssl_scache_sync_connect: rc=%d, fd=%d", |
|
+ (int)rc, |
|
+ sp->peer.connection ? sp->peer.connection->fd : -1); |
|
+ |
|
+ if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { |
|
+ ngx_ssl_scache_sync_destroy_context(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ ngx_ssl_scache_sync_setup_connection(ctx); |
|
+ |
|
+ if (rc != NGX_OK) { |
|
+ /* rc == NGX_AGAIN */ |
|
+ return; |
|
+ } |
|
+ |
|
+ ngx_ssl_scache_sync_write_handler(sp->peer.connection->write); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_setup_connection(ngx_ssl_scache_sync_ctx_t *ctx) |
|
+{ |
|
+ ngx_ssl_scache_sync_peer_t *sp = ctx->sp; |
|
+ ngx_connection_t *c = sp->peer.connection; |
|
+ |
|
+ c->data = ctx; |
|
+ c->pool = ctx->pool; |
|
+ c->log = ctx->log; |
|
+ |
|
+ c->read->handler = ngx_ssl_scache_sync_read_handler; |
|
+ c->read->log = ctx->log; |
|
+ c->write->handler = ngx_ssl_scache_sync_write_handler; |
|
+ c->write->log = ctx->log; |
|
+ |
|
+ if (!c->read->timer_set) |
|
+ ngx_add_timer(c->read, sp->timeout); |
|
+ if (!c->read->timer_set) |
|
+ ngx_add_timer(c->write, sp->timeout); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_write_handler(ngx_event_t *wev) |
|
+{ |
|
+ ssize_t n, size; |
|
+ ngx_connection_t *c; |
|
+ ngx_ssl_scache_sync_ctx_t *ctx; |
|
+ |
|
+ c = wev->data; |
|
+ ctx = c->data; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, wev->log, 0, |
|
+ "ngx_ssl_scache_sync_write_handler: fd=%d", |
|
+ c->fd); |
|
+ |
|
+ if (wev->timedout) { |
|
+ ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, |
|
+ "SSL session cache sync timed out"); |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ size = ctx->request->last - ctx->request->pos; |
|
+ |
|
+ n = ngx_send(c, ctx->request->pos, size); |
|
+ |
|
+ if (n == NGX_ERROR) { |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (n > 0) { |
|
+ ctx->request->pos += n; |
|
+ |
|
+ if (n == size) { |
|
+ wev->handler = ngx_ssl_scache_sync_dummy_handler; |
|
+ |
|
+ if (wev->timer_set) |
|
+ ngx_del_timer(wev); |
|
+ |
|
+ if (ngx_handle_write_event(wev, 0) != NGX_OK) { |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (c->read->ready) |
|
+ ngx_ssl_scache_sync_read_handler(c->read); |
|
+ return; |
|
+ } |
|
+ } |
|
+ |
|
+ if (!wev->timer_set) |
|
+ ngx_add_timer(wev, ctx->sp->timeout); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_read_handler(ngx_event_t *rev) |
|
+{ |
|
+ ssize_t n, size; |
|
+ ngx_int_t rc; |
|
+ ngx_ssl_scache_sync_ctx_t *ctx; |
|
+ ngx_connection_t *c; |
|
+ |
|
+ c = rev->data; |
|
+ ctx = c->data; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, rev->log, 0, |
|
+ "ngx_ssl_scache_sync_read_handler: fd=%d", |
|
+ c->fd); |
|
+ |
|
+ if (rev->timedout) { |
|
+ ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, |
|
+ "SSL session cache sync timed out"); |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (ctx->response == NULL) { |
|
+ ctx->response = ngx_create_temp_buf(ctx->pool, 512); |
|
+ if (ctx->response == NULL) { |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ } |
|
+ |
|
+ for (;;) { |
|
+ size = ctx->response->end - ctx->response->last; |
|
+ |
|
+ n = ngx_recv(c, ctx->response->last, size); |
|
+ |
|
+ if (n > 0) { |
|
+ ctx->response->last += n; |
|
+ |
|
+ rc = ngx_ssl_scache_sync_process_response(ctx); |
|
+ |
|
+ if (rc == NGX_OK) { |
|
+ /* Connection: keep-alive */ |
|
+ ngx_ssl_scache_sync_peer_t* sp = ctx->sp; |
|
+ ngx_ssl_scache_sync_keep_connection(sp); |
|
+ ngx_ssl_scache_sync_destroy_context(ctx); |
|
+ ngx_ssl_scache_sync_post_request(sp); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (rc == NGX_DONE) { |
|
+ /* Connection: close */ |
|
+ ngx_ssl_scache_sync_peer_t* sp = ctx->sp; |
|
+ |
|
+ ngx_ssl_scache_sync_close_connection(sp); |
|
+ ngx_ssl_scache_sync_destroy_context(ctx); |
|
+ if (ngx_queue_empty(&sp->commands)) { |
|
+ /* No waiting commands */ |
|
+ return; |
|
+ } |
|
+ /* Reconnect to process the next request */ |
|
+ ctx = ngx_ssl_scache_sync_create_context(sp); |
|
+ if (ctx == NULL) |
|
+ return; |
|
+ ngx_ssl_scache_sync_connect(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (rc == NGX_ERROR) { |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ |
|
+ /* rc == NGX_AGAIN */ |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (n == NGX_AGAIN) { |
|
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+ return; |
|
+ } |
|
+ return; |
|
+ } |
|
+ |
|
+ /* n == 0 */ |
|
+ break; |
|
+ } |
|
+ |
|
+ /* connection closed */ |
|
+ |
|
+ /* rc == NGX_ERROR or NGX_AGAIN */ |
|
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0, |
|
+ "SSL session cache sync peer prematurely closed connection"); |
|
+ ngx_ssl_scache_sync_error(ctx); |
|
+} |
|
+ |
|
+ |
|
+static ngx_int_t |
|
+ngx_ssl_scache_sync_process_response(ngx_ssl_scache_sync_ctx_t *ctx) |
|
+{ |
|
+ static char END_OF_HEADER[] = CRLF CRLF; |
|
+ static char CONNECTION[] = CRLF "Connection:"; |
|
+ static char CONTENT_LENGTH[] = CRLF "Content-Length:"; |
|
+ static u_char CLOSE[] = "close"; |
|
+ u_char *p = NULL; |
|
+ size_t content_len = 0; |
|
+ |
|
+ size_t len = ctx->response->last - ctx->response->pos; |
|
+ u_char* eoh = ngx_strnstr(ctx->response->pos, END_OF_HEADER, len); |
|
+ if (eoh == NULL) |
|
+ return NGX_AGAIN; |
|
+ *eoh = '\0'; |
|
+ |
|
+ size_t header_len = eoh - ctx->response->pos + sizeof(END_OF_HEADER) - 1; |
|
+ |
|
+ u_char* len_pos = ngx_strcasestrn( |
|
+ ctx->response->pos, CONTENT_LENGTH, sizeof(CONTENT_LENGTH) - 1); |
|
+ if (len_pos != NULL) { |
|
+ p = len_pos + sizeof(CONTENT_LENGTH) - 1; |
|
+ while (*p == ' ' || *p == '\t') |
|
+ ++p; |
|
+ for (; isdigit(*p); ++p) |
|
+ content_len = content_len * 10 + (*p - '0'); |
|
+ } |
|
+ |
|
+ if (len < header_len + content_len) { |
|
+ *eoh = CR; |
|
+ return NGX_AGAIN; |
|
+ } |
|
+ |
|
+ u_char* conn_pos = ngx_strcasestrn( |
|
+ ctx->response->pos, CONNECTION, sizeof(CONNECTION) - 1); |
|
+ if (conn_pos == NULL) |
|
+ goto keep; |
|
+ p = conn_pos + sizeof(CONNECTION) - 1; |
|
+ while (*p == ' ' || *p == '\t') |
|
+ ++p; |
|
+ if (ngx_strncasecmp(p, CLOSE, sizeof(CLOSE) - 1) != 0) |
|
+ goto keep; |
|
+ p += sizeof(CLOSE) - 1; |
|
+ while (*p == ' ' || *p == '\t') |
|
+ ++p; |
|
+ if (*p != '\0' && *p != CR && *p != LF) |
|
+ goto keep; |
|
+ |
|
+ /* Connection: close */ |
|
+ ctx->response->pos += header_len + content_len; |
|
+ return NGX_DONE; |
|
+ |
|
+keep: |
|
+ /* Connection: keep-alive */ |
|
+ ctx->response->pos += header_len + content_len; |
|
+ return NGX_OK; |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_keep_connection(ngx_ssl_scache_sync_peer_t *sp) |
|
+{ |
|
+ ngx_connection_t *c; |
|
+ |
|
+ c = sp->peer.connection; |
|
+ c->data = sp; |
|
+ |
|
+ if (c->read->timer_set) |
|
+ ngx_del_timer(c->read); |
|
+ if (c->write->timer_set) |
|
+ ngx_del_timer(c->write); |
|
+ |
|
+ c->write->handler = ngx_ssl_scache_sync_dummy_handler; |
|
+ c->write->log = ngx_cycle->log; |
|
+ c->read->handler = ngx_ssl_scache_sync_close_check_handler; |
|
+ c->read->log = ngx_cycle->log; |
|
+ |
|
+ c->log = ngx_cycle->log; |
|
+ c->write->log = ngx_cycle->log; |
|
+ c->pool->log = ngx_cycle->log; |
|
+ c->idle = 1; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, sp->peer.connection->log, 0, |
|
+ "ngx_ssl_scache_sync_keep_connection: fd=%d", |
|
+ sp->peer.connection->fd); |
|
+ |
|
+ if (c->read->ready) |
|
+ c->read->handler(c->read); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_dummy_handler(ngx_event_t *ev) |
|
+{ |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, |
|
+ "ngx_ssl_scache_sync_dummy_handler"); |
|
+} |
|
+ |
|
+ |
|
+static int |
|
+ngx_ssl_scache_sync_is_closed(ngx_connection_t *c) |
|
+{ |
|
+ ssize_t n; |
|
+ char buf[1]; |
|
+ |
|
+ if (c->close) |
|
+ return 1; |
|
+ |
|
+ n = recv(c->fd, buf, 1, MSG_PEEK); |
|
+ |
|
+ if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { |
|
+ /* stale event */ |
|
+ |
|
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) |
|
+ return 1; |
|
+ |
|
+ return 0; |
|
+ } |
|
+ |
|
+ return 1; |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_close_check_handler(ngx_event_t *ev) |
|
+{ |
|
+ ngx_connection_t *c = ev->data; |
|
+ ngx_ssl_scache_sync_peer_t *sp = c->data; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, |
|
+ "ngx_ssl_scache_sync_close_check_handler_for_cache: " |
|
+ "fd=%d", |
|
+ c->fd); |
|
+ |
|
+ if (!ngx_ssl_scache_sync_is_closed(c)) |
|
+ return; |
|
+ |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, |
|
+ "ngx_ssl_scache_sync_close_check_handler_for_cache: " |
|
+ "connection closed"); |
|
+ |
|
+ ngx_ssl_scache_sync_close_connection(sp); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_error(ngx_ssl_scache_sync_ctx_t *ctx) |
|
+{ |
|
+ ngx_ssl_scache_sync_peer_t *sp = ctx->sp; |
|
+ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
|
+ "ngx_ssl_scache_sync_error: fd=%d", |
|
+ sp->peer.connection->fd); |
|
+ |
|
+ ngx_ssl_scache_sync_close_connection(sp); |
|
+ ngx_ssl_scache_sync_destroy_context(ctx); |
|
+ |
|
+ if (ngx_queue_empty(&sp->commands)) { |
|
+ /* No waiting requests */ |
|
+ return; |
|
+ } |
|
+ /* Reconnect for next request */ |
|
+ ngx_ssl_scache_sync_post_request(sp); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_destroy_command(ngx_ssl_scache_sync_command_t *cmd) |
|
+{ |
|
+ ngx_destroy_pool(cmd->pool); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_destroy_context(ngx_ssl_scache_sync_ctx_t *ctx) |
|
+{ |
|
+ ngx_destroy_pool(ctx->pool); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_ssl_scache_sync_close_connection(ngx_ssl_scache_sync_peer_t *sp) |
|
+{ |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, sp->peer.connection->log, 0, |
|
+ "ngx_ssl_scache_sync_close_connection: fd=%d", |
|
+ sp->peer.connection->fd); |
|
+ |
|
+ ngx_close_connection(sp->peer.connection); |
|
+ ngx_memzero(&sp->peer, sizeof(sp->peer)); |
|
+} |
|
diff --git a/src/http/modules/ngx_http_scache_sync_module.c b/src/http/modules/ngx_http_scache_sync_module.c |
|
new file mode 100644 |
|
index 0000000..c428ce5 |
|
--- /dev/null |
|
+++ b/src/http/modules/ngx_http_scache_sync_module.c |
|
@@ -0,0 +1,553 @@ |
|
+#include <ngx_config.h> |
|
+#include <ngx_core.h> |
|
+#include <ngx_http.h> |
|
+ |
|
+ |
|
+typedef struct { |
|
+ ngx_flag_t receive; |
|
+} ngx_http_scache_sync_srv_conf_t; |
|
+ |
|
+ |
|
+typedef enum { |
|
+ NGX_HTTP_SCACHE_SYNC_OP_UNKNOWN, |
|
+ NGX_HTTP_SCACHE_SYNC_OP_ADD, |
|
+ NGX_HTTP_SCACHE_SYNC_OP_REMOVE, |
|
+} ngx_http_scache_sync_operation_t; |
|
+ |
|
+ |
|
+static ngx_int_t ngx_http_scache_sync_handler(ngx_http_request_t *r); |
|
+static ngx_buf_t *ngx_http_scache_sync_get_request_body_buf( |
|
+ ngx_http_request_t *r); |
|
+static void ngx_http_scache_sync_body_handler(ngx_http_request_t *r); |
|
+static void ngx_http_scache_sync_do_operation(ngx_http_request_t *r, |
|
+ ngx_http_scache_sync_operation_t op, in_addr_t addr, in_port_t port, |
|
+ ngx_str_t *server, ngx_str_t *key, ngx_str_t *value); |
|
+static ngx_http_conf_addr_t * ngx_http_scache_sync_find_default_server( |
|
+ ngx_http_request_t *r, in_addr_t addr, in_port_t port); |
|
+static ngx_ssl_sess_id_t *ngx_http_scache_sync_find_session( |
|
+ ngx_str_t* key, uint32_t hash, ngx_ssl_session_cache_t *cache); |
|
+static void ngx_http_scache_sync_add_session(ngx_connection_t *c, |
|
+ SSL_CTX* ssl_ctx, ngx_str_t *key, ngx_str_t *value, |
|
+ ngx_shm_zone_t* shm_zone, ngx_ssl_session_cache_t* cache, uint32_t hash, |
|
+ ngx_slab_pool_t *shpool); |
|
+static ngx_int_t ngx_http_scache_sync_postconfig(ngx_conf_t *cf); |
|
+static void *ngx_http_scache_sync_create_srv_conf(ngx_conf_t *cf); |
|
+static char *ngx_http_scache_sync_merge_srv_conf(ngx_conf_t *cf, |
|
+ void *parent, void *child); |
|
+ |
|
+ |
|
+static ngx_command_t ngx_http_scache_sync_commands[] = { |
|
+ |
|
+ { ngx_string("ssl_session_cache_receive"), |
|
+ NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, |
|
+ ngx_conf_set_flag_slot, |
|
+ NGX_HTTP_SRV_CONF_OFFSET, |
|
+ offsetof(ngx_http_scache_sync_srv_conf_t, receive), |
|
+ NULL }, |
|
+ |
|
+ ngx_null_command |
|
+}; |
|
+ |
|
+ |
|
+static ngx_http_module_t ngx_http_scache_sync_module_ctx = { |
|
+ NULL, /* preconfiguration */ |
|
+ ngx_http_scache_sync_postconfig, /* postconfiguration */ |
|
+ |
|
+ NULL, /* create main configuration */ |
|
+ NULL, /* init main configuration */ |
|
+ |
|
+ ngx_http_scache_sync_create_srv_conf, /* create server configuration */ |
|
+ ngx_http_scache_sync_merge_srv_conf, /* merge server configuration */ |
|
+ |
|
+ NULL, /* create location configuration */ |
|
+ NULL /* merge location configuration */ |
|
+}; |
|
+ |
|
+ |
|
+ngx_module_t ngx_http_scache_sync_module = { |
|
+ NGX_MODULE_V1, |
|
+ &ngx_http_scache_sync_module_ctx, /* module context */ |
|
+ ngx_http_scache_sync_commands, /* module directives */ |
|
+ NGX_HTTP_MODULE, /* module type */ |
|
+ NULL, /* init master */ |
|
+ NULL, /* init module */ |
|
+ NULL, /* init process */ |
|
+ NULL, /* init thread */ |
|
+ NULL, /* exit thread */ |
|
+ NULL, /* exit process */ |
|
+ NULL, /* exit master */ |
|
+ NGX_MODULE_V1_PADDING |
|
+}; |
|
+ |
|
+ |
|
+#define ngx_http_scache_sync_str_equal(str, literal) \ |
|
+ ((str)->len == sizeof(literal) - 1 && \ |
|
+ ngx_strncasecmp((str)->data, (u_char *)(literal), sizeof(literal) - 1) == 0) |
|
+ |
|
+ |
|
+static ngx_int_t |
|
+ngx_http_scache_sync_handler(ngx_http_request_t *r) |
|
+{ |
|
+ ngx_int_t rc; |
|
+ ngx_http_scache_sync_srv_conf_t *scache_conf; |
|
+ |
|
+ scache_conf = ngx_http_get_module_srv_conf(r, ngx_http_scache_sync_module); |
|
+ if (!scache_conf->receive) |
|
+ return NGX_DECLINED; |
|
+ |
|
+ r->request_body_in_single_buf = 1; |
|
+ r->request_body_in_file_only = 0; |
|
+ |
|
+ rc = ngx_http_read_client_request_body(r, ngx_http_scache_sync_body_handler); |
|
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) |
|
+ return rc; |
|
+ |
|
+ return NGX_DONE; |
|
+} |
|
+ |
|
+ |
|
+static ngx_buf_t * |
|
+ngx_http_scache_sync_get_request_body_buf(ngx_http_request_t *r) |
|
+{ |
|
+ u_char *p; |
|
+ size_t len; |
|
+ ngx_buf_t *buf; |
|
+ ngx_chain_t *cl; |
|
+ ngx_buf_t *dest; |
|
+ |
|
+ if (r->request_body == NULL |
|
+ || r->request_body->bufs == NULL |
|
+ || r->request_body->temp_file) |
|
+ { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ cl = r->request_body->bufs; |
|
+ buf = cl->buf; |
|
+ |
|
+ if (cl->next == NULL) { |
|
+ return buf; |
|
+ } |
|
+ |
|
+ len = buf->last - buf->pos; |
|
+ cl = cl->next; |
|
+ |
|
+ for ( /* void */ ; cl; cl = cl->next) { |
|
+ buf = cl->buf; |
|
+ len += buf->last - buf->pos; |
|
+ } |
|
+ |
|
+ dest = ngx_create_temp_buf(r->pool, len); |
|
+ if (dest == NULL) { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ p = dest->start; |
|
+ cl = r->request_body->bufs; |
|
+ |
|
+ for ( /* void */ ; cl; cl = cl->next) { |
|
+ buf = cl->buf; |
|
+ p = ngx_cpymem(p, buf->pos, buf->last - buf->pos); |
|
+ } |
|
+ |
|
+ dest->last = p; |
|
+ return dest; |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_http_scache_sync_body_handler(ngx_http_request_t *r) |
|
+{ |
|
+ static const int COMMAND_HEADER_SIZE = 19; |
|
+ |
|
+ ngx_buf_t *b; |
|
+ |
|
+ b = ngx_http_scache_sync_get_request_body_buf(r); |
|
+ if (b == NULL) { |
|
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
|
+ return; |
|
+ } |
|
+ |
|
+ while (b->pos < b->last) { |
|
+ uint32_t n; |
|
+ ngx_http_scache_sync_operation_t op = NGX_HTTP_SCACHE_SYNC_OP_UNKNOWN; |
|
+ in_addr_t addr = 0; |
|
+ in_port_t port = 0; |
|
+ ngx_str_t server = ngx_null_string; |
|
+ ngx_str_t key = ngx_null_string; |
|
+ ngx_str_t value = ngx_null_string; |
|
+ |
|
+ if (b->last - b->pos < COMMAND_HEADER_SIZE) { |
|
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
|
+ return; |
|
+ } |
|
+ |
|
+ op = b->pos[0]; |
|
+ |
|
+ memcpy(&n, &b->pos[1], sizeof(in_addr_t)); |
|
+ addr = ntohl(n); |
|
+ |
|
+ memcpy(&port, &b->pos[5], sizeof(in_port_t)); |
|
+ |
|
+ memcpy(&n, &b->pos[7], sizeof(uint32_t)); |
|
+ server.len = ntohl(n); |
|
+ |
|
+ memcpy(&n, &b->pos[11], sizeof(uint32_t)); |
|
+ key.len = ntohl(n); |
|
+ |
|
+ memcpy(&n, &b->pos[15], sizeof(uint32_t)); |
|
+ value.len = ntohl(n); |
|
+ |
|
+ b->pos += COMMAND_HEADER_SIZE; |
|
+ |
|
+ if (b->last - b->pos < (ssize_t)server.len + (ssize_t)key.len + (ssize_t)value.len) { |
|
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
|
+ return; |
|
+ } |
|
+ |
|
+ server.data = b->pos; |
|
+ b->pos += server.len; |
|
+ |
|
+ key.data = b->pos; |
|
+ b->pos += key.len; |
|
+ |
|
+ value.data = b->pos; |
|
+ b->pos += value.len; |
|
+ |
|
+ ngx_http_scache_sync_do_operation(r, op, addr, port, &server, &key, &value); |
|
+ } |
|
+ |
|
+ ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_http_scache_sync_do_operation(ngx_http_request_t *r, |
|
+ ngx_http_scache_sync_operation_t op, |
|
+ in_addr_t addr, |
|
+ in_port_t port, |
|
+ ngx_str_t* server, |
|
+ ngx_str_t* key, |
|
+ ngx_str_t* value) |
|
+{ |
|
+ ngx_http_ssl_srv_conf_t *sscf; |
|
+ ngx_shm_zone_t *shm_zone; |
|
+ ngx_ssl_session_cache_t *cache; |
|
+ uint32_t hash; |
|
+ ngx_slab_pool_t *shpool; |
|
+ ngx_ssl_sess_id_t *sess_id; |
|
+ |
|
+ /* find virtual server */ |
|
+ |
|
+ ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: " |
|
+ "op=%d, addr=%d, port=%d, key='%V', value.len=%d", |
|
+ (int)op, (int)addr, (int)ntohs(port), key, (int)value->len); |
|
+ |
|
+ ngx_connection_t *c = r->connection; |
|
+ ngx_http_core_srv_conf_t *cscf = NULL; |
|
+ |
|
+ ngx_http_conf_addr_t *conf_addr; |
|
+ conf_addr = ngx_http_scache_sync_find_default_server(r, addr, port); |
|
+ |
|
+ if (conf_addr == NULL) { |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: not found"); |
|
+ return; |
|
+ } |
|
+ |
|
+ if (server->len != 0) { |
|
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: server='%V'", |
|
+ server); |
|
+ |
|
+ ngx_http_virtual_names_t virtual_names; |
|
+ |
|
+ ngx_memzero(&virtual_names, sizeof(ngx_http_virtual_names_t)); |
|
+ virtual_names.names.hash = conf_addr->hash; |
|
+ virtual_names.names.wc_head = conf_addr->wc_head; |
|
+ virtual_names.names.wc_tail = conf_addr->wc_tail; |
|
+#if (NGX_PCRE) |
|
+ virtual_names.nregex = conf_addr->nregex; |
|
+ virtual_names.regex = conf_addr->regex; |
|
+#endif |
|
+ |
|
+ if (ngx_http_find_virtual_server(c, &virtual_names, server, r, &cscf) |
|
+ == NGX_OK) |
|
+ { |
|
+ goto found; |
|
+ } |
|
+ } |
|
+ |
|
+ /* fallback to default server */ |
|
+ cscf = conf_addr->default_server; |
|
+ |
|
+found: |
|
+ sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module); |
|
+ |
|
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: cscf=%p, sscf=%p", |
|
+ cscf, sscf); |
|
+ |
|
+ if (sscf->ssl.ctx == NULL || sscf->shm_zone == NULL) { |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: ssl.ctx or shm_zone is null"); |
|
+ return; |
|
+ } |
|
+ |
|
+ shm_zone = sscf->shm_zone; |
|
+ |
|
+ cache = shm_zone->data; |
|
+ hash = ngx_crc32_short(key->data, key->len); |
|
+ shpool = (ngx_slab_pool_t*)shm_zone->shm.addr; |
|
+ |
|
+ ngx_shmtx_lock(&shpool->mutex); |
|
+ |
|
+ sess_id = ngx_http_scache_sync_find_session(key, hash, cache); |
|
+ |
|
+ if (sess_id != NULL) { |
|
+ /* Session cache found */ |
|
+ if (op == NGX_HTTP_SCACHE_SYNC_OP_REMOVE) { |
|
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, |
|
+ "ngx_http_scache_sync_module: remove ssl session: %08XD:%ud:%d", |
|
+ hash, key->len, value->len); |
|
+ |
|
+ ngx_queue_remove(&sess_id->queue); |
|
+ ngx_rbtree_delete(&cache->session_rbtree, (ngx_rbtree_node_t*)sess_id); |
|
+ ngx_slab_free_locked(shpool, sess_id->session); |
|
+#if (NGX_PTR_SIZE == 4) |
|
+ ngx_slab_free_locked(shpool, sess_id->id); |
|
+#endif |
|
+ ngx_slab_free_locked(shpool, sess_id); |
|
+ } else { |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: session cache already exists"); |
|
+ } |
|
+ } else { |
|
+ /* Session cache not found */ |
|
+ if (op == NGX_HTTP_SCACHE_SYNC_OP_ADD) { |
|
+ ngx_http_scache_sync_add_session( |
|
+ c, sscf->ssl.ctx, key, value, shm_zone, cache, hash, shpool); |
|
+ } else { |
|
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: session cache not found"); |
|
+ } |
|
+ } |
|
+ |
|
+ ngx_shmtx_unlock(&shpool->mutex); |
|
+} |
|
+ |
|
+ |
|
+static ngx_http_conf_addr_t * |
|
+ngx_http_scache_sync_find_default_server(ngx_http_request_t *r, in_addr_t addr, in_port_t port) |
|
+{ |
|
+ size_t i, n; |
|
+ ngx_http_core_main_conf_t *cmcf; |
|
+ ngx_http_conf_port_t *ports; |
|
+ ngx_http_conf_addr_t *conf_addrs; |
|
+ |
|
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_find_default_server: " |
|
+ "addr=%uxD, port=%d", |
|
+ addr, (int)ntohs(port)); |
|
+ |
|
+ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); |
|
+ |
|
+ ports = cmcf->ports->elts; |
|
+ for (i = 0; i < cmcf->ports->nelts; i++) { |
|
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: ports[%d]=%d, req.port=%d", |
|
+ (int)i, (int)ntohs(ports[i].port), (int)ntohs(port)); |
|
+ |
|
+ if (ports[i].port == port) |
|
+ break; |
|
+ } |
|
+ |
|
+ if (i == cmcf->ports->nelts) { |
|
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
|
+ "Default server for %uxD:%d is not found.", |
|
+ addr, (int)ntohs(port)); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ conf_addrs = ports[i].addrs.elts; |
|
+ n = ports[i].addrs.nelts; |
|
+ for (i = 0; i < n; ++i) { |
|
+ struct sockaddr *s = &conf_addrs[i].opt.u.sockaddr; |
|
+ if (s->sa_family != AF_INET) |
|
+ continue; |
|
+ struct sockaddr_in* sin = (struct sockaddr_in*)s; |
|
+ in_addr_t s_addr = sin->sin_addr.s_addr; |
|
+ |
|
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
|
+ "ngx_http_scache_sync_handler: addr=%uxD, req.addr=%uxD", |
|
+ s_addr, addr); |
|
+ |
|
+ if (s_addr == 0 || s_addr == addr) |
|
+ return &conf_addrs[i]; |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+ |
|
+static ngx_ssl_sess_id_t * |
|
+ngx_http_scache_sync_find_session(ngx_str_t* key, uint32_t hash, |
|
+ ngx_ssl_session_cache_t *cache) |
|
+{ |
|
+ ngx_int_t rc; |
|
+ ngx_rbtree_node_t *node, *sentinel; |
|
+ ngx_ssl_sess_id_t* sess_id; |
|
+ |
|
+ node = cache->session_rbtree.root; |
|
+ sentinel = cache->session_rbtree.sentinel; |
|
+ |
|
+ while (node != sentinel) { |
|
+ if (hash < node->key) { |
|
+ node = node->left; |
|
+ continue; |
|
+ } |
|
+ if (hash > node->key) { |
|
+ node = node->right; |
|
+ continue; |
|
+ } |
|
+ |
|
+ /* hash == node->key */ |
|
+ sess_id = (ngx_ssl_sess_id_t *)node; |
|
+ rc = ngx_memn2cmp(key->data, sess_id->id, key->len, (size_t)node->data); |
|
+ if (rc == 0) |
|
+ return sess_id; |
|
+ |
|
+ node = (rc < 0) ? node->left : node->right; |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+ |
|
+static void |
|
+ngx_http_scache_sync_add_session(ngx_connection_t* c, SSL_CTX *ssl_ctx, |
|
+ ngx_str_t *key, ngx_str_t *value, |
|
+ ngx_shm_zone_t* shm_zone, |
|
+ ngx_ssl_session_cache_t* cache, |
|
+ uint32_t hash, ngx_slab_pool_t *shpool) |
|
+{ |
|
+ u_char *id = NULL; |
|
+ u_char *cached_sess = NULL; |
|
+ ngx_ssl_sess_id_t *sess_id = NULL; |
|
+ |
|
+ /* drop one or two expired sessions */ |
|
+ ngx_ssl_expire_sessions(cache, shpool, 1); |
|
+ |
|
+ cached_sess = ngx_slab_alloc_locked(shpool, value->len); |
|
+ if (cached_sess == NULL) { |
|
+ /* drop the oldest non-expired session and try once more */ |
|
+ ngx_ssl_expire_sessions(cache, shpool, 0); |
|
+ cached_sess = ngx_slab_alloc_locked(shpool, value->len); |
|
+ if (cached_sess == NULL) |
|
+ goto failed; |
|
+ } |
|
+ |
|
+ sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); |
|
+ if (sess_id == NULL) { |
|
+ /* drop the oldest non-expired session and try once more */ |
|
+ ngx_ssl_expire_sessions(cache, shpool, 0); |
|
+ sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); |
|
+ if (sess_id == NULL) |
|
+ goto failed; |
|
+ } |
|
+ |
|
+#if (NGX_PTR_SIZE == 8) |
|
+ id = sess_id->sess_id; |
|
+#else |
|
+ id = ngx_slab_alloc_locked(shpool, session_id_length); |
|
+ if (id == NULL) { |
|
+ /* drop the oldest non-expired session and try once more */ |
|
+ ngx_ssl_expire_sessions(cache, shpool, 0); |
|
+ id = ngx_slab_alloc_locked(shpool, session_id_length); |
|
+ if (id == NULL) |
|
+ goto failed; |
|
+ } |
|
+#endif |
|
+ |
|
+ ngx_memcpy(cached_sess, value->data, value->len); |
|
+ ngx_memcpy(id, key->data, key->len); |
|
+ |
|
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, |
|
+ "ngx_http_scache_sync_module: add ssl session: %08XD:%ud:%d", |
|
+ hash, key->len, value->len); |
|
+ |
|
+ sess_id->node.key = hash; |
|
+ sess_id->node.data = (u_char)key->len; |
|
+ sess_id->id = id; |
|
+ sess_id->len = value->len; |
|
+ sess_id->session = cached_sess; |
|
+ sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); |
|
+ |
|
+ ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); |
|
+ ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node); |
|
+ |
|
+ return; |
|
+ |
|
+failed: |
|
+ |
|
+#if (NGX_PTR_SIZE != 8) |
|
+ if (id != NULL) |
|
+ ngx_slab_free_locked(shpool, id); |
|
+#endif |
|
+ |
|
+ if (cached_sess != NULL) |
|
+ ngx_slab_free_locked(shpool, cached_sess); |
|
+ |
|
+ if (sess_id != NULL) |
|
+ ngx_slab_free_locked(shpool, sess_id); |
|
+} |
|
+ |
|
+ |
|
+static ngx_int_t |
|
+ngx_http_scache_sync_postconfig(ngx_conf_t *cf) |
|
+{ |
|
+ ngx_http_handler_pt *h; |
|
+ ngx_http_core_main_conf_t *cmcf; |
|
+ |
|
+ /* add phase handler */ |
|
+ |
|
+ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); |
|
+ |
|
+ h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); |
|
+ if (h == NULL) { |
|
+ return NGX_ERROR; |
|
+ } |
|
+ |
|
+ *h = ngx_http_scache_sync_handler; |
|
+ |
|
+ return NGX_OK; |
|
+} |
|
+ |
|
+ |
|
+static void * |
|
+ngx_http_scache_sync_create_srv_conf(ngx_conf_t *cf) |
|
+{ |
|
+ ngx_http_scache_sync_srv_conf_t *conf; |
|
+ |
|
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scache_sync_srv_conf_t)); |
|
+ if (conf == NULL) { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ conf->receive = NGX_CONF_UNSET; |
|
+ |
|
+ return conf; |
|
+} |
|
+ |
|
+ |
|
+static char * |
|
+ngx_http_scache_sync_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) |
|
+{ |
|
+ ngx_http_scache_sync_srv_conf_t *prev = parent; |
|
+ ngx_http_scache_sync_srv_conf_t *conf = child; |
|
+ |
|
+ ngx_conf_merge_value(conf->receive, prev->receive, 0); |
|
+ |
|
+ return NGX_CONF_OK; |
|
+} |
|
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c |
|
index d6a1794..fa9b0f8 100644 |
|
--- a/src/http/modules/ngx_http_ssl_module.c |
|
+++ b/src/http/modules/ngx_http_ssl_module.c |
|
@@ -47,6 +47,8 @@ static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, |
|
void *conf); |
|
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, |
|
void *conf); |
|
+static char *ngx_http_ssl_session_cache_peers(ngx_conf_t *cf, ngx_command_t *cmd, |
|
+ void *conf); |
|
|
|
static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf); |
|
|
|
@@ -177,6 +179,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { |
|
0, |
|
NULL }, |
|
|
|
+ { ngx_string("ssl_session_cache_peers"), |
|
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, |
|
+ ngx_http_ssl_session_cache_peers, |
|
+ NGX_HTTP_SRV_CONF_OFFSET, |
|
+ 0, |
|
+ NULL }, |
|
+ |
|
{ ngx_string("ssl_session_tickets"), |
|
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, |
|
ngx_conf_set_flag_slot, |
|
@@ -530,6 +539,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) |
|
sscf->session_ticket_keys = NGX_CONF_UNSET_PTR; |
|
sscf->stapling = NGX_CONF_UNSET; |
|
sscf->stapling_verify = NGX_CONF_UNSET; |
|
+ sscf->scache_sync_peers = NGX_CONF_UNSET_PTR; |
|
|
|
return sscf; |
|
} |
|
@@ -771,6 +781,23 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) |
|
|
|
} |
|
|
|
+ ngx_conf_merge_ptr_value(conf->scache_sync_peers, |
|
+ prev->scache_sync_peers, NULL); |
|
+ if (conf->scache_sync_peers != NULL) { |
|
+ size_t i; |
|
+ ngx_array_t* peers = conf->scache_sync_peers; |
|
+ |
|
+ if (ngx_ssl_scache_sync_init(cf, conf->ssl.ctx) != NGX_OK) |
|
+ return NGX_CONF_ERROR; |
|
+ |
|
+ ngx_str_t* names = peers->elts; |
|
+ for (i = 0; i < peers->nelts; i++) { |
|
+ ngx_str_t* name = &names[i]; |
|
+ if (ngx_ssl_scache_sync_add_peer(cf, conf->ssl.ctx, name) != NGX_OK) |
|
+ return NGX_CONF_ERROR; |
|
+ } |
|
+ } |
|
+ |
|
return NGX_CONF_OK; |
|
} |
|
|
|
@@ -930,6 +957,37 @@ invalid: |
|
} |
|
|
|
|
|
+static char * |
|
+ngx_http_ssl_session_cache_peers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
|
+{ |
|
+ size_t i; |
|
+ ngx_str_t *values; |
|
+ ngx_http_ssl_srv_conf_t *sscf = conf; |
|
+ ngx_array_t *peers = sscf->scache_sync_peers; |
|
+ |
|
+ if (peers != NGX_CONF_UNSET_PTR) |
|
+ return "is duplicate"; |
|
+ |
|
+ peers = ngx_array_create(cf->pool, cf->args->nelts - 1, sizeof(ngx_str_t)); |
|
+ if (peers == NULL) |
|
+ return NGX_CONF_ERROR; |
|
+ |
|
+ values = cf->args->elts; |
|
+ |
|
+ for (i = 1; i < cf->args->nelts; i++) { |
|
+ ngx_str_t* s = ngx_array_push(peers); |
|
+ if (s == NULL) |
|
+ return NGX_CONF_ERROR; |
|
+ |
|
+ *s = values[i]; |
|
+ } |
|
+ |
|
+ sscf->scache_sync_peers = peers; |
|
+ |
|
+ return NGX_CONF_OK; |
|
+} |
|
+ |
|
+ |
|
static ngx_int_t |
|
ngx_http_ssl_init(ngx_conf_t *cf) |
|
{ |
|
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h |
|
index 8e69e9e..eb39bd2 100644 |
|
--- a/src/http/modules/ngx_http_ssl_module.h |
|
+++ b/src/http/modules/ngx_http_ssl_module.h |
|
@@ -56,6 +56,8 @@ typedef struct { |
|
|
|
u_char *file; |
|
ngx_uint_t line; |
|
+ |
|
+ ngx_array_t *scache_sync_peers; |
|
} ngx_http_ssl_srv_conf_t; |
|
|
|
|
|
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c |
|
index 6b0a48f..02a80b0 100644 |
|
--- a/src/http/ngx_http.c |
|
+++ b/src/http/ngx_http.c |
|
@@ -1161,7 +1161,7 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
|
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); |
|
|
|
if (cmcf->ports == NULL) { |
|
- cmcf->ports = ngx_array_create(cf->temp_pool, 2, |
|
+ cmcf->ports = ngx_array_create(cf->pool, 2, |
|
sizeof(ngx_http_conf_port_t)); |
|
if (cmcf->ports == NULL) { |
|
return NGX_ERROR; |
|
@@ -1349,7 +1349,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
|
ngx_http_conf_addr_t *addr; |
|
|
|
if (port->addrs.elts == NULL) { |
|
- if (ngx_array_init(&port->addrs, cf->temp_pool, 4, |
|
+ if (ngx_array_init(&port->addrs, cf->pool, 4, |
|
sizeof(ngx_http_conf_addr_t)) |
|
!= NGX_OK) |
|
{ |
|
@@ -1398,7 +1398,7 @@ ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
|
ngx_http_core_srv_conf_t **server; |
|
|
|
if (addr->servers.elts == NULL) { |
|
- if (ngx_array_init(&addr->servers, cf->temp_pool, 4, |
|
+ if (ngx_array_init(&addr->servers, cf->pool, 4, |
|
sizeof(ngx_http_core_srv_conf_t *)) |
|
!= NGX_OK) |
|
{ |
|
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h |
|
index 844f502..4c7b8ec 100644 |
|
--- a/src/http/ngx_http.h |
|
+++ b/src/http/ngx_http.h |
|
@@ -92,6 +92,10 @@ void ngx_http_close_connection(ngx_connection_t *c); |
|
int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); |
|
#endif |
|
|
|
+ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, |
|
+ ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, |
|
+ ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); |
|
+ |
|
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b); |
|
ngx_int_t ngx_http_parse_uri(ngx_http_request_t *r); |
|
ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r, |
|
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c |
|
index cd5f302..1b88f3c 100644 |
|
--- a/src/http/ngx_http_request.c |
|
+++ b/src/http/ngx_http_request.c |
|
@@ -34,9 +34,6 @@ static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, |
|
ngx_uint_t alloc); |
|
static ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, |
|
ngx_str_t *host); |
|
-static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, |
|
- ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, |
|
- ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); |
|
|
|
static void ngx_http_request_handler(ngx_event_t *ev); |
|
static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc); |
|
@@ -2079,7 +2076,7 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) |
|
} |
|
|
|
|
|
-static ngx_int_t |
|
+ngx_int_t |
|
ngx_http_find_virtual_server(ngx_connection_t *c, |
|
ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, |
|
ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp) |