美度手表网站,wordpress经典编辑器没有,推广的软件,深圳58同城网站建设1.模块依赖2. 模块的初始化2.1 location的定义location的定义包含以下几种location [ | ~ | ~* | ^~ ] uri { ... }
location name { ... }:表示精确匹配#xff0c;只有请求的url路径与后面的字符串完全相等时#xff0c;才会命中#xff0c;不支持location嵌套~#xff…1.模块依赖2. 模块的初始化2.1 location的定义location的定义包含以下几种location [ | ~ | ~* | ^~ ] uri { ... }
location name { ... }:表示精确匹配只有请求的url路径与后面的字符串完全相等时才会命中不支持location嵌套~表示使用正则定义的区分大小写~*表示是使用正则定义的不区分大小写^~表示该符号后面的字符是最佳匹配采用该规则不再进行后续的查找name用于定义一个内部 Location 块该块不能被外部 Client 所访问只能被 NGINX 内部配置指令所访问比如 try_files 或者error_page。其修饰的location不能嵌套到其它location,也不能再嵌套其它location即只能是server这一层的2.2 分配ngx_http_conf_ctx_t2.2.1 ngx_http_block其是在解析配置文件中的http分配ctx ngx_pcalloc(cf-pool, sizeof(ngx_http_conf_ctx_t));
ctx-main_conf ngx_pcalloc(cf-pool,sizeof(void *) * ngx_http_max_module);
ctx-srv_conf ngx_pcalloc(cf-pool, sizeof(void *) * ngx_http_max_module);
ctx-loc_conf ngx_pcalloc(cf-pool, sizeof(void *) * ngx_http_max_module);2.2.2 ngx_http_core_location其是在解析配置文件中的http块内location时分配其中main_confsrv_conf是延用上一层级的loc_conf会再一次分配内存ctx ngx_pcalloc(cf-pool, sizeof(ngx_http_conf_ctx_t));
pctx cf-ctx;
ctx-main_conf pctx-main_conf;
ctx-srv_conf pctx-srv_conf;
ctx-loc_conf ngx_pcalloc(cf-pool, sizeof(void *) * ngx_http_max_module);同时也会遍历模块调用create_loc_conf创建location的配置for (i 0; cf-cycle-modules[i]; i) {if (cf-cycle-modules[i]-type ! NGX_HTTP_MODULE) {continue;}module cf-cycle-modules[i]-ctx;if (module-create_loc_conf) {ctx-loc_conf[cf-cycle-modules[i]-ctx_index] module-create_loc_conf(cf);if (ctx-loc_conf[cf-cycle-modules[i]-ctx_index] NULL) {return NGX_CONF_ERROR;}}}设置http_core_module配置的loc_conf来源clcf ctx-loc_conf[ngx_http_core_module.ctx_index];
clcf-loc_conf ctx-loc_conf;2.3 ngx_http_add_location构造ngx_http_location_queue_t将当前ngx_http_core_loc_conf_t添加到上一层级ngx_http_core_loc_conf_t中的location队列中。如果是精确匹配正则有名或者是无名构造的ngx_http_location_queue_t的exact来存放ngx_http_core_loc_conf_t配置否则使用ngx_http_location_queue_t的inclusive来存放ngx_http_core_loc_conf_t配置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;}将构造的队列添加到上一层级的队列中ngx_queue_insert_tail(*locations, lq-queue);2.4 主配置中的server在ngx_http_block中会分配main_confctx-main_conf ngx_pcalloc(cf-pool,sizeof(void *) * ngx_http_max_module);在处理server时ngx_http_core_server当前层的ctx中的main_conf会延用上一层的main_confhttp_ctx cf-ctx;
ctx-main_conf http_ctx-main_conf;将server放入cmcf-server中cscf ctx-srv_conf[ngx_http_core_module.ctx_index];
cscf-ctx ctx;cmcf ctx-main_conf[ngx_http_core_module.ctx_index];cscfp ngx_array_push(cmcf-servers);
if (cscfp NULL) {return NGX_CONF_ERROR;
}*cscfp cscf;2.5 初始化location(ngx_http_init_locations)处理ngx_http_core_srv_conf_t中的有名locationnamed_locations)以及ngx_http_core_loc_conf_t中的正则location(regex_locations),在作割裂之前会先对ngx_http_core_loc_conf_t中的locations排序使用的排序规则为ngx_http_cmp_locations即按照exact(sorted) - inclusive(sorted) - regex - named - noname的原则进行排序经过处理后原先的location队列就只剩下经过排序后的exact以及inclusive类型的location了。这两类location对应配置文件中的定义就是不含修饰符的location,带有和^~前缀的location。2.6 将queue转为list(ngx_http_create_locations_list)将locations queue变成locations list2.7 创建location的二叉查找树(ngx_http_create_locations_tree)创建精确匹配location的二叉查找树使用ngx_queue_middle(其时间度为O(n)得到location_list中的中间位置如果location_list的元素个数为奇数则是中间的一个否则是后半部分的第一个。ngx_queue_t *
ngx_queue_middle(ngx_queue_t *queue)
{ngx_queue_t *middle, *next;middle ngx_queue_head(queue);if (middle ngx_queue_last(queue)) {return middle;}next ngx_queue_head(queue);for ( ;; ) {middle ngx_queue_next(middle);next ngx_queue_next(next);if (next ngx_queue_last(queue)) {return middle;}next ngx_queue_next(next);if (next ngx_queue_last(queue)) {return middle;}}
}使用递归来构建二叉查找树/** 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;q ngx_queue_middle(locations);lq (ngx_http_location_queue_t *) q;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_short) 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_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_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_create_locations_tree(cf, lq-list, prefix len);if (node-tree NULL) {return NULL;}return node;
}
2.8 http的处理阶段包含11个阶段枚举名称NGX_HTTP_POST_READ_PHASE在接收到完整的HTTP头部后处理的HTTP阶段NGX_HTTP_SERVER_REWRITE_PHASE在将请求的URI与location表达式匹配前 修改请求的URI所谓的重定向 是一个独立的HTTP阶段NGX_HTTP_FIND_CONFIG_PHASE根据请求的URI寻找匹配的location表达式 这个阶段只能由ngx_http_core_module模块实现 不建议其他HTTP模块重新定义这一阶段的行为NGX_HTTP_REWRITE_PHASE在NGX_HTTP_FIND_CONFIG_PHASE阶段寻找到匹配的location之后再修改请求的URINGX_HTTP_POST_REWRITE_PHASE这一阶段是用于在rewrite重写URL后 防止错误的nginx.conf配置导致死循环递归地修改URI 因此 这一阶段仅由ngx_http_core_module模块处理。 目前 控制死循环的方式很简单 首先检查rewrite的次数 如果一个请求超过10次重定向,就认为进入了rewrite死循环 这时在NGX_HTTP_POST_REWRITE_PHASE阶段就会向用户返回500 表示服务器内部错误NGX_HTTP_PREACCESS_PHASE表示在处理NGX_HTTP_ACCESS_PHASE阶段决定请求的访问权限前HTTP模块可以介入的处理阶段NGX_HTTP_ACCESS_PHASE这个阶段用于让HTTP模块判断是否允许这个请求访问Nginx服务器NGX_HTTP_POST_ACCESS_PHASE在NGX_HTTP_ACCESS_PHASE阶段中 当HTTP模块的handler处理函数返回不允许访问的错误码时实际就是NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUTHORIZED 这里将负责向用户发送拒绝服务的错误响应。 因此 这个阶段实际上用于给NGX_HTTP_ACCESS_PHASE阶段收尾NGX_HTTP_PRECONTENT_PHASEhttp请求内容前置处理NGX_HTTP_CONTENT_PHASE用于处理HTTP请求内容的阶段 这是大部分HTTP模块最愿意介入的阶段NGX_HTTP_LOG_PHASE处理完请求后记录日志的阶段2.9 阶段处理器的初始化ngx_http_init_phases初始化以下阶段的handlersNGX_HTTP_POST_READ_PHASENGX_HTTP_SERVER_REWRITE_PHASENGX_HTTP_REWRITE_PHASENGX_HTTP_PREACCESS_PHASENGX_HTTP_ACCESS_PHASENGX_HTTP_PRECONTENT_PHASENGX_HTTP_CONTENT_PHASENGX_HTTP_LOG_PHASEstatic ngx_int_t
ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{if (ngx_array_init(cmcf-phases[NGX_HTTP_POST_READ_PHASE].handlers,cf-pool, 1, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,cf-pool, 1, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_REWRITE_PHASE].handlers,cf-pool, 1, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_PREACCESS_PHASE].handlers,cf-pool, 1, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_ACCESS_PHASE].handlers,cf-pool, 2, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_PRECONTENT_PHASE].handlers,cf-pool, 2, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_CONTENT_PHASE].handlers,cf-pool, 4, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}if (ngx_array_init(cmcf-phases[NGX_HTTP_LOG_PHASE].handlers,cf-pool, 1, sizeof(ngx_http_handler_pt))! NGX_OK){return NGX_ERROR;}return NGX_OK;
}2.10 配置后置处理postconfiguration遍历调用http模块的postconfiguration用来注册阶段的handlerfor (m 0; cf-cycle-modules[m]; m) {if (cf-cycle-modules[m]-type ! NGX_HTTP_MODULE) {continue;}module cf-cycle-modules[m]-ctx;if (module-postconfiguration) {if (module-postconfiguration(cf) ! NGX_OK) {return NGX_CONF_ERROR;}}}2.11 阶段引擎handler的初始化将各个不同阶段的handler汇聚成一个处理链表static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{ngx_int_t j;ngx_uint_t i, n;ngx_uint_t find_config_index, use_rewrite, use_access;ngx_http_handler_pt *h;ngx_http_phase_handler_t *ph;ngx_http_phase_handler_pt checker;cmcf-phase_engine.server_rewrite_index (ngx_uint_t) -1;cmcf-phase_engine.location_rewrite_index (ngx_uint_t) -1;find_config_index 0;use_rewrite cmcf-phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;use_access cmcf-phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;n 1 /* find config phase */ use_rewrite /* post rewrite phase */ use_access; /* post access phase */for (i 0; i NGX_HTTP_LOG_PHASE; i) {n cmcf-phases[i].handlers.nelts;}ph ngx_pcalloc(cf-pool,n * sizeof(ngx_http_phase_handler_t) sizeof(void *));if (ph NULL) {return NGX_ERROR;}cmcf-phase_engine.handlers ph;n 0;for (i 0; i NGX_HTTP_LOG_PHASE; i) {h cmcf-phases[i].handlers.elts;switch (i) {case NGX_HTTP_SERVER_REWRITE_PHASE:if (cmcf-phase_engine.server_rewrite_index (ngx_uint_t) -1) {cmcf-phase_engine.server_rewrite_index n;}checker ngx_http_core_rewrite_phase;break;case NGX_HTTP_FIND_CONFIG_PHASE:find_config_index n;ph-checker ngx_http_core_find_config_phase;n;ph;continue;case NGX_HTTP_REWRITE_PHASE:if (cmcf-phase_engine.location_rewrite_index (ngx_uint_t) -1) {cmcf-phase_engine.location_rewrite_index n;}checker ngx_http_core_rewrite_phase;break;case NGX_HTTP_POST_REWRITE_PHASE:if (use_rewrite) {ph-checker ngx_http_core_post_rewrite_phase;ph-next find_config_index;n;ph;}continue;case NGX_HTTP_ACCESS_PHASE:checker ngx_http_core_access_phase;n;break;case NGX_HTTP_POST_ACCESS_PHASE:if (use_access) {ph-checker ngx_http_core_post_access_phase;ph-next n;ph;}continue;case NGX_HTTP_CONTENT_PHASE:checker ngx_http_core_content_phase;break;default:checker ngx_http_core_generic_phase;}n cmcf-phases[i].handlers.nelts;for (j cmcf-phases[i].handlers.nelts - 1; j 0; j--) {ph-checker checker;ph-handler h[j];ph-next n;ph;}}return NGX_OK;
}
2.12 初始监听端口 服务以及监听回调ngx_http_optimize_servers中的ngx_http_add_listening会设置端口的回调ls-handler ngx_http_init_connection;3. 运行时的处理3.1 accept事件处理在处理accept连接事件时会调用ngx_listening_t的回调handler函数ngx_http_init_connection对于新分配的连接如果读事件的ready为1即iocp或者延时的accept事件在有使用accept锁情况 下将事件放入posted_events队列中否则直接调用事件的回调handlerif (rev-ready) {/* the deferred accept(), iocp */if (ngx_use_accept_mutex) {ngx_post_event(rev, ngx_posted_events);return;}rev-handler(rev);return;
}如果读事件的ready不为1则将事件加入定时器的红黑树中。定时器超时后就会调用它的 handler ngx_http_wait_request_handler 函数。ngx_add_timer(rev, cscf-client_header_timeout);将连接设置为可重用因为该连接上还没有请求到来所以当连接池中的连接不够用时就可以重用这个连接。将当前connection添加可重用的连接队列中同时可重用连接数加1ngx_reusable_connection(c, 1);void
ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
{ngx_log_debug1(NGX_LOG_DEBUG_CORE, c-log, 0,reusable connection: %ui, reusable);if (c-reusable) {ngx_queue_remove(c-queue);ngx_cycle-reusable_connections_n--;#if (NGX_STAT_STUB)(void) ngx_atomic_fetch_add(ngx_stat_waiting, -1);
#endif}c-reusable reusable;if (reusable) {/* need cast as ngx_cycle is volatile */ngx_queue_insert_head((ngx_queue_t *) ngx_cycle-reusable_connections_queue, c-queue);ngx_cycle-reusable_connections_n;#if (NGX_STAT_STUB)(void) ngx_atomic_fetch_add(ngx_stat_waiting, 1);
#endif}
}
ngx_handle_read_event将分配连接的事件添加到事件驱动模块中ngx_int_t
ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags)
{if (ngx_event_flags NGX_USE_CLEAR_EVENT) {/* kqueue, epoll */if (!rev-active !rev-ready) {if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) NGX_ERROR){return NGX_ERROR;}}return NGX_OK;} else if (ngx_event_flags NGX_USE_LEVEL_EVENT) {/* select, poll, /dev/poll */if (!rev-active !rev-ready) {if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) NGX_ERROR){return NGX_ERROR;}return NGX_OK;}if (rev-active (rev-ready || (flags NGX_CLOSE_EVENT))) {if (ngx_del_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT | flags) NGX_ERROR){return NGX_ERROR;}return NGX_OK;}} else if (ngx_event_flags NGX_USE_EVENTPORT_EVENT) {/* event ports */if (!rev-active !rev-ready) {if (ngx_add_event(rev, NGX_READ_EVENT, 0) NGX_ERROR) {return NGX_ERROR;}return NGX_OK;}if (rev-oneshot rev-ready) {if (ngx_del_event(rev, NGX_READ_EVENT, 0) NGX_ERROR) {return NGX_ERROR;}return NGX_OK;}}/* iocp */return NGX_OK;
}3.2 首次可读事件处理是通过ngx_http_wait_request_handler来处理首先从网络上读取数据到连接中的bufferngx_connection_t *c;
ngx_buf_t *b;
c rev-data;
b c-buffer;
if (b NULL) {b ngx_create_temp_buf(c-pool, size);if (b NULL) {ngx_http_close_connection(c);return;}c-buffer b;} else if (b-start NULL) {b-start ngx_palloc(c-pool, size);if (b-start NULL) {ngx_http_close_connection(c);return;}b-pos b-start;b-last b-start;b-end b-last size;
}
n c-recv(c, b-last, size);
b-last n;在可重用连接中删除当前连接 ngx_reusable_connection(c, 0);创建http_request,在创建请求中会将上面读取的缓冲区放在ngx_http_request_t中的header_in用于处理请求头c-data ngx_http_create_request(c);处理请求头同时将当前连接读事件的回调函数设置为ngx_http_process_request_line用于处理单次接收的数据不完整rev-handler ngx_http_process_request_line;
ngx_http_process_request_line(rev);3.3 请求行的处理是通过ngx_http_process_request_line来处理的先解析请求行rc ngx_http_parse_request_line(r, r-header_in);