locations 设计和实现
来源:互联网 发布:android web服务器软件 编辑:程序博客网 时间:2024/05/16 09:06
Locations 数据结构及初始化
1) 先看看 ngx_http_core_loc_conf_t 这个结构体
2) 配置文件中,location 指令对应的处理函数是 ngx_http_core_location,先分析下这个函数
2) 下面分析下 ngx_http_add_location 函数
创建 Locations Tree
1) http block 的配置解析完成后,locations 的结构初始化完成(见上面分析)。
仍然在 ngx_http_block 函数中,随后开始了 locations tree 的构建。
2) ngx_http_init_locations 完成的任务其实比较简单。
首先执行 ngx_queue_sort(locations, ngx_http_cmp_locations) 对 locations 进行排序,排序规则比较复杂,请参见 ngx_http_cmp_locations 函数。
然后将 regex location 和 named location 这两种 location 分离出来,分别存储在 cscf->named_locations 和 pclcf->regex_locations 队列里面,这两种 locations 不参与 location tree 的构建。location tree 只是 static location。
3) ngx_http_init_static_location_trees 开始 static location 的构建。
4) ngx_http_create_locations_list 函数
下面简要分析下这个函数
5) 构建 location tree 的过程
ngx_http_create_locations_tree 函数会利用上面构建的 locations list,来构建一个真正的前缀树,它是一个三叉树。
下面看代码:
Location 的查找
1) 先看看 ngx_http_core_loc_conf_t 这个结构体
struct ngx_http_core_loc_conf_s {
// location 名称
ngx_str_t name;
// 如果是 re location,这里存储 re 信息
#if (NGX_PCRE)
ngx_http_regex_t *regex;
#endif
//...
// 是否是精确匹配 location =xxx
unsigned exact_match:1;
unsigned noregex:1;
//...
// locations 子树
ngx_http_location_tree_node_t *static_locations;
#if (NGX_PCRE)
ngx_http_core_loc_conf_t **regex_locations;
#endif
/* pointer to the modules' loc_conf */
void **loc_conf;
//...
// ngx_queue_t 包含一个 *prev 和一个 *next 指针,用于构造链表。
ngx_queue_t *locations;
};
Nginx 的 locations 数据结构信息,都存储在这个结构体里面。// location 名称
ngx_str_t name;
// 如果是 re location,这里存储 re 信息
#if (NGX_PCRE)
ngx_http_regex_t *regex;
#endif
//...
// 是否是精确匹配 location =xxx
unsigned exact_match:1;
unsigned noregex:1;
//...
// locations 子树
ngx_http_location_tree_node_t *static_locations;
#if (NGX_PCRE)
ngx_http_core_loc_conf_t **regex_locations;
#endif
/* pointer to the modules' loc_conf */
void **loc_conf;
//...
// ngx_queue_t 包含一个 *prev 和一个 *next 指针,用于构造链表。
ngx_queue_t *locations;
};
2) 配置文件中,location 指令对应的处理函数是 ngx_http_core_location,先分析下这个函数
static char *
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,void *dummy)
{
//...
// 创建 location 的 ctx
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
// 保存下父 ctx,可能是 server 的 ctx,也可能是父 location 的 ctx
pctx = cf->ctx;
// location 级别,无特别的 main_conf 和 srv_conf,直接用父级别的
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf;
// 创建 loc_conf
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) *ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
// 初始化 loc_conf
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_loc_conf) {
ctx->loc_conf[ngx_modules[i]->ctx_index] =
module->create_loc_conf(cf);
if (ctx->loc_conf[ngx_modules[i]->ctx_index] ==NULL) {
return NGX_CONF_ERROR;
}
}
}
// 获取 ngx_http_core_loc_conf_t 的配置
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
// 保存下当前的 loc_conf 到 clcf 中,用途后面分析
clcf->loc_conf = ctx->loc_conf;
// 获取 location 行解析结果,数组类型,如:["location", "^~", "/images/"]
value = cf->args->elts;
// 根据参数个数不同,来判断 location 类型,对对相应字段赋值
// 如果是正则表达式,则会调用 ngx_http_core_regex_location 对 re 进行编译
if (cf->args->nelts == 3) {
len = value[1].len;
mod = value[1].data;
name = &value[2];
if (len == 1 && mod[0] == '=') {
//..
}
//..
}else {
//...
}
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
// ...
// 将当前的 location 配置加入的父 locations 的队列里面
if (ngx_http_add_location(cf, &pclcf->locations, clcf) !=NGX_OK) {
return NGX_CONF_ERROR;
}
// 保存当前配置,然后继续向下解析
save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF;
// 解析 location 内的配置
rv = ngx_conf_parse(cf, NULL);
*cf = save;
// 返回
return rv;
}
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,void *dummy)
{
//...
// 创建 location 的 ctx
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
// 保存下父 ctx,可能是 server 的 ctx,也可能是父 location 的 ctx
pctx = cf->ctx;
// location 级别,无特别的 main_conf 和 srv_conf,直接用父级别的
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf;
// 创建 loc_conf
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) *ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
// 初始化 loc_conf
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_loc_conf) {
ctx->loc_conf[ngx_modules[i]->ctx_index] =
module->create_loc_conf(cf);
if (ctx->loc_conf[ngx_modules[i]->ctx_index] ==NULL) {
return NGX_CONF_ERROR;
}
}
}
// 获取 ngx_http_core_loc_conf_t 的配置
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
// 保存下当前的 loc_conf 到 clcf 中,用途后面分析
clcf->loc_conf = ctx->loc_conf;
// 获取 location 行解析结果,数组类型,如:["location", "^~", "/images/"]
value = cf->args->elts;
// 根据参数个数不同,来判断 location 类型,对对相应字段赋值
// 如果是正则表达式,则会调用 ngx_http_core_regex_location 对 re 进行编译
if (cf->args->nelts == 3) {
len = value[1].len;
mod = value[1].data;
name = &value[2];
if (len == 1 && mod[0] == '=') {
//..
}
//..
}else {
//...
}
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
// ...
// 将当前的 location 配置加入的父 locations 的队列里面
if (ngx_http_add_location(cf, &pclcf->locations, clcf) !=NGX_OK) {
return NGX_CONF_ERROR;
}
// 保存当前配置,然后继续向下解析
save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF;
// 解析 location 内的配置
rv = ngx_conf_parse(cf, NULL);
*cf = save;
// 返回
return rv;
}
2) 下面分析下 ngx_http_add_location 函数
ngx_int_t
ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
ngx_http_core_loc_conf_t *clcf)
{
ngx_http_location_queue_t *lq;
// 创建 locations 队列
if (*locations == NULL) {
*locations = ngx_palloc(cf->temp_pool,
sizeof(ngx_http_location_queue_t));
if (*locations == NULL) {
return NGX_ERROR;
}
ngx_queue_init(*locations);
}
// 创建队列 item
lq = ngx_palloc(cf->temp_pool,sizeof(ngx_http_location_queue_t));
if (lq == NULL) {
return NGX_ERROR;
}
// 设置队列 item 的 exact 和 inclusive 成员
// 也就是之前创建的 ngx_http_core_loc_conf_t 变量 clcf
if (clcf->exact_match
#if (NGX_PCRE)
|| clcf->regex
#endif
|| clcf->named || clcf->noname)
{
lq->exact = clcf;
lq->inclusive = NULL;
} else {
lq->exact = NULL;
lq->inclusive = clcf;
}
lq->name = &clcf->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_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
ngx_http_core_loc_conf_t *clcf)
{
ngx_http_location_queue_t *lq;
// 创建 locations 队列
if (*locations == NULL) {
*locations = ngx_palloc(cf->temp_pool,
sizeof(ngx_http_location_queue_t));
if (*locations == NULL) {
return NGX_ERROR;
}
ngx_queue_init(*locations);
}
// 创建队列 item
lq = ngx_palloc(cf->temp_pool,sizeof(ngx_http_location_queue_t));
if (lq == NULL) {
return NGX_ERROR;
}
// 设置队列 item 的 exact 和 inclusive 成员
// 也就是之前创建的 ngx_http_core_loc_conf_t 变量 clcf
if (clcf->exact_match
#if (NGX_PCRE)
|| clcf->regex
#endif
|| clcf->named || clcf->noname)
{
lq->exact = clcf;
lq->inclusive = NULL;
} else {
lq->exact = NULL;
lq->inclusive = clcf;
}
lq->name = &clcf->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;
}
创建 Locations Tree
1) http block 的配置解析完成后,locations 的结构初始化完成(见上面分析)。
仍然在 ngx_http_block 函数中,随后开始了 locations tree 的构建。
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
//...
/* create location trees */
for (s = 0; s < cmcf->servers.nelts; s++) {
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
if (ngx_http_init_locations(cf, cscfp[s], clcf) !=NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_http_init_static_location_trees(cf, clcf) !=NGX_OK) {
return NGX_CONF_ERROR;
}
}
//...
}
遍历每个 server,先执行 ngx_http_init_locations ,然后执行ngx_http_init_static_location_trees 完成 locations tree 的构建。ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
//...
/* create location trees */
for (s = 0; s < cmcf->servers.nelts; s++) {
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
if (ngx_http_init_locations(cf, cscfp[s], clcf) !=NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_http_init_static_location_trees(cf, clcf) !=NGX_OK) {
return NGX_CONF_ERROR;
}
}
//...
}
2) ngx_http_init_locations 完成的任务其实比较简单。
首先执行 ngx_queue_sort(locations, ngx_http_cmp_locations) 对 locations 进行排序,排序规则比较复杂,请参见 ngx_http_cmp_locations 函数。
然后将 regex location 和 named location 这两种 location 分离出来,分别存储在 cscf->named_locations 和 pclcf->regex_locations 队列里面,这两种 locations 不参与 location tree 的构建。location tree 只是 static location。
3) ngx_http_init_static_location_trees 开始 static location 的构建。
static ngx_int_t
ngx_http_init_static_location_trees(ngx_conf_t *cf,
ngx_http_core_loc_conf_t *pclcf)
{
//...
locations = pclcf->locations;
if (locations == NULL) {
return NGX_OK;
}
if (ngx_queue_empty(locations)) {
return NGX_OK;
}
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
// 递归创建子 locations tree
if (ngx_http_init_static_location_trees(cf, clcf) !=NGX_OK) {
return NGX_ERROR;
}
}
// 合并相同的 Static location
if (ngx_http_join_exact_locations(cf, locations) !=NGX_OK) {
return NGX_ERROR;
}
// 将具有相同前缀的 locations 转移到 q->list 成员里面
// 待下面详细分析
ngx_http_create_locations_list(locations,ngx_queue_head(locations));
// 创建 location tree,下面详细分析
pclcf->static_locations =ngx_http_create_locations_tree(cf, locations, 0);
if (pclcf->static_locations == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}
ngx_http_init_static_location_trees(ngx_conf_t *cf,
ngx_http_core_loc_conf_t *pclcf)
{
//...
locations = pclcf->locations;
if (locations == NULL) {
return NGX_OK;
}
if (ngx_queue_empty(locations)) {
return NGX_OK;
}
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
// 递归创建子 locations tree
if (ngx_http_init_static_location_trees(cf, clcf) !=NGX_OK) {
return NGX_ERROR;
}
}
// 合并相同的 Static location
if (ngx_http_join_exact_locations(cf, locations) !=NGX_OK) {
return NGX_ERROR;
}
// 将具有相同前缀的 locations 转移到 q->list 成员里面
// 待下面详细分析
ngx_http_create_locations_list(locations,ngx_queue_head(locations));
// 创建 location tree,下面详细分析
pclcf->static_locations =ngx_http_create_locations_tree(cf, locations, 0);
if (pclcf->static_locations == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}
4) ngx_http_create_locations_list 函数
ngx_http_create_locations_list 处理比较复杂。假设有这么一些排好序的 locations 队列。
a ab abc abd ac acd ae bc bcd be,那么经过 ngx_http_create_locations_list 处理后,构造出来的结构大家如下图:
下面简要分析下这个函数
static void
ngx_http_create_locations_list(ngx_queue_t *locations,ngx_queue_t *q)
{
//...
// 队列最后一个元素,递归结束
if (q == ngx_queue_last(locations)) {
return;
}
lq = (ngx_http_location_queue_t *) q;
// 非 inclusive 类型,无需处理,处理下一个
if (lq->inclusive == NULL) {
ngx_http_create_locations_list(locations,ngx_queue_next(q));
return;
}
// 获取当前 location 的 name 和 name 的长度
len = lq->name->len;
name = lq->name->data;
// 以 lq 为准,把所有以 lq->name 为前缀的 location 全部取出来
// 由于所有的 locations 都是经过排序,相同前缀按长度排列在一起
// 这里是寻找第一个不是以 lq->name 为前缀的 location 元素 x
// x 之前的元素,都具有相同的前缀 lq->name
for (x = ngx_queue_next(q);
x != ngx_queue_sentinel(locations);
x = ngx_queue_next(x))
{
lx = (ngx_http_location_queue_t *) x;
if (len > lx->name->len
|| (ngx_strncmp(name, lx->name->data, len) != 0))
{
break;
}
}
// 下面几行的的含义是
// 除 lq 元素外,将其它具有相同前缀的 location 队列从 locations 里面分出来
// 然后放入 lq->list 队列里面,剩余的仍然保留在 locations 队列里面等待处理
q = ngx_queue_next(q);
if (q == x) {
ngx_http_create_locations_list(locations, x);
return;
}
ngx_queue_split(locations, q, &tail);
ngx_queue_add(&lq->list, &tail);
// 如果 locations 队列处理完毕,则开始递归处理 lq->list
if (x == ngx_queue_sentinel(locations)) {
ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));
return;
}
ngx_queue_split(&lq->list, x, &tail);
ngx_queue_add(locations, &tail);
// 递归处理 lq->list 里面的 location
ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));
// 继续处理 locations 队列里面的 location
ngx_http_create_locations_list(locations, x);
}
ngx_http_create_locations_list(ngx_queue_t *locations,ngx_queue_t *q)
{
//...
// 队列最后一个元素,递归结束
if (q == ngx_queue_last(locations)) {
return;
}
lq = (ngx_http_location_queue_t *) q;
// 非 inclusive 类型,无需处理,处理下一个
if (lq->inclusive == NULL) {
ngx_http_create_locations_list(locations,ngx_queue_next(q));
return;
}
// 获取当前 location 的 name 和 name 的长度
len = lq->name->len;
name = lq->name->data;
// 以 lq 为准,把所有以 lq->name 为前缀的 location 全部取出来
// 由于所有的 locations 都是经过排序,相同前缀按长度排列在一起
// 这里是寻找第一个不是以 lq->name 为前缀的 location 元素 x
// x 之前的元素,都具有相同的前缀 lq->name
for (x = ngx_queue_next(q);
x != ngx_queue_sentinel(locations);
x = ngx_queue_next(x))
{
lx = (ngx_http_location_queue_t *) x;
if (len > lx->name->len
|| (ngx_strncmp(name, lx->name->data, len) != 0))
{
break;
}
}
// 下面几行的的含义是
// 除 lq 元素外,将其它具有相同前缀的 location 队列从 locations 里面分出来
// 然后放入 lq->list 队列里面,剩余的仍然保留在 locations 队列里面等待处理
q = ngx_queue_next(q);
if (q == x) {
ngx_http_create_locations_list(locations, x);
return;
}
ngx_queue_split(locations, q, &tail);
ngx_queue_add(&lq->list, &tail);
// 如果 locations 队列处理完毕,则开始递归处理 lq->list
if (x == ngx_queue_sentinel(locations)) {
ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));
return;
}
ngx_queue_split(&lq->list, x, &tail);
ngx_queue_add(locations, &tail);
// 递归处理 lq->list 里面的 location
ngx_http_create_locations_list(&lq->list,ngx_queue_head(&lq->list));
// 继续处理 locations 队列里面的 location
ngx_http_create_locations_list(locations, x);
}
5) 构建 location tree 的过程
ngx_http_create_locations_tree 函数会利用上面构建的 locations list,来构建一个真正的前缀树,它是一个三叉树。
下面看代码:
/*
* to keep cache locality for left leaf nodes, allocate nodes in following
* order: node, left subtree, right subtree, inclusive subtree
*/
static ngx_http_location_tree_node_t *
ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t*locations,
size_t prefix)
{
size_t len;
ngx_queue_t *q, tail;
ngx_http_location_queue_t *lq;
ngx_http_location_tree_node_t *node;
// 取得居中的 location,准备将 locations 分为两半
q = ngx_queue_middle(locations);
lq = (ngx_http_location_queue_t *) q;
// 取得当前除去 prefix 后 name 的长度
len = lq->name->len - prefix;
node = ngx_palloc(cf->pool,
offsetof(ngx_http_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->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
|| (lq->inclusive && lq->inclusive->auto_redirect));
node->len = (u_char) len;
// 给 lq->name 赋值,其值为 lq->name 去掉 prefix 后的部分
ngx_memcpy(node->name, &lq->name->data[prefix], len);
// 将 locations 分为两半
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;
}
// locations 这一半用来构建左字树
node->left = ngx_http_create_locations_tree(cf, locations,prefix);
if (node->left == NULL) {
return NULL;
}
// 将当前 location 移除队列
ngx_queue_remove(q);
if (ngx_queue_empty(&tail)) {
goto inclusive;
}
// 用另外一半构建右子树
node->right = ngx_http_create_locations_tree(cf, &tail,prefix);
if (node->right == NULL) {
return NULL;
}
inclusive:
if (ngx_queue_empty(&lq->list)) {
return node;
}
// 递归构建 lq->list tree,prefix = prefix + len
node->tree = ngx_http_create_locations_tree(cf, &lq->list,prefix + len);
if (node->tree == NULL) {
return NULL;
}
return node;
}
* to keep cache locality for left leaf nodes, allocate nodes in following
* order: node, left subtree, right subtree, inclusive subtree
*/
static ngx_http_location_tree_node_t *
ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t*locations,
size_t prefix)
{
size_t len;
ngx_queue_t *q, tail;
ngx_http_location_queue_t *lq;
ngx_http_location_tree_node_t *node;
// 取得居中的 location,准备将 locations 分为两半
q = ngx_queue_middle(locations);
lq = (ngx_http_location_queue_t *) q;
// 取得当前除去 prefix 后 name 的长度
len = lq->name->len - prefix;
node = ngx_palloc(cf->pool,
offsetof(ngx_http_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->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
|| (lq->inclusive && lq->inclusive->auto_redirect));
node->len = (u_char) len;
// 给 lq->name 赋值,其值为 lq->name 去掉 prefix 后的部分
ngx_memcpy(node->name, &lq->name->data[prefix], len);
// 将 locations 分为两半
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;
}
// locations 这一半用来构建左字树
node->left = ngx_http_create_locations_tree(cf, locations,prefix);
if (node->left == NULL) {
return NULL;
}
// 将当前 location 移除队列
ngx_queue_remove(q);
if (ngx_queue_empty(&tail)) {
goto inclusive;
}
// 用另外一半构建右子树
node->right = ngx_http_create_locations_tree(cf, &tail,prefix);
if (node->right == NULL) {
return NULL;
}
inclusive:
if (ngx_queue_empty(&lq->list)) {
return node;
}
// 递归构建 lq->list tree,prefix = prefix + len
node->tree = ngx_http_create_locations_tree(cf, &lq->list,prefix + len);
if (node->tree == NULL) {
return NULL;
}
return node;
}
Location 的查找
下面分析下,玩家请求过来后,根据玩家访问的 url 查找到对应的 location 的过程。
查找逻辑在 ngx_http_core_find_location 里面,比较简单。
1) 首先查找上面创建的 location tree,典型的树的查找方法,没啥新鲜的,如果查找成功,设置 r->loc_conf。
2) 如果 location tree 没有,则逐个遍历 regex_locations,利用正则表达式进行匹配比较。
简要代码如下:
查找逻辑在 ngx_http_core_find_location 里面,比较简单。
1) 首先查找上面创建的 location tree,典型的树的查找方法,没啥新鲜的,如果查找成功,设置 r->loc_conf。
2) 如果 location tree 没有,则逐个遍历 regex_locations,利用正则表达式进行匹配比较。
简要代码如下:
static ngx_int_t
ngx_http_core_find_location(ngx_http_request_t *r)
{
//...
pclcf = ngx_http_get_module_loc_conf(r,ngx_http_core_module);
// 查找 location tree
rc = ngx_http_core_find_static_location(r, pclcf->static_locations);
//...
if (noregex == 0 && pclcf->regex_locations) {
for (clcfp = pclcf->regex_locations; *clcfp; clcfp++){
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"test location: ~ \"%V\"", &(*clcfp)->name);
n = ngx_http_regex_exec(r, (*clcfp)->regex, &r->uri);
if (n == NGX_OK) {
r->loc_conf = (*clcfp)->loc_conf;
/* look up nested locations */
rc = ngx_http_core_find_location(r);
return (rc == NGX_ERROR) ? rc : NGX_OK;
}
if (n == NGX_DECLINED) {
continue;
}
return NGX_ERROR;
}
}
//..
}
ngx_http_core_find_location(ngx_http_request_t *r)
{
//...
pclcf = ngx_http_get_module_loc_conf(r,ngx_http_core_module);
// 查找 location tree
rc = ngx_http_core_find_static_location(r, pclcf->static_locations);
//...
if (noregex == 0 && pclcf->regex_locations) {
for (clcfp = pclcf->regex_locations; *clcfp; clcfp++){
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"test location: ~ \"%V\"", &(*clcfp)->name);
n = ngx_http_regex_exec(r, (*clcfp)->regex, &r->uri);
if (n == NGX_OK) {
r->loc_conf = (*clcfp)->loc_conf;
/* look up nested locations */
rc = ngx_http_core_find_location(r);
return (rc == NGX_ERROR) ? rc : NGX_OK;
}
if (n == NGX_DECLINED) {
continue;
}
return NGX_ERROR;
}
}
//..
}
----
0 0
- locations 设计和实现
- Configuring Locations(配置locations)
- OLAP设计和实现
- spinlock的设计和实现
- spinlock的设计和实现
- 设备管理系统设计和实现
- spinlock的设计和实现
- AC的设计和实现
- 计算器的设计和实现
- 单链表的设计和实现
- FSM设计和实现1
- FSM设计和实现2
- MXNet设计和实现简介
- MXNet设计和实现简介
- MXNet设计和实现简介
- MXNet设计和实现简介
- # java AQS设计和实现
- MXNet设计和实现简介
- perl 文本内容转hash数组
- hadoop中有时运行会提示mapper找不到
- 程序员困境
- 2416背光亮度
- Test
- locations 设计和实现
- [leetcode] 5. Longest Palindromic Substring
- 使用渲染纹理的制作摄像头
- 构建高并发高可用的电商平台架构实践
- 代码混淆详解
- Python的字典操作
- OC学习 第一节
- [Servlet&JSP] 表达式语言EL
- 【TRIM】TRIM函数“去空格” 功能之外的洞天