Nginx 脚本引擎解析源码注释
nginx的配置文件功能是相当强大的,之前了解了其主体执行流程,配置文件加载等,今天学习了一下其脚本解析的原理等,写了点注释放下面。
目前没写什么描述代码了,快趴下了,得睡觉去···
其他注释的代码在这里:https://github.com/kulv2012/ReadNginxSrc
最近比较忙,过段时间用grahpviz画个图吧
nginx脚本解析的文件包括ngx_http_script.h/c
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_SCRIPT_H_INCLUDED_
#define _NGX_HTTP_SCRIPT_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
u_char *ip;
/*关于pos && code: 每次调用code,都会将解析到的新的字符串放入pos指向的字符串处,
然后将pos向后移动,下次进入的时候,会自动将数据追加到后面的。
对于ip也是这个原理,code里面会将e->ip向后移动。移动的大小根据不同的变量类型相关。
ip指向一快内存,其内容为变量相关的一个结构体,比如ngx_http_script_copy_capture_code_t,
结构体之后,又是下一个ip的地址。比如移动时是这样的 :
code = (ngx_http_script_copy_capture_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_capture_code_t);//移动这么多位移。
*/
u_char *pos;//pos之前的数据就是解析成功的,后面的数据将追加到pos后面。
ngx_http_variable_value_t *sp;//这里貌似是用sp来保存中间结果,比如保存当前这一步的进度,到下一步好用e->sp--来找到上一步的结果。
ngx_str_t buf;//存放结果,也就是buffer,pos指向其中。
ngx_str_t line;//记录请求行URI e->line = r->uri;
/* the start of the rewritten arguments */
u_char *args;
unsigned flushed:1;
unsigned skip:1;
unsigned quote:1;
unsigned is_args:1;
unsigned log:1;
ngx_int_t status;
ngx_http_request_t *request;//所属的请求
} ngx_http_script_engine_t;
typedef struct {
ngx_conf_t *cf;
ngx_str_t *source;//指向字符串,比如http://$http_host/aa.mp4
ngx_array_t **flushes;
ngx_array_t **lengths;//指向外部的编译结果数组&index->lengths;等
ngx_array_t **values;
ngx_uint_t variables;//source指向的字符串中有几个变量
ngx_uint_t ncaptures;//最大的一个$3 的数字
ngx_uint_t captures_mask;
ngx_uint_t size;
void *main;
unsigned compile_args:1;
unsigned complete_lengths:1;
unsigned complete_values:1;
unsigned zero:1;
unsigned conf_prefix:1;
unsigned root_prefix:1;
unsigned dup_capture:1;
unsigned args:1;
} ngx_http_script_compile_t;
typedef struct {
ngx_str_t value;//要解析的字符串。
ngx_uint_t *flushes;
void *lengths;
void *values;
} ngx_http_complex_value_t;
typedef struct {
ngx_conf_t *cf;
ngx_str_t *value;//后面的参数字符串,要解析的字符串。
ngx_http_complex_value_t *complex_value;
unsigned zero:1;
unsigned conf_prefix:1;
unsigned root_prefix:1;
} ngx_http_compile_complex_value_t;
typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e);
typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e);
typedef struct {
ngx_http_script_code_pt code;
uintptr_t len;
} ngx_http_script_copy_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t index;//变量在cmcf->variables中的下标
} ngx_http_script_var_code_t;
typedef struct {
ngx_http_script_code_pt code;
ngx_http_set_variable_pt handler;
uintptr_t data;
} ngx_http_script_var_handler_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t n;//第几个capture,翻倍了的值。就是数字$1,$2,用来寻找r->captures里面的下标,已2为单位。
} ngx_http_script_copy_capture_code_t;
#if (NGX_PCRE)
typedef struct {
ngx_http_script_code_pt code;//当前的code,第一个函数,为ngx_http_script_regex_start_code
ngx_http_regex_t *regex;//解析后的正则表达式。
ngx_array_t *lengths;//我这个正则表达式对应的lengths。依靠它来解析 第二部分 rewrite ^(.*)$ http://$http_host.mp4 break;
//lengths里面包含一系列code,用来求目标url的大小的。
uintptr_t size;
uintptr_t status;
uintptr_t next;//next的含义为;如果当前code匹配失败,那么下一个code的位移是在什么地方,这些东西全部放在一个数组里面的。
uintptr_t test:1;//我是要看看是否正则匹配成功,你待会匹配的时候记得放个变量到堆栈里。
uintptr_t negative_test:1;
uintptr_t uri:1;//是否是URI匹配。
uintptr_t args:1;
/* add the r->args to the new arguments */
uintptr_t add_args:1;//是否自动追加参数到rewrite后面。如果目标结果串后面用问好结尾,则nginx不会拷贝参数到后面的
uintptr_t redirect:1;//nginx判断,如果是用http://等开头的rewrite,就代表是垮域重定向。会做302处理。
uintptr_t break_cycle:1;
//rewrite最后的参数是break,将rewrite后的地址在当前location标签中执行。具体参考ngx_http_script_regex_start_code
ngx_str_t name;
} ngx_http_script_regex_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t uri:1;
uintptr_t args:1;
/* add the r->args to the new arguments */
uintptr_t add_args:1;
uintptr_t redirect:1;
} ngx_http_script_regex_end_code_t;
#endif
typedef struct {
ngx_http_script_code_pt code;
uintptr_t conf_prefix;
} ngx_http_script_full_name_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t status;//返回的状态码。return code [ text ]
ngx_http_complex_value_t text;//ccv.complex_value = &ret->text;后面的参数的脚本引擎地址。
} ngx_http_script_return_code_t;
typedef enum {
ngx_http_script_file_plain = 0,
ngx_http_script_file_not_plain,
ngx_http_script_file_dir,
ngx_http_script_file_not_dir,
ngx_http_script_file_exists,
ngx_http_script_file_not_exists,
ngx_http_script_file_exec,
ngx_http_script_file_not_exec
} ngx_http_script_file_op_e;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t op;
} ngx_http_script_file_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t next;
void **loc_conf;//新的location配置。
} ngx_http_script_if_code_t;
typedef struct {
ngx_http_script_code_pt code;//ngx_http_script_complex_value_code
ngx_array_t *lengths;//复杂指令里面嵌套了其他code
} ngx_http_script_complex_value_code_t;
typedef struct {
ngx_http_script_code_pt code;//可以为ngx_http_script_value_code
uintptr_t value;//数字大小,或者如果text_data不是数字串,就为0.
uintptr_t text_len;//简单字符串的长度。
uintptr_t text_data;//记录字符串地址value->data;
} ngx_http_script_value_code_t;
void ngx_http_script_flush_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val);
ngx_int_t ngx_http_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val, ngx_str_t *value);
ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv);
char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r,
ngx_array_t *predicates);
char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value);
ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc);
u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
void *code_lengths, size_t reserved, void *code_values);
void ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
ngx_array_t *indices);
void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes,
size_t size);
void *ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code);
size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e);
void ngx_http_script_start_args_code(ngx_http_script_engine_t *e);
#if (NGX_PCRE)
void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e);
void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e);
#endif
void ngx_http_script_return_code(ngx_http_script_engine_t *e);
void ngx_http_script_break_code(ngx_http_script_engine_t *e);
void ngx_http_script_if_code(ngx_http_script_engine_t *e);
void ngx_http_script_equal_code(ngx_http_script_engine_t *e);
void ngx_http_script_not_equal_code(ngx_http_script_engine_t *e);
void ngx_http_script_file_code(ngx_http_script_engine_t *e);
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
void ngx_http_script_value_code(ngx_http_script_engine_t *e);
void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e);
void ngx_http_script_var_code(ngx_http_script_engine_t *e);
void ngx_http_script_nop_code(ngx_http_script_engine_t *e);
#endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */
实现文件如下,介绍什么的都在注释中了:
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc);
static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc);
static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc,
ngx_str_t *value, ngx_uint_t last);
static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc,
ngx_str_t *name);
static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc);
#if (NGX_PCRE)
static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc,
ngx_uint_t n);
#endif
static ngx_int_t
ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc);
static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e);
static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e);
#define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code
static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL;
void ngx_http_script_flush_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val)
{//清楚变量的valid,not_found标识,这样就能自动的在下一次去获取变量值了。
ngx_uint_t *index;
index = val->flushes;
if (index) {
while (*index != (ngx_uint_t) -1) {
if (r->variables[*index].no_cacheable) {
r->variables[*index].valid = 0;
r->variables[*index].not_found = 0;
}
index++;
}
}
}
ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, ngx_str_t *value)
{//根据val复杂表达式结构,获取其代表的目标值,存入value.
size_t len;
ngx_http_script_code_pt code;
ngx_http_script_len_code_pt lcode;
ngx_http_script_engine_t e;
if (val->lengths == NULL) {//没有lengths,那就是简单变量了,直接指向一下数据就行。
*value = val->value;
return NGX_OK;
}
ngx_http_script_flush_complex_value(r, val);
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
e.ip = val->lengths;
e.request = r;
e.flushed = 1;
len = 0;
while (*(uintptr_t *) e.ip) {//不断调用code.获取其长度
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 NGX_ERROR;
}
e.ip = val->values;//调用values回调数组进行值的拷贝。
e.pos = value->data;
e.buf = *value;
while (*(uintptr_t *) e.ip) {//获取内容。
code = *(ngx_http_script_code_pt *) e.ip;
code((ngx_http_script_engine_t *) &e);
}
*value = e.buf;
return NGX_OK;
}
/*ngx_http_rewrite_return调用这里。解析return code [ text ] 后面的text或者URL。
结果存放在ccv->complex_value里面。为什么在这个里面呢
*/
ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv)
{
ngx_str_t *v;
ngx_uint_t i, n, nv, nc;
ngx_array_t flushes, lengths, values, *pf, *pl, *pv;
ngx_http_script_compile_t sc;
v = ccv->value;
if (v->len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter");
return NGX_ERROR;
}
nv = 0;
nc = 0;
for (i = 0; i < v->len; i++) {
if (v->data[i] == '$') {
if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
nc++;//统计匿名子模式的数目,这个会向上引用的。
} else {
nv++;//统计一般变量的数目。
}
}
}
//如果第一位为非变量,那就转变为绝对路径。
if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) {
if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
return NGX_ERROR;
}
ccv->conf_prefix = 0;
ccv->root_prefix = 0;
}
//下面计算初始化三个变量的数组。
ccv->complex_value->value = *v;
ccv->complex_value->flushes = NULL;
ccv->complex_value->lengths = NULL;
ccv->complex_value->values = NULL;
if (nv == 0 && nc == 0) {//字符串和变量都没有,那就是简单的东东,上传肯定出bug了,不然这个简单字符串是不能正确处理的。
return NGX_OK;
}
n = nv + 1;
if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) != NGX_OK){
return NGX_ERROR;
}
n = nv * (2 * sizeof(ngx_http_script_copy_code_t) + sizeof(ngx_http_script_var_code_t)) + sizeof(uintptr_t);
if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
return NGX_ERROR;
}
n = (nv * (2*sizeof(ngx_http_script_copy_code_t)+sizeof(ngx_http_script_var_code_t))+sizeof(uintptr_t)+v->len+sizeof(uintptr_t) - 1)
& ~(sizeof(uintptr_t) - 1);
if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
return NGX_ERROR;
}
pf = &flushes;
pl = &lengths;
pv = &values;
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = ccv->cf;
sc.source = v;
sc.flushes = &pf;
sc.lengths = &pl;
sc.values = &pv;
sc.complete_lengths = 1;
sc.complete_values = 1;
sc.zero = ccv->zero;
sc.conf_prefix = ccv->conf_prefix;
sc.root_prefix = ccv->root_prefix;
//进行脚本解析编译,结果会反应到ccv->complex_value里面的。
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_ERROR;
}
if (flushes.nelts) {
ccv->complex_value->flushes = flushes.elts;
ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
}
ccv->complex_value->lengths = lengths.elts;
ccv->complex_value->values = values.elts;
return NGX_OK;
}
char *
ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *value;
ngx_http_complex_value_t **cv;
ngx_http_compile_complex_value_t ccv;
cv = (ngx_http_complex_value_t **) (p + cmd->offset);
if (*cv != NULL) {
return "duplicate";
}
*cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (*cv == NULL) {
return NGX_CONF_ERROR;
}
value = cf->args->elts;
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[1];
ccv.complex_value = *cv;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
ngx_int_t
ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
{
ngx_str_t val;
ngx_uint_t i;
ngx_http_complex_value_t *cv;
if (predicates == NULL) {
return NGX_OK;
}
cv = predicates->elts;
for (i = 0; i < predicates->nelts; i++) {
if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
return NGX_ERROR;
}
if (val.len && val.data[0] != '0') {
return NGX_DECLINED;
}
}
return NGX_OK;
}
char *
ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *value;
ngx_uint_t i;
ngx_array_t **a;
ngx_http_complex_value_t *cv;
ngx_http_compile_complex_value_t ccv;
a = (ngx_array_t **) (p + cmd->offset);
if (*a == NGX_CONF_UNSET_PTR) {
*a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
if (*a == NULL) {
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
cv = ngx_array_push(*a);
if (cv == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[i];
ccv.complex_value = cv;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
ngx_uint_t
ngx_http_script_variables_count(ngx_str_t *value)
{//以'$'开头的便是变量
ngx_uint_t i, n;
for (n = 0, i = 0; i < value->len; i++) {
if (value->data[i] == '$') {
n++;
}
}
return n;
}
/*下面解析如下几种脚本:
$1 , $2 : ngx_http_script_add_capture_code
$abc, $id : ngx_http_script_add_var_code
?a=va : ngx_http_script_add_args_code
abcd : ngx_http_script_add_copy_code
*/
ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc)
{//传入一个字符串,进行编译解析,比如http://$host/aaa.php;将计算长度的lcode放入sc->lengths,计算值的放入sc->values
u_char ch;
ngx_str_t name;
ngx_uint_t i, bracket;
if (ngx_http_script_init_arrays(sc) != NGX_OK) {//根据variables变量数目,创建lengths,values等数组。
return NGX_ERROR;
}
for (i = 0; i < sc->source->len; /* void */ ) {//一个个遍历参数里面的字符串,比如
name.len = 0;
if (sc->source->data[i] == '$') {//找到一个变量
if (++i == sc->source->len) {//但是到头了,结尾
goto invalid_variable;
}
#if (NGX_PCRE)
{
ngx_uint_t n;
if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
//碰到了一个正则的向上引用,比如$1
n = sc->source->data[i] - '0';
if (sc->captures_mask & (1 << n)) {
sc->dup_capture = 1;
}
sc->captures_mask |= 1 << n;//增加这个引用代码到lengths,values数组里面
if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
return NGX_ERROR;
}
i++;
continue;
}
}
#endif
if (sc->source->data[i] == '{') {
bracket = 1;
if (++i == sc->source->len) {
goto invalid_variable;
}
name.data = &sc->source->data[i];
} else {
bracket = 0;
name.data = &sc->source->data[i];
}
for ( /* void */ ; i < sc->source->len; i++, name.len++) {
ch = sc->source->data[i];
if (ch == '}' && bracket) {
i++;
bracket = 0;
break;
}
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')|| ch == '_'){
continue; //接受字母,数组,下划线的变量
}
break;
}
if (bracket) {
ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "the closing bracket in \"%V\" variable is missing", &name);
return NGX_ERROR;
}
if (name.len == 0) {
goto invalid_variable;
}
sc->variables++;//找到了一个变量,将其加入到sc->lengths中,同事cmcf->varibles里面也会增加一个。
if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
return NGX_ERROR;
}
continue;
}
if (sc->source->data[i] == '?' && sc->compile_args) {
sc->args = 1;
sc->compile_args = 0;//增加一个参数到sc->lengths 中
if (ngx_http_script_add_args_code(sc) != NGX_OK) {
return NGX_ERROR;
}
i++;
continue;
}
name.data = &sc->source->data[i];
while (i < sc->source->len) {//不是变量什么的,就直接往后找,一直找到一个变量,或者参数段开始。这中间的是简单字符串
if (sc->source->data[i] == '$') {
break;
}
if (sc->source->data[i] == '?') {
sc->args = 1;
if (sc->compile_args) {
break;
}
}
i++;
name.len++;
}
sc->size += name.len;//下面就是简单的copy了,简单字符串。
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;
}
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);//里面会改变e的ip的
}
return e.pos;
}
void
ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r, ngx_array_t *indices)
{
ngx_uint_t n, *index;
if (indices) {
index = indices->elts;
for (n = 0; n < indices->nelts; n++) {
if (r->variables[index[n]].no_cacheable) {
r->variables[index[n]].valid = 0;
r->variables[index[n]].not_found = 0;
}
}
}
}
static ngx_int_t
ngx_http_script_init_arrays(ngx_http_script_compile_t *sc)
{//根据variables变量数目,创建lengths,values等数组。
ngx_uint_t n;
if (sc->flushes && *sc->flushes == NULL) {
n = sc->variables ? sc->variables : 1;
*sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
if (*sc->flushes == NULL) {
return NGX_ERROR;
}
}
if (*sc->lengths == NULL) {
//下面是有多少个变量,就多少组。每一组包括2个copy_code_t,1个var_code_t,1个指针
n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + sizeof(ngx_http_script_var_code_t)) + sizeof(uintptr_t);
*sc->lengths = ngx_array_create(sc->cf->pool, n, 1);//申请这么多个指针。
if (*sc->lengths == NULL) {
return NGX_ERROR;
}
}
if (*sc->values == NULL) {
n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + sizeof(ngx_http_script_var_code_t))
+ sizeof(uintptr_t) + sc->source->len + sizeof(uintptr_t) - 1)
& ~(sizeof(uintptr_t) - 1);
*sc->values = ngx_array_create(sc->cf->pool, n, 1);
if (*sc->values == NULL) {
return NGX_ERROR;
}
}
sc->variables = 0;
return NGX_OK;
}
static ngx_int_t
ngx_http_script_done(ngx_http_script_compile_t *sc)
{//跟进不同的参数,在sc->lengths后面追加NULL元素。
ngx_str_t zero;
uintptr_t *code;
if (sc->zero) {
zero.len = 1;
zero.data = (u_char *) "\0";
if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
return NGX_ERROR;
}
}
if (sc->conf_prefix || sc->root_prefix) {
if (ngx_http_script_add_full_name_code(sc) != NGX_OK) {
return NGX_ERROR;
}
}
if (sc->complete_lengths) {
code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) NULL;
}
if (sc->complete_values) {
code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) NULL;
}
return NGX_OK;
}
void *
ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
{//在指定的codes数组里面增加一项,大小为size
if (*codes == NULL) {
*codes = ngx_array_create(pool, 256, 1);
if (*codes == NULL) {
return NULL;
}
}
return ngx_array_push_n(*codes, size);
}
void *
ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
{//在code里面增加一项,大小为size
u_char *elts, **p;
void *new;
elts = codes->elts;
new = ngx_array_push_n(codes, size);//codes->elts可能会变化的。如果数组已经满了需要申请一块大的内存
if (new == NULL) {
return NULL;
}
if (code) {
if (elts != codes->elts) {//如果内存变化了,
p = code;//因为code参数表的是&sc->main这种,也就是指向本数组的数据,因此需要更新一下位移信息。
*p += (u_char *) codes->elts - elts;//这是什么意思,加上了新申请的内存的位移。
}
}
return new;
}
static ngx_int_t
ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last)
{
u_char *p;
size_t size, len, zero;
ngx_http_script_copy_code_t *code;
zero = (sc->zero && last);
len = value->len + zero;
code = ngx_http_script_add_code(*sc->lengths, sizeof(ngx_http_script_copy_code_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
code->len = len;//记录字符串长度
size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
code = ngx_http_script_add_code(*sc->values, size, &sc->main);
if (code == NULL) {
return NGX_ERROR;
}
code->code = ngx_http_script_copy_code;
code->len = len;
p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t), value->data, value->len);
if (zero) {
*p = '\0';
sc->zero = 0;
}
return NGX_OK;
}
size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
{//获取指令的长度。
ngx_http_script_copy_code_t *code;
code = (ngx_http_script_copy_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_code_t);//改变ip,让他指向下一个指令的地址。
return code->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) {//拷贝从ip指针后面的部分。也就是数据部分。
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) 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);
}
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;
//根据变量名字,获取其在&cmcf->variables里面的下标。如果没有,就新建它。
index = ngx_http_get_variable_index(sc->cf, name);
if (index == NGX_ERROR) {
return NGX_ERROR;
}
if (sc->flushes) {
p = ngx_array_push(*sc->flushes);
if (p == NULL) {
return NGX_ERROR;
}
*p = index;
}
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;
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;
}
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) {
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) {
return value->len;//返回这个变量的长度。
}
return 0;
}
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 {//flushed的区别就是会强制吧valid变为0,促使调用get_handler函数重新获取变量的值。
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);//拷贝数据到输出变量里面
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script var: \"%*s\"", e->pos - p, p);
}
}
}
static ngx_int_t
ngx_http_script_add_args_code(ngx_http_script_compile_t *sc)
{//添加一个参数 脚本
uintptr_t *code;
code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) ngx_http_script_mark_args_code;
code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) ngx_http_script_start_args_code;
return NGX_OK;
}
size_t
ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
{
e->is_args = 1;
e->ip += sizeof(uintptr_t);
return 1;
}
void
ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
{
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script args");
e->is_args = 1;
e->args = e->pos;
e->ip += sizeof(uintptr_t);
}
#if (NGX_PCRE)
/*
1. 调用正则表达式引擎编译URL参数行,如果匹配失败,则e->ip += code->next;让调用方调到下一个表达式块进行解析。
2.如果成功,调用code->lengths,从而获取正则表达式替换后的字符串长度,以备在此函数返回后的code函数调用中能够存储新字符串长度。
*/
void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e) {
//匹配正则表达式,计算目标字符串长度并分配空间。这个函数是每条rewrite语句最先调用的解析函数,
//本函数负责匹配,和目标字符串长度计算,依据lengths lcodes数组进行
size_t len;
ngx_int_t rc;
ngx_uint_t n;
ngx_http_request_t *r;
ngx_http_script_engine_t le;
ngx_http_script_len_code_pt lcode;
ngx_http_script_regex_code_t *code;
code = (ngx_http_script_regex_code_t *) e->ip;
r = e->request;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"http script regex: \"%V\"", &code->name);
if (code->uri) {
e->line = r->uri;
} else {
e->sp--;
e->line.len = e->sp->len;
e->line.data = e->sp->data;
}
//下面用已经编译的regex 跟e->line去匹配,看看是否匹配成功。
rc = ngx_http_regex_exec(r, code->regex, &e->line);
if (rc == NGX_DECLINED) {//匹配失败
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "\"%V\" does not match \"%V\"", &code->name, &e->line);
}
r->ncaptures = 0;//一个都没有成功
if (code->test) {
if (code->negative_test) {
e->sp->len = 1;
e->sp->data = (u_char *) "1";
} else {
e->sp->len = 0;
e->sp->data = (u_char *) "";
}
e->sp++;//移动到下一个节点。返回。
e->ip += sizeof(ngx_http_script_regex_code_t);
return;
}
e->ip += code->next;//next的含义为;如果当前code匹配失败,那么下一个code的位移是在什么地方,这些东西全部放在一个数组里面的。
return;
}
if (rc == NGX_ERROR) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "\"%V\" matches \"%V\"", &code->name, &e->line);
}
if (code->test) {//如果匹配成功了,那设置一个标志吧,这样比如做if匹配的时候就能通过查看堆栈的值来知道是否成功。
if (code->negative_test) {
e->sp->len = 0;
e->sp->data = (u_char *) "";
} else {
e->sp->len = 1;
e->sp->data = (u_char *) "1";
}
e->sp++;
e->ip += sizeof(ngx_http_script_regex_code_t);
return;
}
if (code->status) {
e->status = code->status;
if (!code->redirect) {
e->ip = ngx_http_script_exit;
return;
}
}
if (code->uri) {
r->internal = 1;
r->valid_unparsed_uri = 0;
if (code->break_cycle) {//rewrite最后的参数是break,将rewrite后的地址在当前location标签中执行
r->valid_location = 0;
r->uri_changed = 0;//将uri_changed设置为0后,也就标志说URL没有变化,那么,
//在ngx_http_core_post_rewrite_phase中就不会执行里面的if语句,也就不会再次走到find config的过程了,而是继续处理后面的。
//不然正常情况,rewrite成功后是会重新来一次的,相当于一个全新的请求。
} else {
r->uri_changed = 1;
}
}
if (code->lengths == NULL) {//如果后面部分是简单字符串比如 rewrite ^(.*)$ http://chenzhenianqing.cn break;
e->buf.len = code->size;//下面只是求一下大小。那数据呢
if (code->uri) {
if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_ARGS);
}
}
for (n = 2; n < r->ncaptures; n += 2) {
e->buf.len += r->captures[n + 1] - r->captures[n];
}
} else {
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
le.ip = code->lengths->elts;
le.line = e->line;
le.request = r;
le.quote = code->redirect;
len = 0;
while (*(uintptr_t *) le.ip) {/*一个个去处理复杂表达式,但是这里其实只是算一下大小的,
真正的数据拷贝在上层的code获取。比如 rewrite ^(.*)$ http://$http_host.mp4 break;
//下面会分步的,拼装出后面的url,对于上面的例子,为
ngx_http_script_copy_len_code 7
ngx_http_script_copy_var_len_code 18
ngx_http_script_copy_len_code 4 === 29
这里只是求一下长度,调用lengths求长度。数据拷贝在ngx_http_rewrite_handler中,本函数返回后就调用如下过程拷贝数据:
ngx_http_script_copy_code 拷贝"http://" 到e->buf
ngx_http_script_copy_var_code 拷贝"115.28.34.175:8881"
ngx_http_script_copy_code 拷贝".mp4"
*/
lcode = *(ngx_http_script_len_code_pt *) le.ip;
len += lcode(&le);
}
e->buf.len = len;//记住总长度。
e->is_args = le.is_args;
}
if (code->add_args && r->args.len) {//是否需要自动增加参数。如果配置行的后面显示的加上了?符号,则nginx不会追加参数。
e->buf.len += r->args.len + 1;
}
e->buf.data = ngx_pnalloc(r->pool, e->buf.len);
if (e->buf.data == NULL) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
e->quote = code->redirect;
e->pos = e->buf.data;//申请了这么大的空间,用来装数据
e->ip += sizeof(ngx_http_script_regex_code_t);//处理下一个。
}
void
ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
{//貌似没干什么事情,如果是redirect,急设置了一下头部header的location,该302了。
u_char *dst, *src;
ngx_http_request_t *r;
ngx_http_script_regex_end_code_t *code;
code = (ngx_http_script_regex_end_code_t *) e->ip;
r = e->request;
e->quote = 0;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"http script regex end");
if (code->redirect) {
dst = e->buf.data;
src = e->buf.data;
ngx_unescape_uri(&dst, &src, e->pos - e->buf.data, NGX_UNESCAPE_REDIRECT);
if (src < e->pos) {
dst = ngx_copy(dst, src, e->pos - src);
}
e->pos = dst;
if (code->add_args && r->args.len) {
*e->pos++ = (u_char) (code->args ? '&' : '?');
e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
}
e->buf.len = e->pos - e->buf.data;
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "rewritten redirect: \"%V\"", &e->buf);
}
r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
r->headers_out.location->hash = 1;
ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value = e->buf;
e->ip += sizeof(ngx_http_script_regex_end_code_t);
return;
}
if (e->args) {//如果请求有参数,那么可能需要拷贝一下参数
e->buf.len = e->args - e->buf.data;
if (code->add_args && r->args.len) {//需要拷贝参数,且参数不为空。下面拷贝一下参数部分。
*e->pos++ = '&';
e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
}
r->args.len = e->pos - e->args;
r->args.data = e->args;
e->args = NULL;
} else {
e->buf.len = e->pos - e->buf.data;
if (!code->add_args) {
r->args.len = 0;
}
}
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "rewritten data: \"%V\", args: \"%V\"", &e->buf, &r->args);
}
if (code->uri) {
r->uri = e->buf;
if (r->uri.len == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the rewritten URI has a zero length");
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
ngx_http_set_exten(r);
}
e->ip += sizeof(ngx_http_script_regex_end_code_t);
}
static ngx_int_t
ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
{//增加一个向上引用比如$1, 参数n是这个$1的1字。
ngx_http_script_copy_capture_code_t *code;
code = ngx_http_script_add_code(*sc->lengths, sizeof(ngx_http_script_copy_capture_code_t), NULL);
if (code == NULL) {//从sc->lengths数组中申请一块内存,并返回其地址。
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt) ngx_http_script_copy_capture_len_code;
code->n = 2 * n;//2倍的原因是PCRE保存结果的关系
code = ngx_http_script_add_code(*sc->values, sizeof(ngx_http_script_copy_capture_code_t), &sc->main);
if (code == NULL) {//在values里面增加一项
return NGX_ERROR;
}
code->code = ngx_http_script_copy_capture_code;
code->n = 2 * n;
if (sc->ncaptures < n) {
sc->ncaptures = n;
}
return NGX_OK;
}
size_t
ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
{//跟ngx_http_script_copy_capture_code对应,这里是求长度,后者是i拷贝值。
int *cap;
u_char *p;
ngx_uint_t n;
ngx_http_request_t *r;
ngx_http_script_copy_capture_code_t *code;
r = e->request;
code = (ngx_http_script_copy_capture_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_capture_code_t);
n = code->n;
if (n < r->ncaptures) {
cap = r->captures;
if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) {
p = r->captures_data;
return cap[n + 1] - cap[n] + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n], NGX_ESCAPE_ARGS);
} else {
return cap[n + 1] - cap[n];
}
}
return 0;
}
void
ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
{//拷贝一下正则表达式解析后的 变量 的值。比如命名子模式$var或者匿名子模式$2
int *cap;
u_char *p, *pos;
ngx_uint_t n;
ngx_http_request_t *r;
ngx_http_script_copy_capture_code_t *code;
r = e->request;
code = (ngx_http_script_copy_capture_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_capture_code_t);
n = code->n;
pos = e->pos;
if (n < r->ncaptures) {
cap = r->captures;//得到刚才的正则表达式解析的结果,放在这里。其内容为2个单位元素的数组,分别代表匹配的开始结束。
p = r->captures_data;
if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) {
e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]], cap[n + 1] - cap[n], NGX_ESCAPE_ARGS);
} else {
//将数据拷贝到目标地址,然后返回尾部,直接修改e->pos
e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script capture: \"%*s\"", e->pos - pos, pos);
}
#endif
static ngx_int_t
ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
{
ngx_http_script_full_name_code_t *code;
code = ngx_http_script_add_code(*sc->lengths,
sizeof(ngx_http_script_full_name_code_t),
NULL);
if (code == NULL) {
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code;
code->conf_prefix = sc->conf_prefix;
code = ngx_http_script_add_code(*sc->values,
sizeof(ngx_http_script_full_name_code_t),
&sc->main);
if (code == NULL) {
return NGX_ERROR;
}
code->code = ngx_http_script_full_name_code;
code->conf_prefix = sc->conf_prefix;
return NGX_OK;
}
static size_t
ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e)
{
ngx_http_script_full_name_code_t *code;
code = (ngx_http_script_full_name_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_full_name_code_t);
return code->conf_prefix ? ngx_cycle->conf_prefix.len:
ngx_cycle->prefix.len;
}
static void
ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
{
ngx_http_script_full_name_code_t *code;
ngx_str_t value;
code = (ngx_http_script_full_name_code_t *) e->ip;
value.data = e->buf.data;
value.len = e->pos - e->buf.data;
if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix)
!= NGX_OK)
{
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
e->buf = value;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script fullname: \"%V\"", &value);
e->ip += sizeof(ngx_http_script_full_name_code_t);
}
void
ngx_http_script_return_code(ngx_http_script_engine_t *e)
{
ngx_http_script_return_code_t *code;
code = (ngx_http_script_return_code_t *) e->ip;
if (code->status < NGX_HTTP_BAD_REQUEST || code->text.value.len || code->text.lengths) {
//是400,或者是个简单字符串,或者是复杂表达式,那么需要正规的好好的处理一下才行。
//根据复杂表达式获取其值,然后确定是重定向还是要发送响应,将头部数据和body数据发送给客户端。
e->status = ngx_http_send_response(e->request, code->status, NULL, &code->text);
} else {//一般正常请求,正常结束就行。顶多终止后面的过程处理
e->status = code->status;
}
e->ip = ngx_http_script_exit;//修改为空,上层会结束的。
}
void
ngx_http_script_break_code(ngx_http_script_engine_t *e)
{//Syntax: break
e->request->uri_changed = 0;//待会就算有重定向成功了,我也不重新find config 了。就这么简单。
e->ip = ngx_http_script_exit;
}
void
ngx_http_script_if_code(ngx_http_script_engine_t *e)
{//if匹配完后,在此做location替换神马的。
ngx_http_script_if_code_t *code;
code = (ngx_http_script_if_code_t *) e->ip;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script if");
e->sp--;//回退一下栈
if (e->sp->len && e->sp->data[0] != '0') {//根据栈上的值是不是"1"来判断刚才的if匹配是否成功。这个是跟上面的code协商的。
if (code->loc_conf) {//成功了的话,就换一个location !!!!!
e->request->loc_conf = code->loc_conf;//替换为if里面的location
ngx_http_update_location_config(e->request);//更新各种配置。
}
e->ip += sizeof(ngx_http_script_if_code_t);//转到下一个code处理。
return;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script if: false");
e->ip += code->next;//如果刚才的if匹配失败了,那么,就跳到下一个code块处理。
}
void
ngx_http_script_equal_code(ngx_http_script_engine_t *e)
{
/*注意,当解析到这个函数的时候,堆栈已经放入了2个值了,从底向上为:ngx_http_rewrite_variable存入变量的值,
ngx_http_script_complex_value_code存入复杂表达式匹配出来的值。因此这个code正好可以取堆栈上的1,2个位置就是要比较的2个字符串。
*/
ngx_http_variable_value_t *val, *res;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script equal");
e->sp--;//得到栈里面的上一个值,其实就是ngx_http_rewrite_value挂载的那些句柄,
//在rewrite phrase过程中执行时设置的值,存放在堆栈里面供大家分享,呵呵
val = e->sp;//
res = e->sp - 1;
e->ip += sizeof(uintptr_t);//往后移动1个指针就行。
//脚本解析出来的字符串放在e->sp中,其正好跟上上一个字符串相等,就OK。这是啥意思。
if (val->len == res->len && ngx_strncmp(val->data, res->data, res->len) == 0) {
*res = ngx_http_variable_true_value;//将堆栈上面第二个字符串改为"1"
//这里改为1是跟ngx_http_script_if_code这个判断整个if是否成功的code配合的,对方也是这么判断是否成功的。
//也就是,我这个比较操作符,跟结果判断操作符(就是下一个code),沟通用这种方式判断是否匹配成功。
return;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script equal: no");
*res = ngx_http_variable_null_value;//不成功。
}
void
ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
{//同ngx_http_script_equal_code,做不等匹配。
ngx_http_variable_value_t *val, *res;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script not equal");
e->sp--;
val = e->sp;
res = e->sp - 1;
e->ip += sizeof(uintptr_t);
if (val->len == res->len && ngx_strncmp(val->data, res->data, res->len) == 0){
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script not equal: no");
*res = ngx_http_variable_null_value;
return;
}
*res = ngx_http_variable_true_value;
}
void
ngx_http_script_file_code(ngx_http_script_engine_t *e)
{//看看文件是否存在。并设置相关的标识,供if语句判断是否存在
ngx_str_t path;
ngx_http_request_t *r;
ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
ngx_http_variable_value_t *value;
ngx_http_script_file_code_t *code;
value = e->sp - 1;
code = (ngx_http_script_file_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_file_code_t);
path.len = value->len - 1;
path.data = value->data;
r = e->request;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http script file op %p \"%V\"", code->op, &path);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
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_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, value->data);
}
switch (code->op) {
case ngx_http_script_file_plain:
case ngx_http_script_file_dir:
case ngx_http_script_file_exists:
case ngx_http_script_file_exec:
goto false_value;
case ngx_http_script_file_not_plain:
case ngx_http_script_file_not_dir:
case ngx_http_script_file_not_exists:
case ngx_http_script_file_not_exec:
goto true_value;
}
goto false_value;
}
switch (code->op) {
case ngx_http_script_file_plain:
if (of.is_file) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_plain:
if (of.is_file) {
goto false_value;
}
goto true_value;
case ngx_http_script_file_dir:
if (of.is_dir) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_dir:
if (of.is_dir) {
goto false_value;
}
goto true_value;
case ngx_http_script_file_exists:
if (of.is_file || of.is_dir || of.is_link) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_exists:
if (of.is_file || of.is_dir || of.is_link) {
goto false_value;
}
goto true_value;
case ngx_http_script_file_exec:
if (of.is_exec) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_exec:
if (of.is_exec) {
goto false_value;
}
goto true_value;
}
false_value:
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script file op false");
*value = ngx_http_variable_null_value;
return;
true_value:
*value = ngx_http_variable_true_value;
return;
}
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
{//依据lengths里面的指令数组,遍历调用里面的codes, 获取一个变量的内容。会增加堆栈值。
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_scbreak ript_engine_t));
le.ip = code->lengths->elts;//复杂指令里面嵌套了其他code
le.line = e->line;
le.request = e->request;
le.quote = e->quote;
for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {//处理这个复杂数据的codes,获取其长度。
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++;//这里貌似是用sp来保存中间结果,比如保存当前这一步的进度,到下一步好用e->sp--来找到上一步的结果。
}
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);
e->sp->len = code->text_len;
e->sp->data = (u_char *) code->text_data;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script value: \"%v\"", e->sp);
e->sp++;//这里貌似是用sp来保存中间结果,比如保存当前这一步的进度,到下一步好用e->sp--来找到上一步的结果。
}
void
ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
{//根据e指向的内容填充r->variables[code->index]。设置i这个变量。一般在set $variable value指令的最后一个code会调用这里保存值。
ngx_http_request_t *r;
ngx_http_script_var_code_t *code;
// e->ip就是之前在解析时设置的各种结构体
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;
#if (NGX_DEBUG)
{
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
v = cmcf->variables.elts;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script set $%V", &v[code->index].name);
}
#endif
}
void
ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
{
ngx_http_script_var_handler_code_t *code;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script set var handler");
code = (ngx_http_script_var_handler_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_handler_code_t);
e->sp--;
code->handler(e->request, e->sp, code->data);
}
void
ngx_http_script_var_code(ngx_http_script_engine_t *e)
{//获取一个变量的植。
ngx_http_variable_value_t *value;
ngx_http_script_var_code_t *code;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script var");
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
value = ngx_http_get_flushed_variable(e->request, code->index);
if (value && !value->not_found) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script var: \"%v\"", value);
*e->sp = *value;//设置值
e->sp++;//这里增加堆栈,保存这个值。后续可以取出来。
return;
}
*e->sp = ngx_http_variable_null_value;
e->sp++;
}
void
ngx_http_script_nop_code(ngx_http_script_engine_t *e)
{
e->ip += sizeof(uintptr_t);
}

近期评论