Nginx-请求处理与响应
void ngx_http_init_connection(ngx_connection_t *c)
{
ngx_uint_t i;
ngx_event_t *rev;
struct sockaddr_in *sin;
ngx_http_port_t *port;
ngx_http_in_addr_t *addr;
ngx_http_log_ctx_t *ctx;
ngx_http_connection_t *hc;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
ngx_http_in6_addr_t *addr6;
#endif 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;
//监听套接口上有多个目的IP
if (port->naddrs > ) { /*
* there are several addresses on this port and one of them
* is an "*:port" wildcard so getsockname() in ngx_http_server_addr()
* is required to determine a server address
*/ if (ngx_connection_local_sockaddr(c, NULL, ) != NGX_OK) {
ngx_http_close_connection(c);
return;
} switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) c->local_sockaddr; addr6 = port->addrs; /* the last address is "*" */ for (i = ; i < port->naddrs - ; i++) {
if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, ) == ) {
break;
}
} hc->addr_conf = &addr6[i].conf; break;
#endif default: /* AF_INET */
sin = (struct sockaddr_in *) c->local_sockaddr; addr = port->addrs; /* the last address is "*" */ for (i = ; i < port->naddrs - ; i++) {
if (addr[i].addr == sin->sin_addr.s_addr) {
break;
}
} hc->addr_conf = &addr[i].conf; break;
} } else { switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6)
case AF_INET6:
addr6 = port->addrs;
hc->addr_conf = &addr6[].conf;
break;
#endif default: /* AF_INET */
addr = port->addrs;
hc->addr_conf = &addr[].conf;
break;
}
} /* the default server configuration for the address:port */
hc->conf_ctx = hc->addr_conf->default_server->ctx;
//当监听套接口只有一个目的IP时,将该地址上的server设置为默认server
//还会有后续处理0
ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
if (ctx == NULL) {
ngx_http_close_connection(c);
return;
} ctx->connection = c;
ctx->request = NULL;
ctx->current_request = NULL; c->log->connection = c->number;
c->log->handler = ngx_http_log_error;
c->log->data = ctx;
c->log->action = "waiting for request"; c->log_error = NGX_ERROR_INFO; rev = c->read;
rev->handler = ngx_http_wait_request_handler;
c->write->handler = ngx_http_empty_handler; #if (NGX_HTTP_V2)
if (hc->addr_conf->http2) {
rev->handler = ngx_http_v2_init;
}
#endif #if (NGX_HTTP_SSL)
//https 的SSL加密
{
ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); if (sscf->enable || hc->addr_conf->ssl) { c->log->action = "SSL handshaking"; if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) {
ngx_log_error(NGX_LOG_ERR, c->log, ,
"no \"ssl_certificate\" is defined "
"in server listening on SSL port");
ngx_http_close_connection(c);
return;
} hc->ssl = ; rev->handler = ngx_http_ssl_handshake;
}
}
#endif if (hc->addr_conf->proxy_protocol) {
hc->proxy_protocol = ;
c->log->action = "reading PROXY protocol";
} if (rev->ready) {
/* the deferred accept(), iocp */
//accept()接受服务端的请求后将请求数据已经准备好了,然后着手处理
if (ngx_use_accept_mutex) {
//有加锁 将事件对象加入ngx_posted_events链表中 然后释放锁 释放锁后在处理事件
ngx_post_event(rev, &ngx_posted_events);
return;
}
//没有假如事件监控机制中,是因为当所有的请求数据都已经到达后 读取数据处理请求然后响应即可,没有必要再加
//入事件监控机制中,如果加入了 什么作用都没有起到,然后在删除 做的都是无用功
rev->handler(rev);
return;
}
//recv->ready == 0加入超时管理机制和事件监控机制中
ngx_add_timer(rev, c->listening->post_accept_timeout);
ngx_reusable_connection(c, ); if (ngx_handle_read_event(rev, ) != NGX_OK) {
ngx_http_close_connection(c);
return;
} }
请求处理
函数ngx_http_process_line()处理的数据就是从客户端发送过来的http请求头中的Request_Line。分为三步 1.读取Request_line数据,2.解析Request_line 3.存储解析结果并设置相关值
第一步:读取Request_Line数据。通过函数ngx_http_read_request_header()将数据存储到r->header_in中。
第二步:解析Request_Line。将读取到的Request_Line数据进行解析的工作实现在ngx_http_process_request_line()中
第三步:存储解析结果并设置相关值。在Request_Line的解析过程中会有一些赋值操作,但更多的是在成功解析后。
static void ngx_http_process_request_line(ngx_event_t *rev)
{
ssize_t n;
ngx_int_t rc, rv;
ngx_str_t host;
ngx_connection_t *c;
ngx_http_request_t *r; c = rev->data;
r = c->data; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, ,
"http process request line");
//超时直接返回
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = ;
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
} rc = NGX_AGAIN;
//解析数据
for ( ;; ) { if (rc == NGX_AGAIN) {
n = ngx_http_read_request_header(r);
//读取数据
if (n == NGX_AGAIN || n == NGX_ERROR) {
return;
}
}
// 解析数据 存储解析结果 将解析结果存储在 r->header_in 中
rc = ngx_http_parse_request_line(r, r->header_in);
//解析成功
if (rc == NGX_OK) { /* the request line has been parsed successfully */ r->request_line.len = r->request_end - r->request_start;
r->request_line.data = r->request_start;
r->request_length = r->header_in->pos - r->request_start; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, ,
"http request line: \"%V\"", &r->request_line); r->method_name.len = r->method_end - r->request_start + ;
r->method_name.data = r->request_line.data; if (r->http_protocol.data) {
r->http_protocol.len = r->request_end - r->http_protocol.data;
} if (ngx_http_process_request_uri(r) != NGX_OK) {
return;
} if (r->host_start && r->host_end) { host.len = r->host_end - r->host_start;
host.data = r->host_start; rc = ngx_http_validate_host(&host, r->pool, ); if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_INFO, c->log, ,
"client sent invalid host in request line");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return;
} if (rc == NGX_ERROR) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
} if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {
return;
} r->headers_in.server = host;
} if (r->http_version < NGX_HTTP_VERSION_10) { if (r->headers_in.server.len ==
&& ngx_http_set_virtual_server(r, &r->headers_in.server)
== NGX_ERROR)
{
return;
} ngx_http_process_request(r);
return;
} if (ngx_list_init(&r->headers_in.headers, r->pool, ,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
} c->log->action = "reading client request headers"; rev->handler = ngx_http_process_request_headers;
ngx_http_process_request_headers(rev); return;
} if (rc != NGX_AGAIN) { /* there was error while a request line parsing */ ngx_log_error(NGX_LOG_INFO, c->log, ,
ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]);
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return;
} /* NGX_AGAIN: a request line parsing is still incomplete */ if (r->header_in->pos == r->header_in->end) { rv = ngx_http_alloc_large_header_buffer(r, ); if (rv == NGX_ERROR) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
} if (rv == NGX_DECLINED) {
r->request_line.len = r->header_in->end - r->request_start;
r->request_line.data = r->request_start; ngx_log_error(NGX_LOG_INFO, c->log, ,
"client sent too long URI");
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
return;
}
}
}
}
Nginx-请求处理与响应的更多相关文章
- 【Nginx】发送响应
请求处理完毕后,需要向用户发送http响应,告知客户端Nginx的执行结果.http响应主要包括响应行.响应头部.包体三部分.发送http响应时需要执行发送http头部(发送http头部时也会发送响应 ...
- nodejs 通过nginx后出现响应慢的解决方法
最近用了nodejs搭建服务器,然后用了nginx做了反向代理,项目开发需求,没办法.但是发现了经过代理之后发现网页请求变慢了,而且是不能忍的一分钟以上. 一开始,怀疑是在nodejs那边的问题,结果 ...
- 修改nginx的http响应头server字段
信息泄露类型:HTTP服务器响应头Server字段信息泄露 示例: 解决: 需要重新对nginx编译安装: [root@localhost ~]# tar zxvf nginx-1.8.1.tar.g ...
- 【Nginx】修改响应头,根据不同请求IP重定向到不同IP
背景: 使用CAS登录的过程中会涉及到三次重定向,如果在同一个局域网内,是没有任何问题的,但如果涉及到跨网访问,这个问题就比较蛋疼了. 解决思路: 通过Nginx对要访问的系统进行代理,根据请求IP来 ...
- 高性能Web服务器Nginx的配置与部署研究(3)Nginx请求处理机制
1. 处理什么样的请求 处理访问到 Nginx 所在 IP 地址的请求,并且这些请求的 HTTP 头信息中的 Host 为所要处理的域名(如下以80端口为例),如下几个 server 就对应响应的请求 ...
- Nginx请求处理流程
因为 Nginx 运行在企业内网的最外层也就是边缘节点,那么他处理的的流量是其他应用服务器处理流量的数倍,甚至几个数量级,我们知道任何一种问题在不同的数量级下,他的解决方案是完全不同的,所以在 Ngi ...
- Nginx学习笔记(三):Nginx 请求处理
Request Nginx 中的 ngx_http_request_t 是对一个 http 请求的封装: 一个 http 请求包含:请求行.请求头.请求体,响应行.响应头.响应体 Nginx 处理请求 ...
- nginx 定义:响应头和请求头
1) 响应头 add_header 例如: add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; a ...
- Nginx配置各种响应头防止XSS,点击劫持,frame恶意攻击
为什么要配置HTTP响应头? 不知道各位有没有被各类XSS攻击.点击劫持 (ClickJacking. frame 恶意引用等等方式骚扰过,百度联盟被封就有这些攻击的功劳在里面.为此一直都在搜寻相关防 ...
- Nginx 如何处理上游响应的数据
陶辉93 一个非常重要的指令 proxy_buffer_size 指令限制头部响应header最大值 proxy_buffering 指令主要是指 上游服务器是否接受完完整包体在处理 默认是on 也就 ...
随机推荐
- 微软TTS语音引擎编程入门
原文链接地址:http://www.jizhuomi.com/software/135.html 我们都使用过一些某某词霸的英语学习工具软件,它们大多都有朗读的功能,其实这就是利用的Windows ...
- HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包)
HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包) 题意分析 裸的完全背包问题 代码总览 #include <iostream> #include <cstdio> ...
- 使用javaScript和JQuery制作经典面试题:光棒效果
使用javaScript与jQuery添加CSS样式的区别和步骤 使用javaScript制作光棒效果 --首先是javaScript <script> $(function () { v ...
- lamp 源码安装
#!/bin/bash #description:mysql-.tar apache2.4.23 php5.6.27 function check_ok(){ ] then echo "-- ...
- 再来说一说sudo
app ALL = (ALL:ALL) ALL eric.zhan ALL = (app : app) ALLDefaults:eric.zhan runas_default=app 如 ...
- 分别利用并查集,DFS和BFS方法求联通块的数量
联通块是指给定n个点,输入a,b(1<=a,b<=n),然后将a,b连接,凡是连接在一起的所有数就是一个联通块: 题意:第一行输入n,m,分别表示有n个数,有输入m对连接点,以下将要输入m ...
- How to configue session timeout in Hive
This article explains how to configure the following settings in Hive:hive.server2.session.check.int ...
- XMind 8 破解补丁 XMindCrack.jar注册机激活教程
XMind 8 破解补丁 XMindCrack.jar注册机激活教程 Xmind 8 update7破解版(附破解教程|激活补丁|序列号) 思维导图 XMind 8 Update 7 Pro 破解版 ...
- Itext2.0.8 和freemarker导出pdf
这个是跟上一篇写的freemarker导出word是一块的.但是关联性不是很大.由于本人技术有限本篇导出也是根据网上大家的做出的demo混合而成.有不足的地方请大家指出.好改正,使以后看到的freem ...
- 【转】Pyhton 单行、多行注释符号使用方法及规范
转自:Pyhton 单行.多行注释符号使用方法及规范 python中的注释有多种,有单行注释,多行注释,批量注释,中文注释也是常用的.python注释也有自己的规范,在文章中会介绍到.注释可以起到一个 ...