nginx 变量机制--脚本引擎

在nginx中变量引擎机制随处可见,今天来分析一下这个机制。拿一个比较容易理解的指令set进行分析。

 

简单模式:set $name "HELLONGX";

对于$name的解析,就是把name作为变量加入到全局的变量表中,这个比较容易理解,今天暂不做分析。

主要分析这个“HELLONGX”是如何应用的。

在配置解析阶段调用如下函数:

if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {

    return NGX_CONF_ERROR;

}

 

在上述函数中,会n = ngx_http_script_variables_count(value);调用该函数计算变量值中是否存在变量.如果不存在val = ngx_http_script_start_code(cf->pool, &lcf->codes,sizeof(ngx_http_script_value_code_t)); 获取对应结构体。

 

变量的赋值如下:

val->code = ngx_http_script_value_code;

val->value = (uintptr_t) n;

val->text_len = (uintptr_t) value->len;

val->text_data = (uintptr_t) value->data;

上述设置完成之后,仅仅是对value获取的方法,最后还需要加一个函数,保证值可以被获取

vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,sizeof(ngx_http_script_var_code_t));

if (vcode == NULL) {

    return NGX_CONF_ERROR;

}

vcode->code = ngx_http_script_set_var_code;

vcode->index = (uintptr_t) index; //index为全部变量数组中的下标

 

 

 

变量如何使用:

在ngx_http_rewrite_handler(ngx_http_request_t *r)rewrite的回调函数中,检查rlcf->codes是否赋值过,如果赋值 执行脚本引擎。

e->sp = ngx_pcalloc(r->pool, rlcf->stack_size * sizeof(ngx_http_variable_value_t));

if (e->sp == NULL) {

    return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

 

//e->ip 为char*类型,直接指向elts的起始地址

e->ip = rlcf->codes->elts;

e->request = r;

e->quote = 1;

e->log = rlcf->log;

e->status = NGX_DECLINED;

 

while (*(uintptr_t *) e->ip) {

    code = *(ngx_http_script_code_pt *) e->ip; //在配置解析时 ngx_http_script_value_code_t 结构体

                                                                        //的第一个变量就是回调函数

    code(e);

}

 

===================

上面的code其实调用的回调函数为ngx_http_script_value_code

void

ngx_http_script_value_code(ngx_http_script_engine_t *e) //获取变量值

{

    ngx_http_script_value_code_t *code;

 

    code = (ngx_http_script_value_code_t *) e->ip;

 

    e->ip += sizeof(ngx_http_script_value_code_t);//偏移到下一个结构体的开始位置

 

    //将保存的变量放入到sp中

    e->sp->len = code->text_len;

    e->sp->data = (u_char *) code->text_data;

    //sp偏移加一

    e->sp++;

}

 

void

ngx_http_script_set_var_code(ngx_http_script_engine_t *e) //保存变量值

{

ngx_http_request_t *r;

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);

 

r = e->request;

 

e->sp--;

 

r->variables[code->index].len = e->sp->len;

r->variables[code->index].valid = 1;

r->variables[code->index].no_cacheable = 0;

r->variables[code->index].not_found = 0;

r->variables[code->index].data = e->sp->data; //把上一次执行的回调函数获取的值,在这里赋值

}

 

 

复杂模式:set $name "$value1-$value2-hellongx";

对于$name的解析,同上,本次暂不做分析。

主要分析这个“$value1-$value2-hellongx”是如何应用的。

首先通过n = ngx_http_script_variables_count(value);确定值域中变量的个数,如果大于0,则为复合模式。

complex = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(ngx_http_script_complex_value_code_t));

if (complex == NULL) {

return NGX_CONF_ERROR;

}

complex->code = ngx_http_script_complex_value_code; //同简单模式一样,该回调会获取具体值

complex->lengths = NULL;

 

//下面函数块是将 值域中进行拆分处理

sc.cf = cf;

sc.source = value;

sc.lengths = &complex->lengths;

sc.values = &lcf->codes;

sc.variables = n;

sc.complete_lengths = 1;

if (ngx_http_script_compile(&sc) != NGX_OK) {

return NGX_CONF_ERROR;

}

 

//值域拆分函数

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进行内存空间的分配 会根据变量的个数

if (ngx_http_script_init_arrays(sc) != NGX_OK) {

return NGX_ERROR;

}

 

for (i = 0; i < sc->source->len; /* void */ ) {

//循环分析“$value1-$value2-hellongx”值

//本示例中 先分析$value, 通过ngx_http_script_add_var_code(sc, &name)添加回调函数

{

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) (void *)ngx_http_script_copy_var_len_code;

code->index = (uintptr_t) index;

 

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_http_script_done(sc);

 

接下来看一下变量如何生效

在ngx_http_rewrite_handler(ngx_http_request_t *r)rewrite的回调函数中,检查rlcf->codes是否赋值过,如果赋值 执行脚本引擎。

e->sp = ngx_pcalloc(r->pool, rlcf->stack_size * sizeof(ngx_http_variable_value_t));

if (e->sp == NULL) {

return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

 

//e->ip 为char*类型,直接指向elts的起始地址

e->ip = rlcf->codes->elts;

e->request = r;

e->quote = 1;

e->log = rlcf->log;

e->status = NGX_DECLINED;

 

while (*(uintptr_t *) e->ip) {

code = *(ngx_http_script_code_pt *) e->ip; //在配置解析时 ngx_http_script_value_code_t 结构体

//的第一个变量就是回调函数

code(e);

}

 

===================

第一个code的回调是

void

ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)

{

size_t len;

ngx_http_script_engine_t le;

ngx_http_script_len_code_pt lcode;

ngx_http_script_complex_value_code_t *code;

code = (ngx_http_script_complex_value_code_t *) e->ip;

e->ip += sizeof(ngx_http_script_complex_value_code_t);

ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,

"http script complex value");

 

ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

 

le.ip = code->lengths->elts;

le.line = e->line;

le.request = e->request;

le.quote = e->quote;

/*这里的主要工作是遍历lengths,计算所有变量的长度,然后申请内存*/

for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {

lcode = *(ngx_http_script_len_code_pt *) le.ip;

}

 

e->buf.len = len;

e->buf.data = ngx_pnalloc(e->request->pool, len);

if (e->buf.data == NULL) {

e->ip = ngx_http_script_exit;

e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;

return;

}

 

e->pos = e->buf.data;

e->sp->len = e->buf.len;

e->sp->data = e->buf.data;

e->sp++;

}

 

接下来遍历执行code 也就是rlcf->codes下的函数

变量值:

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 = ngx_copy(p, value->data, value->len);

}

}

}

固定值:

void

ngx_http_script_copy_code(ngx_http_script_engine_t *e)

{

u_char *p;

ngx_http_script_copy_code_t *code;

 

code = (ngx_http_script_copy_code_t *) e->ip;

 

p = e->pos;

 

if (!e->skip) {

e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t),

code->len);

}

 

e->ip += sizeof(ngx_http_script_copy_code_t)

+ ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));

 

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,

"http script copy: \"%*s\"", e->pos - p, p);

}

 

最后一步:将具体值保存在全局变量数组中

void

ngx_http_script_set_var_code(ngx_http_script_engine_t *e) //保存变量值

{

ngx_http_request_t *r;

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);

r = e->request;

e->sp--;

r->variables[code->index].len = e->sp->len;

r->variables[code->index].valid = 1;

r->variables[code->index].no_cacheable = 0;

r->variables[code->index].not_found = 0;

r->variables[code->index].data = e->sp->data; //把上一次执行的回调函数获取的值,在这里赋值

}

========================  

rewrite  return if 等指令 大同小异

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值