1678 lines
43 KiB
C
1678 lines
43 KiB
C
![]() |
/*
|
||
|
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <ngx_config.h>
|
||
|
#include <ngx_core.h>
|
||
|
#include <ngx_http.h>
|
||
|
#include "ngx_dynamic_conf.h"
|
||
|
#include "ngx_http_dynamic.h"
|
||
|
|
||
|
|
||
|
static void *ngx_http_dynamic_create_conf(ngx_conf_t *cf);
|
||
|
static void *ngx_http_dynamic_core_create_main_conf(ngx_conf_t *cf);
|
||
|
static char *ngx_http_dynamic_core_init_main_conf(ngx_conf_t *cf, void *conf);
|
||
|
static void *ngx_http_dynamic_core_create_srv_conf(ngx_conf_t *cf);
|
||
|
static char *ngx_http_dynamic_core_init_srv_conf(ngx_conf_t *cf, void *conf);
|
||
|
static void *ngx_http_dynamic_core_create_loc_conf(ngx_conf_t *cf);
|
||
|
static char *ngx_http_dynamic_core_init_loc_conf(ngx_conf_t *cf, void *conf);
|
||
|
|
||
|
static char *ngx_http_dynamic_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||
|
void *conf);
|
||
|
static char *ngx_http_dynamic_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
|
||
|
void *conf);
|
||
|
static char *ngx_http_dynamic_core_server_name(ngx_conf_t *cf,
|
||
|
ngx_command_t *cmd, void *conf);
|
||
|
static char *ngx_http_dynamic_core_location(ngx_conf_t *cf, ngx_command_t *cmd,
|
||
|
void *conf);
|
||
|
|
||
|
|
||
|
typedef struct ngx_http_dynamic_location_tree_node_s
|
||
|
ngx_http_dynamic_location_tree_node_t;
|
||
|
typedef struct ngx_http_dynamic_core_loc_conf_s
|
||
|
ngx_http_dynamic_core_loc_conf_t;
|
||
|
|
||
|
struct ngx_http_dynamic_core_loc_conf_s {
|
||
|
ngx_str_t name; /* location name */
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_dynamic_regex_t *regex;
|
||
|
#endif
|
||
|
|
||
|
unsigned exact_match:1;
|
||
|
unsigned noregex:1;
|
||
|
|
||
|
ngx_queue_t *locations;
|
||
|
|
||
|
ngx_http_dynamic_location_tree_node_t *static_locations;
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_http_dynamic_core_loc_conf_t **regex_locations;
|
||
|
#endif
|
||
|
|
||
|
void **loc_conf;
|
||
|
};
|
||
|
|
||
|
typedef struct {
|
||
|
ngx_queue_t queue;
|
||
|
ngx_http_dynamic_core_loc_conf_t *exact;
|
||
|
ngx_http_dynamic_core_loc_conf_t *inclusive;
|
||
|
ngx_str_t *name;
|
||
|
u_char *file_name;
|
||
|
ngx_uint_t line;
|
||
|
ngx_queue_t list;
|
||
|
} ngx_http_dynamic_location_queue_t;
|
||
|
|
||
|
struct ngx_http_dynamic_location_tree_node_s {
|
||
|
ngx_http_dynamic_location_tree_node_t *left;
|
||
|
ngx_http_dynamic_location_tree_node_t *right;
|
||
|
ngx_http_dynamic_location_tree_node_t *tree;
|
||
|
|
||
|
ngx_http_dynamic_core_loc_conf_t *exact;
|
||
|
ngx_http_dynamic_core_loc_conf_t *inclusive;
|
||
|
|
||
|
u_char len;
|
||
|
u_char name[1];
|
||
|
};
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
/* array of the ngx_http_dynamic_server_name_t, "server_name" directive */
|
||
|
ngx_array_t server_names;
|
||
|
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf;
|
||
|
|
||
|
void **srv_conf;
|
||
|
} ngx_http_dynamic_core_srv_conf_t;
|
||
|
|
||
|
typedef struct {
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_dynamic_regex_t *regex;
|
||
|
#endif
|
||
|
ngx_http_dynamic_core_srv_conf_t *server; /* virtual name server conf */
|
||
|
ngx_str_t name;
|
||
|
} ngx_http_dynamic_server_name_t;
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
/* ngx_http_dynamic_srv_conf_t */
|
||
|
ngx_array_t servers;
|
||
|
|
||
|
ngx_uint_t server_names_hash_max_size;
|
||
|
ngx_uint_t server_names_hash_bucket_size;
|
||
|
|
||
|
/* the default server configuration for this address:port */
|
||
|
ngx_http_dynamic_core_srv_conf_t *default_server;
|
||
|
|
||
|
ngx_hash_combined_t names;
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_uint_t nregex;
|
||
|
ngx_http_dynamic_server_name_t *regex;
|
||
|
#endif
|
||
|
} ngx_http_dynamic_core_main_conf_t;
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
void **main_conf;
|
||
|
} ngx_http_dynamic_conf_t;
|
||
|
|
||
|
|
||
|
static ngx_core_module_t ngx_http_dynamic_module_ctx = {
|
||
|
ngx_string("http_dynamic"),
|
||
|
NULL,
|
||
|
NULL
|
||
|
};
|
||
|
|
||
|
static ngx_command_t ngx_http_dynamic_dcommands[] = {
|
||
|
|
||
|
{ ngx_string("http"),
|
||
|
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
|
||
|
ngx_http_dynamic_block,
|
||
|
0,
|
||
|
0,
|
||
|
NULL },
|
||
|
|
||
|
ngx_null_command
|
||
|
};
|
||
|
|
||
|
static ngx_dynamic_core_module_t ngx_http_dynamic_module_dctx = {
|
||
|
ngx_string("http_dynamic"),
|
||
|
ngx_http_dynamic_create_conf,
|
||
|
NULL
|
||
|
};
|
||
|
|
||
|
ngx_module_t ngx_http_dynamic_module = {
|
||
|
NGX_MODULE_V1,
|
||
|
&ngx_http_dynamic_module_ctx, /* module context */
|
||
|
NULL, /* module directives */
|
||
|
NGX_CORE_MODULE, /* module type */
|
||
|
NULL, /* init master */
|
||
|
NULL, /* init module */
|
||
|
NULL, /* init process */
|
||
|
NULL, /* init thread */
|
||
|
NULL, /* exit thread */
|
||
|
NULL, /* exit process */
|
||
|
NULL, /* exit master */
|
||
|
(uintptr_t) &ngx_http_dynamic_module_dctx, /* module dynamic context */
|
||
|
(uintptr_t) ngx_http_dynamic_dcommands, /* module dynamic directives */
|
||
|
NGX_MODULE_V1_DYNAMIC_PADDING
|
||
|
};
|
||
|
|
||
|
|
||
|
static ngx_http_module_t ngx_http_dynamic_core_module_ctx = {
|
||
|
NULL, /* preconfiguration */
|
||
|
NULL, /* postconfiguration */
|
||
|
|
||
|
NULL, /* create main configuration */
|
||
|
NULL, /* init main configuration */
|
||
|
|
||
|
NULL, /* create server configuration */
|
||
|
NULL, /* merge server configuration */
|
||
|
|
||
|
NULL, /* create location configuration */
|
||
|
NULL /* merge location configuration */
|
||
|
};
|
||
|
|
||
|
|
||
|
static ngx_command_t ngx_http_dynamic_core_dcommands[] = {
|
||
|
|
||
|
{ ngx_string("server_names_hash_max_size"),
|
||
|
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
|
||
|
ngx_conf_set_num_slot,
|
||
|
0,
|
||
|
offsetof(ngx_http_dynamic_core_main_conf_t, server_names_hash_max_size),
|
||
|
NULL },
|
||
|
|
||
|
{ ngx_string("server_names_hash_bucket_size"),
|
||
|
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
|
||
|
ngx_conf_set_num_slot,
|
||
|
0,
|
||
|
offsetof(ngx_http_dynamic_core_main_conf_t,
|
||
|
server_names_hash_bucket_size),
|
||
|
NULL },
|
||
|
|
||
|
{ ngx_string("server"),
|
||
|
NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
|
||
|
ngx_http_dynamic_core_server,
|
||
|
0,
|
||
|
0,
|
||
|
NULL },
|
||
|
|
||
|
{ ngx_string("server_name"),
|
||
|
NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
|
||
|
ngx_http_dynamic_core_server_name,
|
||
|
0,
|
||
|
0,
|
||
|
NULL },
|
||
|
|
||
|
{ ngx_string("location"),
|
||
|
NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
|
||
|
ngx_http_dynamic_core_location,
|
||
|
0,
|
||
|
0,
|
||
|
NULL },
|
||
|
|
||
|
ngx_null_command
|
||
|
};
|
||
|
|
||
|
|
||
|
static ngx_http_dynamic_module_t ngx_http_dynamic_core_module_dctx = {
|
||
|
ngx_http_dynamic_core_create_main_conf, /* create main configuration */
|
||
|
ngx_http_dynamic_core_init_main_conf, /* init main configuration */
|
||
|
|
||
|
ngx_http_dynamic_core_create_srv_conf, /* create server configuration */
|
||
|
ngx_http_dynamic_core_init_srv_conf, /* init server configuration */
|
||
|
|
||
|
ngx_http_dynamic_core_create_loc_conf, /* create location configuration */
|
||
|
ngx_http_dynamic_core_init_loc_conf /* init location configuration */
|
||
|
};
|
||
|
|
||
|
|
||
|
ngx_module_t ngx_http_dynamic_core_module = {
|
||
|
NGX_MODULE_V1,
|
||
|
&ngx_http_dynamic_core_module_ctx, /* module context */
|
||
|
NULL, /* 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 */
|
||
|
(uintptr_t) &ngx_http_dynamic_core_module_dctx, /* module dynamic context */
|
||
|
(uintptr_t) ngx_http_dynamic_core_dcommands, /* module dynamic directives */
|
||
|
NGX_MODULE_V1_DYNAMIC_PADDING
|
||
|
};
|
||
|
|
||
|
|
||
|
static void *
|
||
|
ngx_http_dynamic_create_conf(ngx_conf_t *cf)
|
||
|
{
|
||
|
ngx_http_dynamic_conf_t *hdccf;
|
||
|
|
||
|
hdccf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_conf_t));
|
||
|
if (hdccf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return hdccf;
|
||
|
}
|
||
|
|
||
|
static void *
|
||
|
ngx_http_dynamic_core_create_main_conf(ngx_conf_t *cf)
|
||
|
{
|
||
|
ngx_http_dynamic_core_main_conf_t *hdcmcf;
|
||
|
|
||
|
hdcmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_core_main_conf_t));
|
||
|
if (hdcmcf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (ngx_array_init(&hdcmcf->servers, cf->pool, 4,
|
||
|
sizeof(ngx_http_dynamic_core_srv_conf_t *)) != NGX_OK)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
hdcmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
|
||
|
hdcmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT;
|
||
|
|
||
|
return hdcmcf;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_core_init_main_conf(ngx_conf_t *cf, void *conf)
|
||
|
{
|
||
|
ngx_http_dynamic_core_main_conf_t *hdcmcf;
|
||
|
|
||
|
hdcmcf = conf;
|
||
|
|
||
|
ngx_conf_init_uint_value(hdcmcf->server_names_hash_max_size, 512);
|
||
|
ngx_conf_init_uint_value(hdcmcf->server_names_hash_bucket_size,
|
||
|
ngx_cacheline_size);
|
||
|
|
||
|
return NGX_CONF_OK;
|
||
|
}
|
||
|
|
||
|
static void *
|
||
|
ngx_http_dynamic_core_create_srv_conf(ngx_conf_t *cf)
|
||
|
{
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf;
|
||
|
|
||
|
hdcscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_core_srv_conf_t));
|
||
|
if (hdcscf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (ngx_array_init(&hdcscf->server_names, cf->pool, 4,
|
||
|
sizeof(ngx_http_dynamic_server_name_t)) != NGX_OK)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return hdcscf;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_core_init_srv_conf(ngx_conf_t *cf, void *conf)
|
||
|
{
|
||
|
return NGX_CONF_OK;
|
||
|
}
|
||
|
|
||
|
static void *
|
||
|
ngx_http_dynamic_core_create_loc_conf(ngx_conf_t *cf)
|
||
|
{
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf;
|
||
|
|
||
|
hdclcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_core_loc_conf_t));
|
||
|
if (hdclcf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return hdclcf;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_core_init_loc_conf(ngx_conf_t *cf, void *conf)
|
||
|
{
|
||
|
return NGX_CONF_OK;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_regex_location(ngx_conf_t *cf,
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf,
|
||
|
ngx_str_t *regex, ngx_uint_t caseless)
|
||
|
{
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_regex_compile_t rc;
|
||
|
u_char errstr[NGX_MAX_CONF_ERRSTR];
|
||
|
|
||
|
ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
|
||
|
|
||
|
rc.pattern = *regex;
|
||
|
rc.err.len = NGX_MAX_CONF_ERRSTR;
|
||
|
rc.err.data = errstr;
|
||
|
|
||
|
#if (NGX_HAVE_CASELESS_FILESYSTEM)
|
||
|
rc.options = NGX_REGEX_CASELESS;
|
||
|
#else
|
||
|
rc.options = caseless ? NGX_REGEX_CASELESS : 0;
|
||
|
#endif
|
||
|
|
||
|
hdclcf->regex = ngx_dynamic_regex_compile(cf, &rc);
|
||
|
if (hdclcf->regex == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
hdclcf->name = *regex;
|
||
|
|
||
|
return NGX_OK;
|
||
|
|
||
|
#else
|
||
|
|
||
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||
|
"using regex \"%V\" requires PCRE library",
|
||
|
regex);
|
||
|
return NGX_ERROR;
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_predeal_location(ngx_conf_t *cf,
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf)
|
||
|
{
|
||
|
ngx_str_t *value, *name;
|
||
|
size_t len;
|
||
|
u_char *mod;
|
||
|
|
||
|
value = cf->args->elts;
|
||
|
|
||
|
if (cf->args->nelts == 3) {
|
||
|
|
||
|
len = value[1].len;
|
||
|
mod = value[1].data;
|
||
|
name = &value[2];
|
||
|
|
||
|
if (len == 1 && mod[0] == '=') {
|
||
|
|
||
|
hdclcf->name = *name;
|
||
|
hdclcf->exact_match = 1;
|
||
|
|
||
|
} else if (len == 2 && mod[0] == '^' && mod[1] == '~') {
|
||
|
|
||
|
hdclcf->name = *name;
|
||
|
hdclcf->noregex = 1;
|
||
|
|
||
|
} else if (len == 1 && mod[0] == '~') {
|
||
|
|
||
|
if (ngx_http_dynamic_core_regex_location(cf, hdclcf, name, 0)
|
||
|
!= NGX_OK)
|
||
|
{
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
} else if (len == 2 && mod[0] == '~' && mod[1] == '*') {
|
||
|
|
||
|
if (ngx_http_dynamic_core_regex_location(cf, hdclcf, name, 1)
|
||
|
!= NGX_OK)
|
||
|
{
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||
|
"invalid location modifier \"%V\"", &value[1]);
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
} else { /* cf->args->nelts == 2 */
|
||
|
|
||
|
name = &value[1];
|
||
|
|
||
|
if (name->data[0] == '=') {
|
||
|
|
||
|
hdclcf->name.len = name->len - 1;
|
||
|
hdclcf->name.data = name->data + 1;
|
||
|
hdclcf->exact_match = 1;
|
||
|
|
||
|
} else if (name->data[0] == '^' && name->data[1] == '~') {
|
||
|
|
||
|
hdclcf->name.len = name->len - 2;
|
||
|
hdclcf->name.data = name->data + 2;
|
||
|
hdclcf->noregex = 1;
|
||
|
|
||
|
} else if (name->data[0] == '~') {
|
||
|
|
||
|
name->len--;
|
||
|
name->data++;
|
||
|
|
||
|
if (name->data[0] == '*') {
|
||
|
|
||
|
name->len--;
|
||
|
name->data++;
|
||
|
|
||
|
if (ngx_http_dynamic_core_regex_location(cf, hdclcf, name, 1)
|
||
|
!= NGX_OK)
|
||
|
{
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
if (ngx_http_dynamic_core_regex_location(cf, hdclcf, name, 0)
|
||
|
!= NGX_OK)
|
||
|
{
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
hdclcf->name = *name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_cmp_locations(const ngx_queue_t *one,
|
||
|
const ngx_queue_t *two)
|
||
|
{
|
||
|
ngx_int_t rc;
|
||
|
ngx_http_dynamic_core_loc_conf_t *first, *second;
|
||
|
ngx_http_dynamic_location_queue_t *lq1, *lq2;
|
||
|
|
||
|
lq1 = (ngx_http_dynamic_location_queue_t *) one;
|
||
|
lq2 = (ngx_http_dynamic_location_queue_t *) two;
|
||
|
|
||
|
first = lq1->exact ? lq1->exact : lq1->inclusive;
|
||
|
second = lq2->exact ? lq2->exact : lq2->inclusive;
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
if (first->regex && !second->regex) {
|
||
|
/* shift the regex matches to the end */
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (!first->regex && second->regex) {
|
||
|
/* shift the regex matches to the end */
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (first->regex || second->regex) {
|
||
|
/* do not sort the regex matches */
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
rc = ngx_filename_cmp(first->name.data, second->name.data,
|
||
|
ngx_min(first->name.len, second->name.len) + 1);
|
||
|
|
||
|
if (rc == 0 && !first->exact_match && second->exact_match) {
|
||
|
/* an exact match must be before the same inclusive one */
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_join_exact_locations(ngx_conf_t *cf,
|
||
|
ngx_queue_t *locations)
|
||
|
{
|
||
|
ngx_queue_t *q, *x;
|
||
|
ngx_http_dynamic_location_queue_t *lq, *lx;
|
||
|
|
||
|
q = ngx_queue_head(locations);
|
||
|
|
||
|
while (q != ngx_queue_last(locations)) {
|
||
|
|
||
|
x = ngx_queue_next(q);
|
||
|
|
||
|
lq = (ngx_http_dynamic_location_queue_t *) q;
|
||
|
lx = (ngx_http_dynamic_location_queue_t *) x;
|
||
|
|
||
|
if (lq->name->len == lx->name->len
|
||
|
&& ngx_filename_cmp(lq->name->data, lx->name->data, lx->name->len)
|
||
|
== 0)
|
||
|
{
|
||
|
if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) {
|
||
|
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||
|
"duplicate location \"%V\" in %s:%ui",
|
||
|
lx->name, lx->file_name, lx->line);
|
||
|
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
lq->inclusive = lx->inclusive;
|
||
|
|
||
|
ngx_queue_remove(x);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
q = ngx_queue_next(q);
|
||
|
}
|
||
|
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ngx_http_dynamic_core_create_locations_list(ngx_queue_t *locations,
|
||
|
ngx_queue_t *q)
|
||
|
{
|
||
|
u_char *name;
|
||
|
size_t len;
|
||
|
ngx_queue_t *x, tail;
|
||
|
ngx_http_dynamic_location_queue_t *lq, *lx;
|
||
|
|
||
|
if (q == ngx_queue_last(locations)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lq = (ngx_http_dynamic_location_queue_t *) q;
|
||
|
|
||
|
if (lq->inclusive == NULL) {
|
||
|
ngx_http_dynamic_core_create_locations_list(locations,
|
||
|
ngx_queue_next(q));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
len = lq->name->len;
|
||
|
name = lq->name->data;
|
||
|
|
||
|
for (x = ngx_queue_next(q);
|
||
|
x != ngx_queue_sentinel(locations);
|
||
|
x = ngx_queue_next(x))
|
||
|
{
|
||
|
lx = (ngx_http_dynamic_location_queue_t *) x;
|
||
|
|
||
|
if (len > lx->name->len
|
||
|
|| ngx_filename_cmp(name, lx->name->data, len) != 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
q = ngx_queue_next(q);
|
||
|
|
||
|
if (q == x) {
|
||
|
ngx_http_dynamic_core_create_locations_list(locations, x);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ngx_queue_split(locations, q, &tail);
|
||
|
ngx_queue_add(&lq->list, &tail);
|
||
|
|
||
|
if (x == ngx_queue_sentinel(locations)) {
|
||
|
ngx_http_dynamic_core_create_locations_list(&lq->list,
|
||
|
ngx_queue_head(&lq->list));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ngx_queue_split(&lq->list, x, &tail);
|
||
|
ngx_queue_add(locations, &tail);
|
||
|
|
||
|
ngx_http_dynamic_core_create_locations_list(&lq->list,
|
||
|
ngx_queue_head(&lq->list));
|
||
|
|
||
|
ngx_http_dynamic_core_create_locations_list(locations, x);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* to keep cache locality for left leaf nodes, allocate nodes in following
|
||
|
* order: node, left subtree, right subtree, inclusive subtree
|
||
|
*/
|
||
|
|
||
|
static ngx_http_dynamic_location_tree_node_t *
|
||
|
ngx_http_dynamic_core_create_locations_tree(ngx_conf_t *cf,
|
||
|
ngx_queue_t *locations, size_t prefix)
|
||
|
{
|
||
|
size_t len;
|
||
|
ngx_queue_t *q, tail;
|
||
|
ngx_http_dynamic_location_queue_t *lq;
|
||
|
ngx_http_dynamic_location_tree_node_t *node;
|
||
|
|
||
|
q = ngx_queue_middle(locations);
|
||
|
|
||
|
lq = (ngx_http_dynamic_location_queue_t *) q;
|
||
|
len = lq->name->len - prefix;
|
||
|
|
||
|
node = ngx_palloc(cf->pool,
|
||
|
offsetof(ngx_http_dynamic_location_tree_node_t, name) + len);
|
||
|
if (node == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
node->left = NULL;
|
||
|
node->right = NULL;
|
||
|
node->tree = NULL;
|
||
|
node->exact = lq->exact;
|
||
|
node->inclusive = lq->inclusive;
|
||
|
|
||
|
node->len = (u_char) len;
|
||
|
ngx_memcpy(node->name, &lq->name->data[prefix], len);
|
||
|
|
||
|
ngx_queue_split(locations, q, &tail);
|
||
|
|
||
|
if (ngx_queue_empty(locations)) {
|
||
|
/*
|
||
|
* ngx_queue_split() insures that if left part is empty,
|
||
|
* then right one is empty too
|
||
|
*/
|
||
|
goto inclusive;
|
||
|
}
|
||
|
|
||
|
node->left = ngx_http_dynamic_core_create_locations_tree(cf, locations,
|
||
|
prefix);
|
||
|
if (node->left == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ngx_queue_remove(q);
|
||
|
|
||
|
if (ngx_queue_empty(&tail)) {
|
||
|
goto inclusive;
|
||
|
}
|
||
|
|
||
|
node->right = ngx_http_dynamic_core_create_locations_tree(cf, &tail,
|
||
|
prefix);
|
||
|
if (node->right == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
inclusive:
|
||
|
|
||
|
if (ngx_queue_empty(&lq->list)) {
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
node->tree = ngx_http_dynamic_core_create_locations_tree(cf, &lq->list,
|
||
|
prefix + len);
|
||
|
if (node->tree == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_init_locations(ngx_conf_t *cf,
|
||
|
ngx_http_dynamic_core_loc_conf_t *phdclcf)
|
||
|
{
|
||
|
ngx_queue_t *q, *locations, tail;
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf;
|
||
|
ngx_http_dynamic_location_queue_t *lq;
|
||
|
ngx_http_dynamic_core_loc_conf_t **hdclcfp;
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_uint_t r;
|
||
|
ngx_queue_t *regex;
|
||
|
#endif
|
||
|
|
||
|
locations = phdclcf->locations;
|
||
|
|
||
|
if (locations == NULL) {
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
ngx_queue_sort(locations, ngx_http_dynamic_core_cmp_locations);
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
regex = NULL;
|
||
|
r = 0;
|
||
|
#endif
|
||
|
|
||
|
for (q = ngx_queue_head(locations);
|
||
|
q != ngx_queue_sentinel(locations);
|
||
|
q = ngx_queue_next(q))
|
||
|
{
|
||
|
lq = (ngx_http_dynamic_location_queue_t *) q;
|
||
|
|
||
|
hdclcf = lq->exact ? lq->exact : lq->inclusive;
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
|
||
|
if (hdclcf->regex) {
|
||
|
r++;
|
||
|
|
||
|
if (regex == NULL) {
|
||
|
regex = q;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (q != ngx_queue_sentinel(locations)) {
|
||
|
ngx_queue_split(locations, q, &tail);
|
||
|
}
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
|
||
|
if (regex) {
|
||
|
|
||
|
hdclcfp = ngx_palloc(cf->pool,
|
||
|
(r + 1) * sizeof(ngx_http_dynamic_core_loc_conf_t *));
|
||
|
if (hdclcfp == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
phdclcf->regex_locations = hdclcfp;
|
||
|
|
||
|
for (q = regex;
|
||
|
q != ngx_queue_sentinel(locations);
|
||
|
q = ngx_queue_next(q))
|
||
|
{
|
||
|
lq = (ngx_http_dynamic_location_queue_t *) q;
|
||
|
|
||
|
*(hdclcfp++) = lq->exact;
|
||
|
}
|
||
|
|
||
|
*hdclcfp = NULL;
|
||
|
|
||
|
ngx_queue_split(locations, regex, &tail);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_init_static_location_trees(ngx_conf_t *cf,
|
||
|
ngx_http_dynamic_core_loc_conf_t *phdclcf)
|
||
|
{
|
||
|
ngx_queue_t *locations;
|
||
|
|
||
|
locations = phdclcf->locations;
|
||
|
|
||
|
if (locations == NULL) {
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
if (ngx_queue_empty(locations)) {
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
if (ngx_http_dynamic_core_join_exact_locations(cf, locations) != NGX_OK) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
ngx_http_dynamic_core_create_locations_list(locations,
|
||
|
ngx_queue_head(locations));
|
||
|
|
||
|
phdclcf->static_locations =
|
||
|
ngx_http_dynamic_core_create_locations_tree(cf, locations, 0);
|
||
|
if (phdclcf->static_locations == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf)
|
||
|
{
|
||
|
ngx_http_dynamic_location_queue_t *lq;
|
||
|
|
||
|
if (ngx_http_dynamic_core_predeal_location(cf, hdclcf) != NGX_OK) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
if (*locations == NULL) {
|
||
|
*locations = ngx_pcalloc(cf->temp_pool,
|
||
|
sizeof(ngx_http_location_queue_t));
|
||
|
if (*locations == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
ngx_queue_init(*locations);
|
||
|
}
|
||
|
|
||
|
lq = ngx_pcalloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
|
||
|
if (lq == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
if (hdclcf->exact_match
|
||
|
#if (NGX_PCRE)
|
||
|
|| hdclcf->regex
|
||
|
#endif
|
||
|
)
|
||
|
{
|
||
|
lq->exact = hdclcf;
|
||
|
lq->inclusive = NULL;
|
||
|
} else {
|
||
|
lq->exact = NULL;
|
||
|
lq->inclusive = hdclcf;
|
||
|
}
|
||
|
|
||
|
lq->name = &hdclcf->name;
|
||
|
lq->file_name = cf->conf_file->file.name.data;
|
||
|
lq->line = cf->conf_file->line;
|
||
|
|
||
|
ngx_queue_init(&lq->list);
|
||
|
|
||
|
ngx_queue_insert_tail(*locations, &lq->queue);
|
||
|
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* NGX_OK - exact or regex match
|
||
|
* NGX_AGAIN - inclusive match
|
||
|
* NGX_DECLINED - no match
|
||
|
*/
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_find_static_location(ngx_http_request_t *r,
|
||
|
ngx_http_dynamic_core_loc_conf_t *phdclcf,
|
||
|
ngx_http_dynamic_core_loc_conf_t **hdclcf)
|
||
|
{
|
||
|
ngx_http_dynamic_location_tree_node_t *node;
|
||
|
u_char *uri;
|
||
|
size_t len, n;
|
||
|
ngx_int_t rc, rv;
|
||
|
|
||
|
len = r->uri.len;
|
||
|
uri = r->uri.data;
|
||
|
|
||
|
rv = NGX_DECLINED;
|
||
|
|
||
|
node = phdclcf->static_locations;
|
||
|
|
||
|
for ( ;; ) {
|
||
|
|
||
|
if (node == NULL) {
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||
|
"test location: \"%*s\"",
|
||
|
(size_t) node->len, node->name);
|
||
|
|
||
|
n = (len <= (size_t) node->len) ? len : node->len;
|
||
|
|
||
|
rc = ngx_filename_cmp(uri, node->name, n);
|
||
|
|
||
|
if (rc != 0) {
|
||
|
node = (rc < 0) ? node->left : node->right;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (len > (size_t) node->len) {
|
||
|
|
||
|
if (node->inclusive) {
|
||
|
|
||
|
*hdclcf = node->inclusive->
|
||
|
loc_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
rv = NGX_AGAIN;
|
||
|
|
||
|
node = node->tree;
|
||
|
uri += n;
|
||
|
len -= n;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* exact only */
|
||
|
|
||
|
node = node->right;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (len == (size_t) node->len) {
|
||
|
|
||
|
if (node->exact) {
|
||
|
*hdclcf = node->exact->
|
||
|
loc_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
return NGX_OK;
|
||
|
|
||
|
} else {
|
||
|
*hdclcf = node->inclusive->
|
||
|
loc_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
return NGX_AGAIN;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* len < node->len */
|
||
|
|
||
|
node = node->left;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* NGX_OK - exact or regex match
|
||
|
* NGX_AGAIN - inclusive match
|
||
|
* NGX_ERROR - regex error
|
||
|
* NGX_DECLINED - no match
|
||
|
*/
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_find_location(ngx_http_request_t *r,
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf,
|
||
|
ngx_http_dynamic_core_loc_conf_t **hdclcf)
|
||
|
{
|
||
|
ngx_int_t rc;
|
||
|
ngx_http_dynamic_core_loc_conf_t *phdclcf;
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_int_t n;
|
||
|
ngx_uint_t noregex;
|
||
|
ngx_http_dynamic_core_loc_conf_t **hdclcfp;
|
||
|
|
||
|
noregex = 0;
|
||
|
#endif
|
||
|
|
||
|
phdclcf = hdcscf->hdclcf;
|
||
|
|
||
|
rc = ngx_http_dynamic_core_find_static_location(r, phdclcf, hdclcf);
|
||
|
|
||
|
if (rc == NGX_AGAIN) {
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
noregex = (*hdclcf)->noregex;
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
if (rc == NGX_OK || rc == NGX_DONE) {
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/* rc == NGX_DECLINED or rc == NGX_AGAIN in nested location */
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
|
||
|
if (noregex == 0 && phdclcf->regex_locations) {
|
||
|
|
||
|
for (hdclcfp = phdclcf->regex_locations; *hdclcfp; hdclcfp++) {
|
||
|
|
||
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||
|
"test location: ~ \"%V\"", &(*hdclcfp)->name);
|
||
|
|
||
|
n = ngx_regex_exec((*hdclcfp)->regex->regex, &r->uri, NULL, 0);
|
||
|
|
||
|
if (n == NGX_OK) {
|
||
|
*hdclcf = (*hdclcfp)->
|
||
|
loc_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
if (n == NGX_REGEX_NO_MATCHED) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_init_virtual_servers(ngx_conf_t *cf,
|
||
|
ngx_http_dynamic_conf_t *hdcf)
|
||
|
{
|
||
|
ngx_http_dynamic_core_main_conf_t *hdcmcf;
|
||
|
ngx_http_dynamic_core_srv_conf_t **hdcscfp;
|
||
|
ngx_hash_init_t hash;
|
||
|
ngx_hash_keys_arrays_t ha;
|
||
|
ngx_http_dynamic_server_name_t *name;
|
||
|
ngx_uint_t s, n;
|
||
|
ngx_int_t rc;
|
||
|
#if (NGX_PCRE)
|
||
|
ngx_uint_t regex, i;
|
||
|
|
||
|
regex = 0;
|
||
|
#endif
|
||
|
|
||
|
hdcmcf = hdcf->main_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
|
||
|
ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));
|
||
|
|
||
|
ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
|
||
|
if (ha.temp_pool == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
ha.pool = cf->pool;
|
||
|
|
||
|
if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
hdcscfp = hdcmcf->servers.elts;
|
||
|
hdcmcf->default_server = hdcscfp[0];
|
||
|
|
||
|
for (s = 0; s < hdcmcf->servers.nelts; ++s) {
|
||
|
|
||
|
name = hdcscfp[s]->server_names.elts;
|
||
|
|
||
|
for (n = 0; n < hdcscfp[s]->server_names.nelts; ++n) {
|
||
|
#if (NGX_PCRE)
|
||
|
if (name[n].regex) {
|
||
|
++regex;
|
||
|
continue;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,
|
||
|
NGX_HASH_WILDCARD_KEY);
|
||
|
if (rc == NGX_ERROR) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
if (rc == NGX_DECLINED) {
|
||
|
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||
|
"invalid server name or wildcard \"%V\"",
|
||
|
&name[n].name);
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
if (rc == NGX_BUSY) {
|
||
|
ngx_log_error(NGX_LOG_WARN, cf->log, 0,
|
||
|
"conflicting server name \"%V\", ignored",
|
||
|
&name[n].name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hash.key = ngx_hash_key_lc;
|
||
|
hash.max_size = hdcmcf->server_names_hash_max_size;
|
||
|
hash.bucket_size = hdcmcf->server_names_hash_bucket_size;
|
||
|
hash.name = "http_dynamic_server_names_hash";
|
||
|
hash.pool = cf->pool;
|
||
|
|
||
|
if (ha.keys.nelts) {
|
||
|
hash.hash = &hdcmcf->names.hash;
|
||
|
hash.temp_pool = NULL;
|
||
|
|
||
|
if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ha.dns_wc_head.nelts) {
|
||
|
|
||
|
ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts,
|
||
|
sizeof(ngx_hash_key_t), ngx_dynamic_cmp_dns_wildcards);
|
||
|
|
||
|
hash.hash = NULL;
|
||
|
hash.temp_pool = ha.temp_pool;
|
||
|
|
||
|
if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,
|
||
|
ha.dns_wc_head.nelts) != NGX_OK)
|
||
|
{
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
hdcmcf->names.wc_head = (ngx_hash_wildcard_t *) hash.hash;
|
||
|
}
|
||
|
|
||
|
if (ha.dns_wc_tail.nelts) {
|
||
|
|
||
|
ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts,
|
||
|
sizeof(ngx_hash_key_t), ngx_dynamic_cmp_dns_wildcards);
|
||
|
|
||
|
hash.hash = NULL;
|
||
|
hash.temp_pool = ha.temp_pool;
|
||
|
|
||
|
if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,
|
||
|
ha.dns_wc_tail.nelts) != NGX_OK)
|
||
|
{
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
hdcmcf->names.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
|
||
|
|
||
|
}
|
||
|
|
||
|
ngx_destroy_pool(ha.temp_pool);
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
if (regex == 0) {
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
hdcmcf->nregex = regex;
|
||
|
hdcmcf->regex = ngx_pcalloc(cf->pool,
|
||
|
regex * sizeof(ngx_http_dynamic_server_name_t));
|
||
|
if (hdcmcf->regex == NULL) {
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
i = 0;
|
||
|
|
||
|
for (s = 0; s < hdcmcf->servers.nelts; ++s) {
|
||
|
|
||
|
name = hdcscfp[s]->server_names.elts;
|
||
|
|
||
|
for (n = 0; n < hdcscfp[s]->server_names.nelts; ++n) {
|
||
|
if (name[n].regex) {
|
||
|
hdcmcf->regex[i++] = name[n];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return NGX_OK;
|
||
|
|
||
|
failed:
|
||
|
ngx_destroy_pool(ha.temp_pool);
|
||
|
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
|
||
|
static ngx_int_t
|
||
|
ngx_http_dynamic_core_find_virtual_server(ngx_http_request_t *r,
|
||
|
ngx_http_dynamic_core_main_conf_t *hdcmcf,
|
||
|
ngx_http_dynamic_core_srv_conf_t **hdcscfp)
|
||
|
{
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf;
|
||
|
ngx_str_t *server;
|
||
|
|
||
|
server = &r->headers_in.server;
|
||
|
|
||
|
hdcscf = ngx_hash_find_combined(&hdcmcf->names,
|
||
|
ngx_hash_key(server->data, server->len),
|
||
|
server->data, server->len);
|
||
|
|
||
|
if (hdcscf) {
|
||
|
*hdcscfp = hdcscf;
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
|
||
|
if (server->len && hdcmcf->nregex) {
|
||
|
ngx_int_t n;
|
||
|
ngx_uint_t i;
|
||
|
ngx_http_dynamic_server_name_t *sn;
|
||
|
|
||
|
sn = hdcmcf->regex;
|
||
|
|
||
|
for (i = 0; i < hdcmcf->nregex; ++i) {
|
||
|
|
||
|
n = ngx_regex_exec(sn[i].regex->regex, server, NULL, 0);
|
||
|
|
||
|
if (n == NGX_REGEX_NO_MATCHED) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (n >= 0) {
|
||
|
*hdcscfp = sn[i].server;
|
||
|
return NGX_OK;
|
||
|
}
|
||
|
|
||
|
return NGX_ERROR;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return NGX_DECLINED;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||
|
{
|
||
|
ngx_http_dynamic_module_t *module;
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf, *phdclcf;
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf;
|
||
|
ngx_conf_t pcf;
|
||
|
void *mconf, **loc_conf;
|
||
|
ngx_uint_t i, ci;
|
||
|
char *rv = NULL;
|
||
|
|
||
|
hdcscf = conf;
|
||
|
phdclcf = hdcscf->hdclcf;
|
||
|
|
||
|
/* loc_conf is temp cause hdclcf does not created now */
|
||
|
loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
|
||
|
if (loc_conf == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
for (i = 0; cf->cycle->modules[i]; ++i) {
|
||
|
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
module = (ngx_http_dynamic_module_t *)
|
||
|
cf->cycle->modules[i]->spare_hook0;
|
||
|
|
||
|
if (module == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (module->create_loc_conf) {
|
||
|
mconf = module->create_loc_conf(cf);
|
||
|
if (mconf == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hdclcf = loc_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
hdclcf->loc_conf = loc_conf;
|
||
|
|
||
|
if (ngx_http_dynamic_core_add_location(cf, &phdclcf->locations, hdclcf)
|
||
|
!= NGX_OK)
|
||
|
{
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
pcf = *cf;
|
||
|
cf->ctx = hdclcf->loc_conf;
|
||
|
cf->cmd_type = NGX_HTTP_LOC_CONF;
|
||
|
|
||
|
if (ngx_dynamic_conf_parse(cf, 0) != NGX_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
for (i = 0; cf->cycle->modules[i]; ++i) {
|
||
|
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
module = (ngx_http_dynamic_module_t *)
|
||
|
cf->cycle->modules[i]->spare_hook0;
|
||
|
ci = cf->cycle->modules[i]->ctx_index;
|
||
|
if (module == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (module->init_loc_conf) {
|
||
|
rv = module->init_loc_conf(cf, hdclcf->loc_conf[ci]);
|
||
|
if (rv != NGX_CONF_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*cf = pcf;
|
||
|
|
||
|
return NGX_CONF_OK;
|
||
|
|
||
|
failed:
|
||
|
*cf = pcf;
|
||
|
|
||
|
if (rv) {
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
|
||
|
void *conf)
|
||
|
{
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf;
|
||
|
u_char ch;
|
||
|
ngx_str_t *value;
|
||
|
ngx_uint_t i;
|
||
|
ngx_http_dynamic_server_name_t *sn;
|
||
|
|
||
|
hdcscf = conf;
|
||
|
|
||
|
value = cf->args->elts;
|
||
|
|
||
|
for (i = 1; i < cf->args->nelts; i++) {
|
||
|
|
||
|
ch = value[i].data[0];
|
||
|
|
||
|
if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
|
||
|
|| (ch == '.' && value[i].len < 2))
|
||
|
{
|
||
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||
|
"server name \"%V\" is invalid", &value[i]);
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
if (ngx_strchr(value[i].data, '/')) {
|
||
|
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||
|
"server name \"%V\" has suspicious symbols",
|
||
|
&value[i]);
|
||
|
}
|
||
|
|
||
|
sn = ngx_array_push(&hdcscf->server_names);
|
||
|
if (sn == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
sn->regex = NULL;
|
||
|
#endif
|
||
|
sn->server = hdcscf;
|
||
|
|
||
|
if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
|
||
|
sn->name = cf->cycle->hostname;
|
||
|
|
||
|
} else {
|
||
|
sn->name = value[i];
|
||
|
}
|
||
|
|
||
|
if (value[i].data[0] != '~') {
|
||
|
ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
#if (NGX_PCRE)
|
||
|
{
|
||
|
u_char *p;
|
||
|
ngx_regex_compile_t rc;
|
||
|
u_char errstr[NGX_MAX_CONF_ERRSTR];
|
||
|
|
||
|
if (value[i].len == 1) {
|
||
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||
|
"empty regex in server name \"%V\"", &value[i]);
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
value[i].len--;
|
||
|
value[i].data++;
|
||
|
|
||
|
ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
|
||
|
|
||
|
rc.pattern = value[i];
|
||
|
rc.err.len = NGX_MAX_CONF_ERRSTR;
|
||
|
rc.err.data = errstr;
|
||
|
|
||
|
for (p = value[i].data; p < value[i].data + value[i].len; p++) {
|
||
|
if (*p >= 'A' && *p <= 'Z') {
|
||
|
rc.options = NGX_REGEX_CASELESS;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sn->regex = ngx_dynamic_regex_compile(cf, &rc);
|
||
|
if (sn->regex == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
sn->name = value[i];
|
||
|
}
|
||
|
#else
|
||
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||
|
"using regex \"%V\" "
|
||
|
"requires PCRE library", &value[i]);
|
||
|
|
||
|
return NGX_CONF_ERROR;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return NGX_CONF_OK;
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||
|
{
|
||
|
ngx_http_dynamic_module_t *module;
|
||
|
ngx_http_dynamic_core_main_conf_t *hdcmcf;
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf, **hdcscfp;
|
||
|
ngx_http_dynamic_core_loc_conf_t *phdclcf;
|
||
|
ngx_conf_t pcf;
|
||
|
void *mconf, **srv_conf;
|
||
|
ngx_uint_t i, ci;
|
||
|
char *rv = NULL;
|
||
|
|
||
|
hdcmcf = conf;
|
||
|
|
||
|
/* srv_conf is temp cause hdcscf does not created now */
|
||
|
srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
|
||
|
if (srv_conf == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
for (i = 0; cf->cycle->modules[i]; ++i) {
|
||
|
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
module = (ngx_http_dynamic_module_t *)
|
||
|
cf->cycle->modules[i]->spare_hook0;
|
||
|
if (module == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (module->create_srv_conf) {
|
||
|
mconf = module->create_srv_conf(cf);
|
||
|
if (mconf == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
srv_conf[cf->cycle->modules[i]->ctx_index] = mconf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hdcscf = srv_conf[ngx_http_dynamic_core_module.ctx_index];
|
||
|
hdcscf->srv_conf = srv_conf;
|
||
|
|
||
|
hdcscf->hdclcf = ngx_pcalloc(cf->pool,
|
||
|
sizeof(ngx_http_dynamic_core_loc_conf_t));
|
||
|
|
||
|
/* save hdcscf into hdcmcf */
|
||
|
hdcscfp = ngx_array_push(&hdcmcf->servers);
|
||
|
if (hdcscfp == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
*hdcscfp = hdcscf;
|
||
|
|
||
|
pcf = *cf;
|
||
|
cf->ctx = hdcscf->srv_conf;
|
||
|
cf->cmd_type = NGX_HTTP_SRV_CONF;
|
||
|
|
||
|
if (ngx_dynamic_conf_parse(cf, 0) != NGX_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
for (i = 0; cf->cycle->modules[i]; ++i) {
|
||
|
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
module = (ngx_http_dynamic_module_t *)
|
||
|
cf->cycle->modules[i]->spare_hook0;
|
||
|
ci = cf->cycle->modules[i]->ctx_index;
|
||
|
if (module == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (module->init_srv_conf) {
|
||
|
rv = module->init_srv_conf(cf, hdcscf->srv_conf[ci]);
|
||
|
if (rv != NGX_CONF_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*cf = pcf;
|
||
|
|
||
|
phdclcf = hdcscf->hdclcf;
|
||
|
|
||
|
if (ngx_http_dynamic_core_init_locations(cf, phdclcf) != NGX_OK) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
if (ngx_http_dynamic_core_init_static_location_trees(cf, phdclcf) != NGX_OK) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
return NGX_CONF_OK;
|
||
|
|
||
|
failed:
|
||
|
*cf = pcf;
|
||
|
|
||
|
if (rv) {
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
return NGX_CONF_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
ngx_http_dynamic_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||
|
{
|
||
|
ngx_http_dynamic_conf_t *hdccf;
|
||
|
ngx_http_dynamic_module_t *module;
|
||
|
ngx_conf_t pcf;
|
||
|
ngx_uint_t i, ci;
|
||
|
char *rv = NULL;
|
||
|
|
||
|
hdccf = conf;
|
||
|
|
||
|
/* create main_conf ctx */
|
||
|
hdccf->main_conf = ngx_pcalloc(cf->pool, sizeof(void *)
|
||
|
* ngx_http_max_module);
|
||
|
if (hdccf->main_conf == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
/* create http dynamic conf for all http module */
|
||
|
for (i = 0; cf->cycle->modules[i]; ++i) {
|
||
|
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
module = (ngx_http_dynamic_module_t *)
|
||
|
cf->cycle->modules[i]->spare_hook0;
|
||
|
ci = cf->cycle->modules[i]->ctx_index;
|
||
|
|
||
|
if (module == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (module->create_main_conf) {
|
||
|
hdccf->main_conf[ci] = module->create_main_conf(cf);
|
||
|
if (hdccf->main_conf[ci] == NULL) {
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* save conf for recovery */
|
||
|
pcf = *cf;
|
||
|
|
||
|
cf->ctx = hdccf->main_conf;
|
||
|
cf->module_type = NGX_HTTP_MODULE;
|
||
|
cf->cmd_type = NGX_HTTP_MAIN_CONF;
|
||
|
|
||
|
if (ngx_dynamic_conf_parse(cf, 0) != NGX_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
for (i = 0; cf->cycle->modules[i]; ++i) {
|
||
|
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
module = (ngx_http_dynamic_module_t *)
|
||
|
cf->cycle->modules[i]->spare_hook0;
|
||
|
ci = cf->cycle->modules[i]->ctx_index;
|
||
|
|
||
|
if (module == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (module->init_main_conf) {
|
||
|
rv = module->init_main_conf(cf, hdccf->main_conf[ci]);
|
||
|
if (rv != NGX_CONF_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ngx_http_dynamic_core_init_virtual_servers(cf, hdccf) != NGX_OK) {
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
*cf = pcf;
|
||
|
|
||
|
return NGX_CONF_OK;
|
||
|
|
||
|
failed:
|
||
|
*cf = pcf;
|
||
|
|
||
|
if (rv) {
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
return NGX_CONF_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* interface from here */
|
||
|
|
||
|
void *
|
||
|
ngx_http_get_module_main_dconf(ngx_http_request_t *r, ngx_module_t *m)
|
||
|
{
|
||
|
ngx_http_dynamic_conf_t *hdcf;
|
||
|
|
||
|
hdcf = ngx_get_dconf(&ngx_http_dynamic_module);
|
||
|
if (hdcf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return hdcf->main_conf[m->ctx_index];
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
ngx_http_get_module_srv_dconf(ngx_http_request_t *r, ngx_module_t *m)
|
||
|
{
|
||
|
ngx_http_dynamic_core_main_conf_t *hdcmcf;
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf;
|
||
|
ngx_int_t rc;
|
||
|
|
||
|
hdcmcf = ngx_http_get_module_main_dconf(r, &ngx_http_dynamic_core_module);
|
||
|
if (hdcmcf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rc = ngx_http_dynamic_core_find_virtual_server(r, hdcmcf, &hdcscf);
|
||
|
switch (rc) {
|
||
|
case NGX_ERROR:
|
||
|
return NULL;
|
||
|
case NGX_DECLINED: /* virtual server not found */
|
||
|
return hdcmcf->default_server->srv_conf[m->ctx_index];
|
||
|
default:
|
||
|
return hdcscf->srv_conf[m->ctx_index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
ngx_http_get_module_loc_dconf(ngx_http_request_t *r, ngx_module_t *m)
|
||
|
{
|
||
|
ngx_http_dynamic_core_srv_conf_t *hdcscf;
|
||
|
ngx_http_dynamic_core_loc_conf_t *hdclcf;
|
||
|
ngx_int_t rc;
|
||
|
|
||
|
hdcscf = ngx_http_get_module_srv_dconf(r, &ngx_http_dynamic_core_module);
|
||
|
if (hdcscf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
hdclcf = NULL;
|
||
|
rc = ngx_http_dynamic_core_find_location(r, hdcscf, &hdclcf);
|
||
|
if (rc == NGX_ERROR) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (hdclcf) {
|
||
|
return hdclcf->loc_conf[m->ctx_index];
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|