Open vislee opened 7 years ago
该模块通过发起子请求来验证http请求。
location /test1 { auth_request /auth1; hello_world; hello_by "hello liwq"; } location /test2 { auth_request /auth2; } location /auth1 { return 200 "ok"; } location /auth2 { return 401 "null"; }
curl 'http://127.0.0.1:8080/test1' hello world hello liwq curl -I 'http://127.0.0.1:8080/test2' HTTP/1.1 401 Unauthorized
该模块通过一个ngx_http_auth_request_conf_t结构体保存解析的配置。
typedef struct { ngx_str_t uri; // auth_request指令解析的值 ngx_array_t *vars; // auth_request_set指令解析的值。类型为:ngx_http_auth_request_variable_t } ngx_http_auth_request_conf_t; typedef struct { ngx_int_t index; // 变量的下标 ngx_http_complex_value_t value; // 编译后的结果 ngx_http_set_variable_pt set_handler; } ngx_http_auth_request_variable_t;
解析完请求行请求头后调用ngx_http_auth_request_handler回调。
请求上下文不为空则(再次调用): a. 如果子请求没结束,继续返回ngx_again. b. 调用ngx_http_auth_request_set_variables c. 判断子请求返回的状态,并作为该模块的返回。
请求上下文为空,则创建一个上下文ngx_http_auth_request_ctx_t。
调用ngx_http_subrequest添加一个验证的子请求,子请求结束后的回调信息为ngx_http_post_subrequest_t结构,回调函数为ngx_http_auth_request_done,参数为上下文结构体。
返回ngx_again.
handler返回,执行权交到ngx_http_core_access_phase函数,该函数返回ngx_ok,调用check的函数ngx_http_core_run_phases结束,返回到ngx_http_process_request函数中,ngx_http_process_request函数继续向下执行调用ngx_http_run_posted_requests处理子请求。
ngx_http_run_posted_request从原始请求派生出的子请求中执行子请求的回调函数,一般为ngx_http_handler函数,因子请求是内部请求,所以从server_rewrite阶段开始执行http的9个阶段。 当子请求结束会调用ngx_http_finalize_request。
ngx_http_finalize_request函数,如果是子请求,会执行post_subrequest回调,该回调是ngx_http_auth_request_done。
ngx_http_auth_request_done函数把子请求返回的状态赋给原始请求的上下文中。
当所有子请求处理完毕后,返回到ngx事件框架。可写事件回调ngx_http_request_handler函数,该函数继续执行ngx_http_core_run_phases函数,接着执行http的10个阶段, 因为auth_request模块返回的是ngx_again,r->phase_handler没有变化。所以继续执行 ngx_http_auth_request_handler回调,从上下文不为空开始。
ngx_http_finalize_request 函数:
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_connection_t *c; ngx_http_request_t *pr; ngx_http_core_loc_conf_t *clcf; c = r->connection; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, "http finalize request: %i, \"%V?%V\" a:%d, c:%d", rc, &r->uri, &r->args, r == c->data, r->main->count); if (rc == NGX_DONE) { ngx_http_finalize_connection(r); return; } if (rc == NGX_OK && r->filter_finalize) { c->error = 1; } if (rc == NGX_DECLINED) { r->content_handler = NULL; r->write_event_handler = ngx_http_core_run_phases; ngx_http_core_run_phases(r); return; } // 子请求 且 子请求有结束时的回调 if (r != r->main && r->post_subrequest) { rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc); } if (rc == NGX_ERROR || rc == NGX_HTTP_REQUEST_TIME_OUT || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST || c->error) { if (ngx_http_post_action(r) == NGX_OK) { return; } ngx_http_terminate_request(r, rc); return; } if (rc >= NGX_HTTP_SPECIAL_RESPONSE || rc == NGX_HTTP_CREATED || rc == NGX_HTTP_NO_CONTENT) { if (rc == NGX_HTTP_CLOSE) { ngx_http_terminate_request(r, rc); return; } if (r == r->main) { if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } } c->read->handler = ngx_http_request_handler; c->write->handler = ngx_http_request_handler; ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc)); return; } if (r != r->main) { // 子请求 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); // 后台子请求(分离子请求) if (r->background) { if (!r->logged) { if (clcf->log_subrequest) { ngx_http_log_request(r); } r->logged = 1; } else { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "subrequest: \"%V?%V\" logged again", &r->uri, &r->args); } r->done = 1; ngx_http_finalize_connection(r); return; } if (r->buffered || r->postponed) { if (ngx_http_set_write_handler(r) != NGX_OK) { ngx_http_terminate_request(r, 0); } return; } pr = r->parent; if (r == c->data) { // 添加子请求函数ngx_http_subrequest中,如果不是后台子请求则会把子请求覆盖到c->data. // r->main->count--; if (!r->logged) { if (clcf->log_subrequest) { ngx_http_log_request(r); } r->logged = 1; } else { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "subrequest: \"%V?%V\" logged again", &r->uri, &r->args); } r->done = 1; if (pr->postponed && pr->postponed->request == r) { pr->postponed = pr->postponed->next; } c->data = pr; } else { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http finalize non-active request: \"%V?%V\"", &r->uri, &r->args); r->write_event_handler = ngx_http_request_finalizer; if (r->waited) { r->done = 1; } } // pr 为父请求 // 把父请求添加到主请求的自请求队列中,以便父请求可以被调用执行 if (ngx_http_post_request(pr, NULL) != NGX_OK) { r->main->count++; ngx_http_terminate_request(r, 0); return; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http wake parent request: \"%V?%V\"", &pr->uri, &pr->args); return; } if (r->buffered || c->buffered || r->postponed) { if (ngx_http_set_write_handler(r) != NGX_OK) { ngx_http_terminate_request(r, 0); } return; } if (r != c->data) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http finalize non-active request: \"%V?%V\"", &r->uri, &r->args); return; } r->done = 1; r->read_event_handler = ngx_http_block_reading; r->write_event_handler = ngx_http_request_empty_handler; if (!r->post_action) { r->request_complete = 1; } if (ngx_http_post_action(r) == NGX_OK) { return; } if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { c->write->delayed = 0; ngx_del_timer(c->write); } if (c->read->eof) { ngx_http_close_request(r, 0); return; } ngx_http_finalize_connection(r); }
auth_request模块的函数
// 注册到NGX_HTTP_ACCESS_PHASE阶段的回调函数 static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r) { ngx_table_elt_t *h, *ho; ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_auth_request_ctx_t *ctx; ngx_http_auth_request_conf_t *arcf; arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module); // 没配置验证的子请求uri,则执行下一阶段 if (arcf->uri.len == 0) { return NGX_DECLINED; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth request handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module); if (ctx != NULL) { if (!ctx->done) { return NGX_AGAIN; } /* * as soon as we are done - explicitly set variables to make * sure they will be available after internal redirects */ if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) { return NGX_ERROR; } /* return appropriate status */ if (ctx->status == NGX_HTTP_FORBIDDEN) { return ctx->status; } if (ctx->status == NGX_HTTP_UNAUTHORIZED) { sr = ctx->subrequest; h = sr->headers_out.www_authenticate; if (!h && sr->upstream) { h = sr->upstream->headers_in.www_authenticate; } if (h) { ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { return NGX_ERROR; } *ho = *h; r->headers_out.www_authenticate = ho; } return ctx->status; } if (ctx->status >= NGX_HTTP_OK && ctx->status < NGX_HTTP_SPECIAL_RESPONSE) { return NGX_OK; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "auth request unexpected status: %ui", ctx->status); return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ps == NULL) { return NGX_ERROR; } ps->handler = ngx_http_auth_request_done; ps->data = ctx; // 添加子请求 if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED) != NGX_OK) { return NGX_ERROR; } /* * allocate fake request body to avoid attempts to read it and to make * sure real body file (if already read) won't be closed by upstream */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } sr->header_only = 1; ctx->subrequest = sr; ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module); return NGX_AGAIN; } // 子请求结束的回调函数 static ngx_int_t ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc) { ngx_http_auth_request_ctx_t *ctx = data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth request done s:%ui", r->headers_out.status); ctx->done = 1; ctx->status = r->headers_out.status; return rc; } // static ngx_int_t ngx_http_auth_request_set_variables(ngx_http_request_t *r, ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx) { ngx_str_t val; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_auth_request_variable_t *av, *last; ngx_http_core_main_conf_t *cmcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth request set variables"); if (arcf->vars == NULL) { return NGX_OK; } cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = cmcf->variables.elts; av = arcf->vars->elts; last = av + arcf->vars->nelts; while (av < last) { /* * explicitly set new value to make sure it will be available after * internal redirects */ vv = &r->variables[av->index]; if (ngx_http_complex_value(ctx->subrequest, &av->value, &val) != NGX_OK) { return NGX_ERROR; } vv->valid = 1; vv->not_found = 0; vv->data = val.data; vv->len = val.len; if (av->set_handler) { /* * set_handler only available in cmcf->variables_keys, so we store * it explicitly */ av->set_handler(r, vv, v[av->index].data); } av++; } return NGX_OK; }
执行子请求,被ngx_http_request_handler函数调用。
void ngx_http_run_posted_requests(ngx_connection_t *c) { ngx_http_request_t *r; ngx_http_posted_request_t *pr; for ( ;; ) { if (c->destroyed) { return; } r = c->data; // 原始请求派生出的所有子请求,是一个单链表。 pr = r->main->posted_requests; if (pr == NULL) { return; } // 从单表表头取出一个元素 r->main->posted_requests = pr->next; // 子请求单链表表头元素 r = pr->request; ngx_http_set_log_request(c->log, r); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http posted request: \"%V?%V\"", &r->uri, &r->args); // write_event_handler指向ngx_http_handler 函数,添加子请求的时候设置的。 r->write_event_handler(r); } }
概述
该模块通过发起子请求来验证http请求。
代码
该模块通过一个ngx_http_auth_request_conf_t结构体保存解析的配置。
解析完请求行请求头后调用ngx_http_auth_request_handler回调。
请求上下文不为空则(再次调用): a. 如果子请求没结束,继续返回ngx_again. b. 调用ngx_http_auth_request_set_variables c. 判断子请求返回的状态,并作为该模块的返回。
请求上下文为空,则创建一个上下文ngx_http_auth_request_ctx_t。
调用ngx_http_subrequest添加一个验证的子请求,子请求结束后的回调信息为ngx_http_post_subrequest_t结构,回调函数为ngx_http_auth_request_done,参数为上下文结构体。
返回ngx_again.
handler返回,执行权交到ngx_http_core_access_phase函数,该函数返回ngx_ok,调用check的函数ngx_http_core_run_phases结束,返回到ngx_http_process_request函数中,ngx_http_process_request函数继续向下执行调用ngx_http_run_posted_requests处理子请求。
ngx_http_run_posted_request从原始请求派生出的子请求中执行子请求的回调函数,一般为ngx_http_handler函数,因子请求是内部请求,所以从server_rewrite阶段开始执行http的9个阶段。 当子请求结束会调用ngx_http_finalize_request。
ngx_http_finalize_request函数,如果是子请求,会执行post_subrequest回调,该回调是ngx_http_auth_request_done。
ngx_http_auth_request_done函数把子请求返回的状态赋给原始请求的上下文中。
当所有子请求处理完毕后,返回到ngx事件框架。可写事件回调ngx_http_request_handler函数,该函数继续执行ngx_http_core_run_phases函数,接着执行http的10个阶段, 因为auth_request模块返回的是ngx_again,r->phase_handler没有变化。所以继续执行 ngx_http_auth_request_handler回调,从上下文不为空开始。
ngx_http_finalize_request 函数:
auth_request模块的函数
执行子请求,被ngx_http_request_handler函数调用。