Nginx 소스 코드 분석
모듈 ngxhttp_proxy_module 의 변수 $host 사용 과정
우선 첫 번 째, 변수의 성명 과 인터페이스 호출:
파일 보기 ngxhttp_variables. c 에 static ngx 성명 이 있 습 니 다.http_variable_t ngx_http_core_variables [] 즉 http 처리 와 관련 된 핵심 변 수 는 모든 모듈 에서 자신 이 사용 하 는 변 수 를 정의 합 니 다.먼저 ngxhttp_variable_t 의 정의:
struct ngx_http_variable_s {
ngx_str_t name; /* must be first to build the hash */
ngx_http_set_variable_pt set_handler; /* */
ngx_http_get_variable_pt get_handler; /* */
uintptr_t data;/* */
ngx_uint_t flags;
ngx_uint_t index;/* , 0*/
};
우 리 는 그 중의 하 나 를 보 았 다.
{ ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
이 항목 은 $host 변수의 정의 입 니 다. name 과 get 만 지정 합 니 다.hander, 그럼 이 handler 를 직접 보 겠 습 니 다.
static ngx_int_t
ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{ // handler http request , v ,data 。
ngx_http_core_srv_conf_t *cscf;
// HTTP Host URL Host ( http server ),
//
if (r->headers_in.server.len) {
v->len = r->headers_in.server.len;
v->data = r->headers_in.server.data;
} else {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
// ,
v->len = cscf->server_name.len;
v->data = cscf->server_name.data;
}
// ,
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
첫 번 째 는 기본적으로 여기까지 입 니 다. 두 번 째 변수의 분석 과정 을 계속 살 펴 보 겠 습 니 다. 즉, 설정 파일 에서 변 수 를 사용 할 때 nginx 가 시작 할 때 이 변 수 를 어떻게 분석 하고 어떤 처 리 를 하면 나중에 사용 하기에 편리 합 니까?여기 서 우 리 는 ngxhttp_proxy_module 모듈 에 proxy 설정pass 명령 을 사용 할 때 변수 $host 를 사용 한 다음 처리 과정 을 봅 니 다.
Nginx 에 다음 설정 이 있다 고 가정 합 니 다.
location / {
proxy_cache cache_one;
proxy_cache_valid 200 5d;
proxy_cache_key $host$uri;
resolver 8.8.8.8;
proxy_pass http://$host;
proxy_set_header Host $host;
}
우리 ngxhttp_proxy_module. c 파일 에서 명령 proxy패스 처리 하면 됩 니 다.유사 변수 정의, 많은 모듈 에서 이 모듈 이 사용 하 는 명령 을 정의 합 니 다. 이 명령 들 은 설정 파일 에서 사용 할 수 있 습 니 다. 위 설정 의 proxy 와 유사 합 니 다.패스 는 바로 ngxhttp_proxy_module 모듈 의 명령, ngxhttp_proxy_module 모듈 에서 다음 과 같은 명령 을 정의 합 니 다.
static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_pass"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
ngx_http_proxy_pass,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
.
.
.
}
여기에 proxy 를 인용 하 였 습 니 다.pass 명령 의 정의 입 니 다.명령 정의 에 대해 자세히 설명 하지 않 습 니 다. 이 명령 을 해석 하 는 handler 즉 ngx 를 보 았 습 니 다.http_proxy_pass, 이 handler 는 nginx 가 설정 파일 을 분석 할 때 이 명령 을 만나면 이 명령 의 설정 을 분석 하고 미리 처리 합 니 다. 이 handler 를 살 펴 보 겠 습 니 다.
static char *
ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_proxy_loc_conf_t *plcf = conf;
size_t add;
u_short port;
ngx_str_t *value, *url;
ngx_url_t u;
ngx_uint_t n;
ngx_http_core_loc_conf_t *clcf;
ngx_http_script_compile_t sc;
if (plcf->upstream.upstream || plcf->proxy_lengths) {
return "is duplicate";
}
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
// http handler
clcf->handler = ngx_http_proxy_handler;
//clcf->name.data location path , nginx “/”,
// if ,auto_redirect 1, uri
//location path “/” URL ( )
if (clcf->name.data[clcf->name.len - 1] == '/') {
clcf->auto_redirect = 1;
}
//nginx proxy_pass http://$host; 이 줄 은 빈 칸 에 따라 배열 로 해석 하여 elts 에 놓 습 니 다. value = cf->args->elts;
// proxy_pass http://$host; value[1] http://$host
url = &value[1];
// url , , , 1
n = ngx_http_script_variables_count(url);
if (n) {// ,
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = url;
sc.lengths = &plcf->proxy_lengths;
//plcf->proxy_lengths proxy_pass
sc.values = &plcf->proxy_values;
//proxy_values proxy_pass
sc.variables = n;//
sc.complete_lengths = 1;
sc.complete_values = 1;
// proxy_pass url
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
// ,
return NGX_CONF_OK;
}
변수의 주요 처리 과정 은 ngxhttp_script_copile 방법, 이 방법 을 살 펴 보 자.
ngx_int_t
ngx_http_script_compile(ngx_http_script_compile_t *sc)
{
u_char ch;
ngx_str_t name;
ngx_uint_t i, bracket;
// sc.lengths sc.values , proxy_lengths proxy_values;
if (ngx_http_script_init_arrays(sc) != NGX_OK) {
return NGX_ERROR;
}
//source url,
for (i = 0; i < sc->source->len; /* void */ ) {
name.len = 0;//name
//
if (sc->source->data[i] == '$') {
if (++i == sc->source->len) {
goto invalid_variable;
}
if (sc->source->data[i] == '{') {
// $ {
} else {
bracket = 0;
//name , $ , ++i
name.data = &sc->source->data[i];
}
// for name
for ( /* void */ ; i < sc->source->len; i++, name.len++) {
ch = sc->source->data[i];
if (ch == '}' && bracket) {
// }
}
if ((ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z')
|| (ch >= '0' && ch <= '9')
|| ch == '_')
{
continue;
}
break;
}
if (name.len == 0) {
goto invalid_variable;
}
// 1
sc->variables++;
//
if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
return NGX_ERROR;
}
continue;
}
if (sc->source->data[i] == '?' && sc->compile_args) {
//
continue;
}
// , , URL, http:// name.data = &sc->source->data[i];
// , name
while (i < sc->source->len) {
if (sc->source->data[i] == '$') {
break;
}
if (sc->source->data[i] == '?') {
}
i++;
name.len++;
}
sc->size += name.len;
//
if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
!= NGX_OK)
{
return NGX_ERROR;
}
}
//
return ngx_http_script_done(sc);
invalid_variable:
ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
return NGX_ERROR;
}
계속 깊이 들 어가 서 ngx 호출http_script_add_var_code (sc, & name) 는 어떻게 새로운 변 수 를 관련 배열 에 넣 습 니까?
static ngx_int_t
ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
{
ngx_int_t index, *p;
ngx_http_script_var_code_t *code;
// name cmcf->variables , name,
index = ngx_http_get_variable_index(sc->cf, name);
if (index == NGX_ERROR) {
return NGX_ERROR;
}
//flushes
if (sc->flushes) {
p = ngx_array_push(*sc->flushes);
if (p == NULL) {
return NGX_ERROR;
}
*p = index;
}
// sc->lengths ,
code = ngx_http_script_add_code(*sc->lengths,
sizeof(ngx_http_script_var_code_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
// , ,
code->code = (ngx_http_script_code_pt) ngx_http_script_copy_var_len_code;
code->index = (uintptr_t) index;
// sc->values
code = ngx_http_script_add_code(*sc->values,
sizeof(ngx_http_script_var_code_t),
&sc->main);
if (code == NULL) {
return NGX_ERROR;
}
// , ,
code->code = ngx_http_script_copy_var_code;
code->index = (uintptr_t) index;
return NGX_OK;
}
여기 보면 ngxhttp_script_add_var_code 에서 분 석 된 변 수 를 노드 로 만 들 것 입 니 다. 하 나 는 길 이 를 계산 하 는 노드 이 고 하 나 는 결 과 를 계산 하 는 노드 입 니 다. 각각 호출 인터페이스 ngx 를 지정 합 니 다.http_script_copy_var_len_code 는 변수 값 의 길이 와 ngx 를 계산 합 니 다.http_script_copy_var_변 수 를 가 져 오 는 code 입 니 다.변 수 를 사용 할 때 이 인 터 페 이 스 를 호출 하여 변수의 길 이 를 계산 하고 값 을 가 져 옵 니 다.
다음은 제 가 직접 ngx 를 보 겠 습 니 다.http_script_copy_var_len_code 와 ngxhttp_script_copy_var_code 의 실현:
size_t
ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
{
ngx_http_variable_value_t *value;
ngx_http_script_var_code_t *code;
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
if (e->flushed) {
// index , , hander
value = ngx_http_get_indexed_variable(e->request, code->index);
} else {
// , , , ngx_http_get_indexed_variable()
value = ngx_http_get_flushed_variable(e->request, code->index);
}
if (value && !value->not_found) {
return value->len;
}
return 0;
}
다시 보기 ngxhttp_script_copy_var_code 의 실현:void
ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
{
u_char *p;
ngx_http_variable_value_t *value;
ngx_http_script_var_code_t *code;
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
if (!e->skip) {
if (e->flushed) {
value = ngx_http_get_indexed_variable(e->request, code->index);
} else {
value = ngx_http_get_flushed_variable(e->request, code->index);
}
if (value && !value->not_found) {
p = e->pos;
// , e->pos , e->pos 。
e->pos = ngx_copy(p, value->data, value->len);
}
}
}
세 번 째 부분 은 변 수 를 사용 하 는 것 입 니 다. 우리 위의 예 는 바로 설정 입 니 다.
proxy_pass http://$host;
, nginx 가 원본 서버 에 자원 을 요청 할 때 설정 한 proxypass 는 새로운 요청 URL 을 생 성하 고 해당 하 는 자원 에 대한 답장 을 요청 합 니 다. 새로운 URL 을 생 성 하 는 곳 을 살 펴 보 겠 습 니 다.
static ngx_int_t
ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
ngx_http_proxy_loc_conf_t *plcf)
{
u_char *p;
size_t add;
u_short port;
ngx_str_t proxy;
ngx_url_t url;
ngx_http_upstream_t *u;
// proxy_pass URL, proxy
if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
plcf->proxy_values->elts)
== NULL)
{
return NGX_ERROR;
}
if (proxy.len > 7
&& ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
{
add = 7;
port = 80;
#if (NGX_HTTP_SSL)
} else if (proxy.len > 8
&& ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
{
add = 8;
port = 443;
r->upstream->ssl = 1;
#endif
} else {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid URL prefix in \"%V\"", &proxy);
return NGX_ERROR;
}
u = r->upstream;
u->schema.len = add;
u->schema.data = proxy.data;
ngx_memzero(&url, sizeof(ngx_url_t));
url.url.len = proxy.len - add;
url.url.data = proxy.data + add;
url.default_port = port;
url.uri_part = 1;
url.no_resolve = 1;
//½âÎöÇëÇóURL£¿
if (ngx_parse_url(r->pool, &url) != NGX_OK) {
if (url.err) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"%s in upstream \"%V\"", url.err, &url.url);
}
return NGX_ERROR;
}
//Èç¹û°üº¬uri²¿·ÖÇÒÈ«²¿Îª²ÎÊý£¬ÔòÖØп½±´Ò»·Ý£¬²¢ÔÚÆäÇ°Ìí¼ÓÉÏ/
if (url.uri.len) {
if (url.uri.data[0] == '?') {
p = ngx_pnalloc(r->pool, url.uri.len + 1);
if (p == NULL) {
return NGX_ERROR;
}
*p++ = '/';
ngx_memcpy(p, url.uri.data, url.uri.len);
url.uri.len++;
url.uri.data = p - 1;
}
}
ctx->vars.key_start = u->schema;
//ÉèÖÃctx->varsµÄhost-headerºÍportÒÔ¼°uri
ngx_http_proxy_set_vars(&url, &ctx->vars);
u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
if (u->resolved == NULL) {
return NGX_ERROR;
}
//url.addrsÓ¦¸Ã±íʾÒѽâÎöhostµÃµ½µÄIPµØÖ·£¬´Ë´¦Ó¦¸Ãδ½âÎö
if (url.addrs && url.addrs[0].sockaddr) {
u->resolved->sockaddr = url.addrs[0].sockaddr;
u->resolved->socklen = url.addrs[0].socklen;
u->resolved->naddrs = 1;
u->resolved->host = url.addrs[0].name;
} else {
u->resolved->host = url.host;
u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
u->resolved->no_port = url.no_port;
}
return NGX_OK;
}
저희 가 주로 보 러 왔어요.
ngx_http_script_run 의 실현:
u_char *
ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
void *code_lengths, size_t len, void *code_values)
{
ngx_uint_t i;
ngx_http_script_code_pt code;
ngx_http_script_len_code_pt lcode;
ngx_http_script_engine_t e;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
for (i = 0; i < cmcf->variables.nelts; i++) {
if (r->variables[i].no_cacheable) {
r->variables[i].valid = 0;
r->variables[i].not_found = 0;
}
}
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
e.ip = code_lengths;
e.request = r;
e.flushed = 1;
while (*(uintptr_t *) e.ip) {
lcode = *(ngx_http_script_len_code_pt *) e.ip;
len += lcode(&e);
}
value->len = len;
value->data = ngx_pnalloc(r->pool, len);
if (value->data == NULL) {
return NULL;
}
e.ip = code_values;
e.pos = value->data;
while (*(uintptr_t *) e.ip) {
code = *(ngx_http_script_code_pt *) e.ip;
code((ngx_http_script_engine_t *) &e);
}
return e.pos;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.