前一篇讲过,对于HTTP指令块下的server,Nginx会为其创建相应的监听套接字,并且注册连接处理函数ngx_http_init_connection。
我们在ngx_event_accept中看到过,该函数会在accept后进行调用。
/* http/ngx_http_request.h */
typedef struct { // HTTP连接结构体定义
ngx_http_request_t *request; // HTTP请求
ngx_buf_t **busy;
ngx_int_t nbusy;
ngx_buf_t **free;
ngx_int_t nfree;
ngx_uint_t pipeline;
} ngx_http_connection_t;
/* http/ngx_http_request.c */
/* 初始化HTTP请求
* param rev: HTTP连接的读事件
*/
static void ngx_http_init_request(ngx_event_t *rev)
{
ngx_uint_t i;
socklen_t len;
struct sockaddr_in addr_in;
ngx_connection_t *c;
ngx_http_request_t *r;
ngx_http_in_port_t *in_port;
ngx_http_in_addr_t *in_addr;
ngx_http_connection_t *hc;
ngx_http_server_name_t *server_name;
ngx_http_core_srv_conf_t *cscf;
ngx_http_core_loc_conf_t *clcf;
#if (NGX_HTTP_SSL)
ngx_http_ssl_srv_conf_t *sscf;
#endif
c = rev->data;
if (rev->timedout) {
// 如果timedout为1, 表明客户端超时
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
#if (NGX_STAT_STUB)
(*ngx_stat_reading)--;
#endif
// 关闭HTTP连接
ngx_http_close_connection(c);
return;
}
// 从连接c获取其custom data, 在这里也就是HTTP连接
hc = c->data;
if (hc) {
#if (NGX_STAT_STUB)
(*ngx_stat_reading)++;
#endif
} else {
// 如果hc为空
// 从内存池c->pool申请一个ngx_http_connection_t结构体大小的内存空间hc
if (!(hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)))) {
#if (NGX_STAT_STUB)
(*ngx_stat_reading)--;
#endif
ngx_http_close_connection(c);
return;
}
}
// 获取HTTP连接hc的请求r
r = hc->request;
if (r) {
// 如果r不为空
// 对r置全0
ngx_memzero(r, sizeof(ngx_http_request_t));
r->pipeline = hc->pipeline;
if (hc->nbusy) {
r->header_in = hc->busy[0];
}
} else {
// 如果r为空
// 从内存池c->pool申请一个ngx_http_request_t结构体大小的内存空间r
if (!(r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)))) {
#if (NGX_STAT_STUB)
(*ngx_stat_reading)--;
#endif
ngx_http_close_connection(c);
return;
}
// 置hc->request为r
hc->request = r;
}
#if (NGX_STAT_STUB)
r->stat_reading = 1;
#endif
c->data = r;
r->http_connection = hc;
c->sent = 0;
r->signature = NGX_HTTP_MODULE;
in_port = c->servers;
in_addr = in_port->addrs.elts;
r->port = in_port->port;
r->port_text = &in_port->port_text;
i = 0;
if (in_port->addrs.nelts > 1) {
// 如果该端口的绑定地址列表的元素个数大于1,
// 即多宿主机下针对多块网卡绑定该端口
#if (WIN32)
if (c->local_sockaddr) {
r->in_addr =
((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
} else {
#endif
len = sizeof(struct sockaddr_in);
// 调用getsockname来获取连接的本地地址
if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) {
ngx_connection_error(c, ngx_socket_errno,
"getsockname() failed");
ngx_http_close_connection(c);
return;
}
// 记录HTTP请求的本地地址
r->in_addr = addr_in.sin_addr.s_addr;
#if (WIN32)
}
#endif
/* the last in_port->addrs address is "*" */
// 地址列表的最后一个元素必为通配地址?
for ( /* void */ ; i < in_port->addrs.nelts - 1; i++) {
if (in_addr[i].addr == r->in_addr) {
break;
}
}
} else {
// 如果该端口的绑定地址列表的元素个数不大于1,
// 那么HTTP请求的本地地址自然就是in_addr[0].addr
r->in_addr = in_addr[0].addr;
}
r->virtual_names = &in_addr[i].names;
/* the default server configuration for the address:port */
cscf = in_addr[i].core_srv_conf;
r->main_conf = cscf->ctx->main_conf;
r->srv_conf = cscf->ctx->srv_conf;
r->loc_conf = cscf->ctx->loc_conf;
// 更改读事件rev的事件处理函数为ngx_http_process_request_line,
// 顾名思义, 该函数用于读取和处理请求行
rev->event_handler = ngx_http_process_request_line;
#if (NGX_HTTP_SSL)
// 如果编译时, 加入了HTTP_SSL模块
// 获取ngx_http_ssl_module模块的server层次配置上下文sscf
sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
if (sscf->enable) {
// 如果sscf->enable为1, 即使能HTTPS
if (c->ssl == NULL) {
if (ngx_ssl_create_session(sscf->ssl_ctx, c, NGX_SSL_BUFFER)
== NGX_ERROR)
{
ngx_http_close_connection(c);
return;
}
c->ssl->no_rcv_shut = 1;
// 设置读事件rev的事件处理函数为ngx_http_ssl_handshake
rev->event_handler = ngx_http_ssl_handshake;
}
r->filter_need_in_memory = 1;
}
#endif
server_name = cscf->server_names.elts;
r->server_name = &server_name->name;
// 获取ngx_http_core_module模块的location层次配置上下文
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
c->log->file = clcf->err_log->file;
if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
c->log->log_level = clcf->err_log->log_level;
}
if (c->buffer == NULL) {
// 如果c->buffer为空
// 从内存池c->pool申请一个大小为client_header_buffer_size的临时缓冲区c->buffer
c->buffer = ngx_create_temp_buf(c->pool,
cscf->client_header_buffer_size);
if (c->buffer == NULL) {
ngx_http_close_connection(c);
return;
}
}
if (r->header_in == NULL) {
// 如果r->header_in为空, 即HTTP请求存放请求头的缓冲区为空
// 置r->header_in为c->buffer, 也就是使用连接c的buffer来作为请求r的header_in缓冲区
r->header_in = c->buffer;
}
// 创建大小为request_pool_size的内存池r->pool
if (!(r->pool = ngx_create_pool(cscf->request_pool_size, c->log))) {
ngx_http_close_connection(c);
return;
}
// 初始化r->cleanup数组: 使用的内存池为r->pool, 元素类型为ngx_http_cleanup_t, 初始容量为5
if (ngx_array_init(&r->cleanup, r->pool, 5, sizeof(ngx_http_cleanup_t))
== NGX_ERROR)
{
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
ngx_http_close_connection(c);
return;
}
// 初始化r->headers_out.headers单向链表: 每个链表节点的数据区: 元素类型为ngx_table_elt_t, 初始容量为20
if (ngx_list_init(&r->headers_out.headers, r->pool, 20,
sizeof(ngx_table_elt_t)) == NGX_ERROR)
{
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
ngx_http_close_connection(c);
return;
}
// 从内存池r->pool申请ngx_http_max_module个指针大小的内存空间r->ctx
r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
if (r->ctx == NULL) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
ngx_http_close_connection(c);
return;
}
c->single_connection = 1;
r->connection = c;
r->file.fd = NGX_INVALID_FILE;
r->headers_in.content_length_n = -1;
r->headers_in.keep_alive_n = -1;
r->headers_out.content_length_n = -1;
r->headers_out.last_modified_time = -1;
// 置r的http_state为NGX_HTTP_READING_REQUEST_STATE, 即正在读取HTTP请求
r->http_state = NGX_HTTP_READING_REQUEST_STATE;
#if (NGX_STAT_STUB)
(*ngx_stat_requests)++;
#endif
// 调用读事件rev的处理函数来对其进行处理
// 如果不启用HTTPS, 那么可想而知这里就是调用ngx_http_process_request_line
rev->event_handler(rev);
}
/* HTTP监听套接字的连接处理函数
* param c: 待处理的新连接
*/
void ngx_http_init_connection(ngx_connection_t *c)
{
ngx_event_t *rev;
ngx_http_log_ctx_t *ctx;
// 日志处理
if (!(ctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) {
ngx_http_close_connection(c);
return;
}
ctx->connection = c->number;
ctx->client = c->addr_text.data;
ctx->action = "reading client request line";
c->log->data = ctx;
c->log->handler = ngx_http_log_error;
c->log_error = NGX_ERROR_INFO;
// 获取连接c的读事件rev
rev = c->read;
// 设置读事件rev的事件处理函数为ngx_http_init_request
rev->event_handler = ngx_http_init_request;
// 设置连接c的写事件的事件处理函数为ngx_http_empty_handler;
// 顾名思义, ngx_http_empty_handler其实什么也不做, 因为在读取"完"HTTP请求前,
// 一般不会向客户端发送消息
/* STUB: epoll edge */ c->write->event_handler = ngx_http_empty_handler;
if (rev->ready) {
// 如果rev的ready标志位为1, 即当前可读
// 当我们设置了deferred accept时, accept后已连接套接字即为可读
if (ngx_accept_mutex) {
// 如果ngx_accept_mutex不为空, 说明使用互斥锁来防止惊群现象,
// 此时把读事件rev放进延迟处理队列等候处理
// 获取ngx_posted_events_mutex锁
if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
ngx_http_close_connection(c);
return;
}
// 将rev添加进延迟处理队列
ngx_post_event(rev);
// 解锁ngx_posted_events_mutex
ngx_mutex_unlock(ngx_posted_events_mutex);
return;
}
#if (NGX_STAT_STUB)
// 使能Nginx的统计功能时, ngx_stat_reading所指变量加1
(*ngx_stat_reading)++;
#endif
// 直接调用ngx_http_init_request对读事件rev进行处理
ngx_http_init_request(rev);
return;
}
// 将读事件rev添加到定时器红黑树中, 超时时间为post_accept_timeout;
// post_accept_timeout顾名思义, 在accept连接后等待第一次读事件的超时时间,
// 避免客户端连接后长时间不发送请求的问题
ngx_add_timer(rev, c->listening->post_accept_timeout);
// 将读事件rev添加到epoll句柄中
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
ngx_http_close_connection(c);
return;
}
#if 0
// 因为暂时不会向客户端发送消息, 所以不需要为写事件注册处理函数,
// 更不需要将写事件添加到epoll句柄
c->write->ready = 0;
c->write->event_handler = ngx_http_dummy;
if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
ngx_http_close_connection(c);
return;
}
#endif
#if (NGX_STAT_STUB)
(*ngx_stat_reading)++;
#endif
}