先看看ngx_http_init_listening,在系列文章中已经提到过这个函数,他的第三个参数port是一个结构体,定义如下
typedef struct {
ngx_int_t family;
in_port_t port;
ngx_array_t addrs; /* array of ngx_http_conf_addr_t */
} ngx_http_conf_port_t;
前面2个成员变量的含义不言自明,第三个变量addrs是一个数组,填写的是什么呢,是一个叫做ngx_http_conf_addr_t的结构体:
typedef struct {
ngx_http_listen_opt_t opt;
ngx_hash_t hash;
ngx_hash_wildcard_t *wc_head;
ngx_hash_wildcard_t *wc_tail;
#if (NGX_PCRE)
ngx_uint_t nregex;
ngx_http_server_name_t *regex;
#endif
/* the default server configuration for this address:port */
ngx_http_core_srv_conf_t *default_server;
ngx_array_t servers; /* array of ngx_http_core_srv_conf_t */
} ngx_http_conf_addr_t;
他有2个比较重要的成员,opt包含了真实的ip地址,default_server指向这个地址端口对应的配置文件中的默认server{}配置块,servers则指向匹配的所有server块。
然后调用定义一个hport,并调用ngx_http_add_addrs把addrs数组的值传递给hport的addrs成员,特别是把default_server传递过来。最后,hport会指向ls->servers,这个值会在ngx_http_init_connection里面用到。
跳转到这个函数,看看他的具体代码:
hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));
if (hc == NULL) {
ngx_http_close_connection(c);
return;
}
c->data = hc;
/* find the server configuration for the address:port */
port = c->listening->servers;
首先根据c->listening->servers找到port,并搜索port->addrs中与c->local_sockaddr相等的地址,然后把他的成员conf传递给hc->addr_conf,hc是一个指向c->data的ngx_http_connect_t的结构体指针,再看下面这句代码:
hc->conf_ctx = hc->addr_conf->default_server->ctx;
hc->conf_ctx 的定义如下
typedef struct {
void **main_conf;
void **srv_conf;
void **loc_conf;
} ngx_http_conf_ctx_t;
这样,hc包含了一个ngx_connection_t对应的所有ngx_http_core_srv_conf_t和ngx_http_core_loc_conf_t。
最后在ngx_http_create_request中,这些指针会传递给ngx_http_request_t的成员:
r->main_conf = hc->conf_ctx->main_conf;
r->srv_conf = hc->conf_ctx->srv_conf;
r->loc_conf = hc->conf_ctx->loc_conf;
每个独立http请求都会通过NGX_HTTP_FIND_CONFIG_PHASE这个阶段,对应的函数是:ngx_http_core_find_config_phase
因为location是放在二叉树结构中,该函数最重要的动作就是递归调用ngx_http_core_find_location,通过ngx_http_regex_exec来匹配r->uri。如果匹配成功就返回,否则继续递归调用,