首页 > Nginx > Nginx 脚本引擎解析源码注释

Nginx 脚本引擎解析源码注释

2013年5月13日 发表评论 阅读评论 3230次阅读    

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

Share
分类: Nginx 标签: ,
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.

注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。