HTTP 请求处理的 11 个阶段 -- ngx_http_handler

2015-10-14 16:19:23   最后更新: 2015-10-16 17:45:27   访问数量:909




对于 HTTP/0.9,请求不具有 header,因此在处理完请求行后紧接着进行的就是请求内容的处理

而对于 HTTP/1.0 和 HTTP/1.1,在调用 ngx_http_read_request_header 解析 HEADER、ngx_http_process_request_header 校验 HEADER 后,紧接着就会调用 ngx_http_process_request 进行请求的处理

// void ngx_http_process_request(ngx_http_request_t *r) // http 请求处理 {{{ void ngx_http_process_request(ngx_http_request_t *r) { ngx_connection_t *c; c = r->connection; #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { long rc; X509 *cert; ngx_http_ssl_srv_conf_t *sscf; if (c->ssl == NULL) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent plain HTTP request to HTTPS port"); ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); return; } sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client SSL certificate verify error: (%l:%s)", rc, X509_verify_cert_error_string(rc)); ngx_ssl_remove_cached_session(sscf->ssl.ctx, (SSL_get0_session(c->ssl->connection))); ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); return; } if (sscf->verify == 1) { cert = SSL_get_peer_certificate(c->ssl->connection); if (cert == NULL) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent no required SSL certificate"); ngx_ssl_remove_cached_session(sscf->ssl.ctx, (SSL_get0_session(c->ssl->connection))); ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); return; } X509_free(cert); } } } #endif // 如果设置了定时器则删除定时器 if (c->read->timer_set) { ngx_del_timer(c->read); } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); r->stat_reading = 0; (void) ngx_atomic_fetch_add(ngx_stat_writing, 1); r->stat_writing = 1; #endif c->read->handler = ngx_http_request_handler; c->write->handler = ngx_http_request_handler; r->read_event_handler = ngx_http_block_reading; // http 请求处理回调调用函数 ngx_http_handler(r); ngx_http_run_posted_requests(c); } // }}}

 

 

主要做了以下工作:

  1. 如果设置了定时器则删除,既然所有的请求已经接收完毕,就不会再发生超时了
  2. 重设连接的读写回调函数
  3. 重设请求读事件回调函数
  4. 调用 ngx_http_handler 处理 HTTP 请求的 11 个阶段
  5. 调用 ngx_http_run_posted_requests 处理 posted_requests 队列中的 POST 请求

 

 

 

在函数中,重新设置了读事件回调,那么请求的写事件回调是在哪里重设的呢?

是在 ngx_http_handler 函数中重设的

// void ngx_http_handler(ngx_http_request_t *r) // 调用 ngx_http_core_run_phases 完成 11 个 HTTP 处理阶段的处理 {{{ void ngx_http_handler(ngx_http_request_t *r) { ngx_http_core_main_conf_t *cmcf; r->connection->log->action = NULL; r->connection->unexpected_eof = 0; // 设置初始执行的 HTTP 处理阶段 if (!r->internal) { switch (r->headers_in.connection_type) { case 0: r->keepalive = (r->http_version > NGX_HTTP_VERSION_10); break; case NGX_HTTP_CONNECTION_CLOSE: r->keepalive = 0; break; case NGX_HTTP_CONNECTION_KEEP_ALIVE: r->keepalive = 1; break; } r->lingering_close = (r->headers_in.content_length_n > 0 || r->headers_in.chunked); r->phase_handler = 0; } else { cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); r->phase_handler = cmcf->phase_engine.server_rewrite_index; } r->valid_location = 1; #if (NGX_HTTP_GZIP) r->gzip_tested = 0; r->gzip_ok = 0; r->gzip_vary = 0; #endif // 设置请求写事件回调函数 r->write_event_handler = ngx_http_core_run_phases; // 11 个 HTTP 处理阶段 ngx_http_core_run_phases(r); } // }}}

 

 

然后这个函数通过请求的 internal 字段判断是否从 0 号回调开始执行

最后,就要进入请求的 11 个阶段的处理了 -- ngx_http_core_run_phases

 

HTTP 请求的 11 个处理阶段

在上面这篇博客中,我们介绍了 nginx HTTP 请求处理的 11 个阶段

并在 ngx_http_init_phase_handlers 函数中为 phase_engine 赋值了所有的 checker 和 handler

 

在 ngx_http_handler 函数中,就顺次调用了这些 checker 和 handler 完成了整个 HTTP 请求的处理

// void ngx_http_core_run_phases(ngx_http_request_t *r) // 11 个 HTTP 处理阶段 {{{ void ngx_http_core_run_phases(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_phase_handler_t *ph; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; while (ph[r->phase_handler].checker) { // 所有的处理阶段回调函数构成了一个链表 // NGX_HTTP_SERVER_REWRITE_PHASE ngx_http_core_rewrite_phase // NGX_HTTP_FIND_CONFIG_PHASE ngx_http_core_find_config_phase // NGX_HTTP_REWRITE_PHASE ngx_http_core_rewrite_phase // NGX_HTTP_POST_REWRITE_PHASE ngx_http_core_post_rewrite_phase // NGX_HTTP_PREACCESS_PHASE ngx_http_core_generic_phase // NGX_HTTP_POST_READ_PHASE ngx_http_limit_conn_handler // NGX_HTTP_ACCESS_PHASE ngx_http_core_access_phase // NGX_HTTP_POST_ACCESS_PHASE ngx_http_core_post_access_phase // NGX_HTTP_CONTENT_PHASE ngx_http_core_content_phase // NGX_HTTP_TRY_FILES_PHASE ngx_http_core_try_files_phase rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); // 全部回调完成 if (rc == NGX_OK) { return; } } } // }}}

 

 

注释中标注了每个阶段的 checker,他们都是在 ngx_http_init_phase_handlers 中初始化的

 

nginx 11 个 HTTP 处理阶段及其对应的 checker 回调函数
阶段checker
NGX_HTTP_SERVER_REWRITE_PHASEngx_http_core_rewrite_phase
NGX_HTTP_FIND_CONFIG_PHASEngx_http_core_find_config_phase
NGX_HTTP_REWRITE_PHASEngx_http_core_rewrite_phase
NGX_HTTP_POST_REWRITE_PHASEngx_http_core_post_rewrite_phase
NGX_HTTP_PREACCESS_PHASEngx_http_core_generic_phase
NGX_HTTP_POST_READ_PHASEngx_http_core_generic_phase
NGX_HTTP_ACCESS_PHASEngx_http_core_access_phase
NGX_HTTP_POST_ACCESS_PHASEngx_http_core_post_access_phase
NGX_HTTP_CONTENT_PHASEngx_http_core_content_phase
NGX_HTTP_TRY_FILES_PHASEngx_http_core_try_files_phase
NGX_HTTP_LOG_PHASEngx_http_core_generic_phase

 

每个阶段都是通过 checker 回调作为入口的,如果该阶段需要执行 handler 回调函数,则在 checker 中会去调用相应的 handler 函数

如果 checker 返回 NGX_OK 则表示已经完成全部回调的执行,否则继续执行,执行回调的序号是在各个 checker 中自增的

 

NGX_HTTP_REWRITE_PHASE、NGX_HTTP_SERVER_REWRITE_PHASE:重定向URI -- ngx_http_core_rewrite_phase

这个函数只是简单的调用 handler 完成重定向 URI 的处理

 

// ngx_int_t // ngx_http_core_rewrite_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_SERVER_REWRITE_PHASE、NGX_HTTP_REWRITE_PHASE 阶段 checker 函数 // 用于 rewrite uri {{{ ngx_int_t ngx_http_core_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_int_t rc; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "rewrite phase: %ui", r->phase_handler); // ngx_http_rewrite_handler rc = ph->handler(r); if (rc == NGX_DECLINED) { r->phase_handler++; return NGX_AGAIN; } if (rc == NGX_DONE) { return NGX_OK; } /* NGX_OK, NGX_AGAIN, NGX_ERROR, NGX_HTTP_... */ ngx_http_finalize_request(r, rc); return NGX_OK; } // }}}

 

 

NGX_HTTP_FIND_CONFIG_PHASE:根据请求 URI 匹配 location 表达式 -- ngx_http_core_find_config_phase

这个阶段是不允许用户定义 handler 的,因为在 checker 中并不会去执行 handler

这个阶段的主要工作是根据 URI 匹配 location,并处理 location 中设置重定向的情况

 

// ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_FIND_CONFIG_PHASE 阶段 checker,根据请求 URI 匹配 location 表达式 {{{ ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { u_char *p; size_t len; ngx_int_t rc; ngx_http_core_loc_conf_t *clcf; r->content_handler = NULL; r->uri_changed = 0; // 根据 URI 查找 location rc = ngx_http_core_find_location(r); if (rc == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); // 非内部请求访问内部 location 是非法的 if (!r->internal && clcf->internal) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); return NGX_OK; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "using configuration \"%s%V\"", (clcf->noname ? "*" : (clcf->exact_match ? "=" : "")), &clcf->name); // 根据匹配的 location 设置 request 的属性 ngx_http_update_location_config(r); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http cl:%O max:%O", r->headers_in.content_length_n, clcf->client_max_body_size); // 请求内容大小是否超过限制 if (r->headers_in.content_length_n != -1 && !r->discard_body && clcf->client_max_body_size && clcf->client_max_body_size < r->headers_in.content_length_n) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client intended to send too large body: %O bytes", r->headers_in.content_length_n); r->expect_tested = 1; (void) ngx_http_discard_request_body(r); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; } // 处理重定向 if (rc == NGX_DONE) { ngx_http_clear_location(r); r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ if (r->args.len == 0) { r->headers_out.location->value = clcf->name; } else { len = clcf->name.len + 1 + r->args.len; p = ngx_pnalloc(r->pool, len); if (p == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } r->headers_out.location->value.len = len; r->headers_out.location->value.data = p; p = ngx_cpymem(p, clcf->name.data, clcf->name.len); *p++ = '?'; ngx_memcpy(p, r->args.data, r->args.len); } ngx_http_finalize_request(r, NGX_HTTP_MOVED_PERMANENTLY); return NGX_OK; } r->phase_handler++; return NGX_AGAIN; } // }}}

 

 

NGX_HTTP_POST_REWRITE_PHASE:检测 URI 的重定向 -- ngx_http_core_post_rewrite_phase

这个阶段也同样不会执行 handler,主要工作是限制 URI 的重定向次数,不允许超过十次,防止陷入死循环

 

// ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_POST_REWRITE_PHASE 阶段 checker,防止递归修改 URI 造成死循环 {{{ ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_http_core_srv_conf_t *cscf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "post rewrite phase: %ui", r->phase_handler); // 不需要重写 URI,直接返回 if (!r->uri_changed) { r->phase_handler++; return NGX_AGAIN; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uri changes: %d", r->uri_changes); /* * gcc before 3.3 compiles the broken code for * if (r->uri_changes-- == 0) * if the r->uri_changes is defined as * unsigned uri_changes:4 */ // uri_changes 保存重写次数,初始值为 11,为 0 说明被重写了 10 次以上,禁止 r->uri_changes--; if (r->uri_changes == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "rewrite or internal redirection cycle " "while processing \"%V\"", &r->uri); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } r->phase_handler = ph->next; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); r->loc_conf = cscf->ctx->loc_conf; return NGX_AGAIN; } // }}}

 

 

NGX_HTTP_POST_READ_PHASE、NGX_HTTP_PREACCESS_PHASE:读取请求、粗粒度的访问检测 -- ngx_http_core_generic_phase

这两个阶段的主要工作是对连接和请求做一些基本的限制

checker 非常简单,仅仅是对 handler 的执行

 

// ngx_int_t // ngx_http_core_generic_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_POST_READ_PHASE、NGX_HTTP_PREACCESS_PHASE 阶段 checker // 仅仅调用 handler {{{ ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_int_t rc; /* * generic phase checker, * used by the post read and pre-access phases */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "generic phase: %ui", r->phase_handler); // NGX_HTTP_PREACCESS_PHASE ngx_http_limit_req_handler // NGX_HTTP_POST_READ_PHASE ngx_http_limit_conn_handler rc = ph->handler(r); if (rc == NGX_OK) { r->phase_handler = ph->next; return NGX_AGAIN; } if (rc == NGX_DECLINED) { r->phase_handler++; return NGX_AGAIN; } if (rc == NGX_AGAIN || rc == NGX_DONE) { return NGX_OK; } /* rc == NGX_ERROR || rc == NGX_HTTP_... */ ngx_http_finalize_request(r, rc); return NGX_OK; } // }}}

 

 

NGX_HTTP_ACCESS_PHASE:判断用户是否有权限访问 -- ngx_http_core_access_phase

这个阶段的主要工作是细粒度的访问权限验证

checker 通过调用 handler 完成了对用户名密码等的验证

 

// ngx_int_t // ngx_http_core_access_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_POST_ACCESS_PHASE 阶段 checker,判断用户是否有权限访问 {{{ ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_int_t rc; ngx_http_core_loc_conf_t *clcf; if (r != r->main) { r->phase_handler = ph->next; return NGX_AGAIN; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "access phase: %ui", r->phase_handler); // ngx_http_access_handler,访问权限判断 // ngx_http_auth_basic_handler, ngx_http_auth_basic_module 提供密码验证 rc = ph->handler(r); if (rc == NGX_DECLINED) { r->phase_handler++; return NGX_AGAIN; } if (rc == NGX_AGAIN || rc == NGX_DONE) { return NGX_OK; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { if (rc == NGX_OK) { r->phase_handler++; return NGX_AGAIN; } } else { if (rc == NGX_OK) { r->access_code = 0; if (r->headers_out.www_authenticate) { r->headers_out.www_authenticate->hash = 0; } r->phase_handler = ph->next; return NGX_AGAIN; } if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) { if (r->access_code != NGX_HTTP_UNAUTHORIZED) { r->access_code = rc; } r->phase_handler++; return NGX_AGAIN; } } /* rc == NGX_ERROR || rc == NGX_HTTP_... */ ngx_http_finalize_request(r, rc); return NGX_OK; } // }}}

 

 

NGX_HTTP_POST_ACCESS_PHASE:将拒绝访问信息返回给用户 -- ngx_http_core_post_access_phase

如果前几个阶段的验证失败,则相应请求将无法访问,这个阶段就会将拒绝访问的信息返回给用户

这个阶段也不会调用任何 handler

 

// ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_POST_ACCESS_PHASE 阶段 checker // 根据 NGX_HTTP_ACCESS_PHASE 阶段的返回将对应的错误信息返回给用户 {{{ ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { ngx_int_t access_code; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "post access phase: %ui", r->phase_handler); access_code = r->access_code; if (access_code) { if (access_code == NGX_HTTP_FORBIDDEN) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "access forbidden by rule"); } r->access_code = 0; ngx_http_finalize_request(r, access_code); return NGX_OK; } r->phase_handler++; return NGX_AGAIN; } // }}}

 

 

NGX_HTTP_CONTENT_PHASE:生成 HTTP 响应 -- ngx_http_core_content_phase

这个阶段是 HTTP 请求处理的关键性的一个阶段,他会生成 HTTP 响应

我们编写的模块大部分是在这个 phase 执行的

 

// ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_CONTENT_PHASE 阶段 checker,生成 HTTP 响应 {{{ ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { size_t root; ngx_int_t rc; ngx_str_t path; // 在 NGX_HTTP_FIND_CONFIG_PHASE 阶段 // 如果发现 location 有对应的 handler 需要执行 // 则会赋值给 content_handler,在此执行 // 从而就不会去执行其他的 handler 了 if (r->content_handler) { r->write_event_handler = ngx_http_request_empty_handler; ngx_http_finalize_request(r, r->content_handler(r)); return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "content phase: %ui", r->phase_handler); // 执行各个模块的 handler // ngx_http_index_module ngx_http_index_handler rc = ph->handler(r); if (rc != NGX_DECLINED) { ngx_http_finalize_request(r, rc); return NGX_OK; } /* rc == NGX_DECLINED */ ph++; if (ph->checker) { r->phase_handler++; return NGX_AGAIN; } /* no content handler was found */ if (r->uri.data[r->uri.len - 1] == '/') { if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "directory index of \"%s\" is forbidden", path.data); } ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN); return NGX_OK; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found"); ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); return NGX_OK; } // }}}

 

 

在这个阶段的 checker 中,首先判断请求的 content_handler 是否已经被赋值

如果在 NGX_HTTP_FIND_CONFIG_PHASE 阶段发现 location 有对应的 handler 需要执行,就会将这个 handler 赋值给 content_handler,那么在这个阶段就不会再执行其他 handler,而是在执行 content_handler 回调后直接完成这一阶段的处理

否则就会调用所有的 handler 完成处理了

 

NGX_HTTP_TRY_FILES_PHASE:试从多个静态文件中找出需要访问的静态文件 -- ngx_http_core_try_files_phase

 

// ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r, // ngx_http_phase_handler_t *ph) // NGX_HTTP_TRY_FILES_PHASE 阶段 checker // 尝试从多个静态文件中找出需要访问的静态文件 {{{ ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) { size_t len, root, alias, reserve, allocated; u_char *p, *name; ngx_str_t path, args; ngx_uint_t test_dir; ngx_http_try_file_t *tf; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_script_len_code_pt lcode; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "try files phase: %ui", r->phase_handler); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->try_files == NULL) { r->phase_handler++; return NGX_AGAIN; } allocated = 0; root = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; tf = clcf->try_files; alias = clcf->alias; for ( ;; ) { if (tf->lengths) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = tf->lengths->elts; e.request = r; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } } else { len = tf->name.len; } if (!alias) { reserve = len > r->uri.len ? len - r->uri.len : 0; } else if (alias == NGX_MAX_SIZE_T_VALUE) { reserve = len; } else { reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; } if (reserve > allocated || !allocated) { /* 16 bytes are preallocation */ allocated = reserve + 16; if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } name = path.data + root; } if (tf->values == NULL) { /* tf->name.len includes the terminating '\0' */ ngx_memcpy(name, tf->name.data, tf->name.len); path.len = (name + tf->name.len - 1) - path.data; } else { e.ip = tf->values->elts; e.pos = name; e.flushed = 1; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } path.len = e.pos - path.data; *e.pos = '\0'; if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; } } test_dir = tf->test_dir; tf++; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "trying to use %s: \"%s\" \"%s\"", test_dir ? "dir" : "file", name, path.data); if (tf->lengths == NULL && tf->name.len == 0) { if (tf->code) { ngx_http_finalize_request(r, tf->code); return NGX_OK; } path.len -= root; path.data += root; if (path.data[0] == '@') { (void) ngx_http_named_location(r, &path); } else { ngx_http_split_args(r, &path, &args); (void) ngx_http_internal_redirect(r, &path, &args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_OK; } ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR && of.err != NGX_ENAMETOOLONG) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); } continue; } if (of.is_dir && !test_dir) { continue; } path.len -= root; path.data += root; if (!alias) { r->uri = path; } else if (alias == NGX_MAX_SIZE_T_VALUE) { if (!test_dir) { r->uri = path; r->add_uri_to_alias = 1; } } else { r->uri.len = alias + path.len; r->uri.data = ngx_pnalloc(r->pool, r->uri.len); if (r->uri.data == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } p = ngx_copy(r->uri.data, clcf->name.data, alias); ngx_memcpy(p, name, path.len); } ngx_http_set_exten(r); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "try file uri: \"%V\"", &r->uri); r->phase_handler++; return NGX_AGAIN; } /* not reached */ } // }}}

 

 






读书笔记      龙潭书斋      源代码      nginx      源码      sourcecode      http      回调函数      source      ngx_http_handler      checker      handler     


京ICP备15018585号