nginx 변수 다시 이야기 하기 (1)

11905 단어
여 기 는 ngxhttp_script_copile 을 단서 로 nginx 의 변수 원리 중 또 어떤 발굴 할 만 한 부분 이 있 는 지 살 펴 보 자.
ngx_http_script_copile 함수 가 호출 되 었 습 니 다. 일반적으로 변 수 를 처리 하 는 데 사 용 됩 니 다. 특히 설정 처리 단계 에서 변수 가 나타 날 때 (즉 "$" 로 시작 하 는 설정) 보통 이 함수 로 처리 합 니 다. 이른바 "실행 시 프로세서" 를 생 성 합 니 다."함수 의 시작 에 ngx http script init arrays 함수 가 있 습 니 다. 말 그대로 우리 도 그 역할 을 대체적으로 알 수 있 습 니 다. 여 기 는 잠시 두 었 다가 나중에 토론 하 겠 습 니 다."
핵심 적 인 처 리 는 for 순환 에 있 습 니 다. 그 중에서 sc 는 우리 가 필요 로 하 는 대부분의 정 보 를 포함 하고 있 습 니 다. 그러면 이 sc 는 도대체 어떤 내력 입 니까? 우 리 는 proxy pass 를 예 로 들 면:
ngx_http_proxy_pass:
...
/* n  proxy_pass          ,          */
if (n) {

        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = url; // url  proxy_pass        ,    
        /* 
         *         ,nginx  ”      “                
         *     ,    ,                  (       ),  
         *    lengths values 。
         */
        sc.lengths = &plcf->proxy_lengths;
        sc.values = &plcf->proxy_values;
        sc.variables = n;

        /*          compile     , lengths values           , NULL  。
         *      :       ,   lengths values   ,  NULL,            */
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }

        return NGX_CONF_OK;
    }

다음은 ngx http script copile 의 핵심 처리 부분 을 보 겠 습 니 다.
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') {

                n = sc->source->data[i] - '0';

                if (sc->captures_mask & (1 << n)) {
                    sc->dup_capture = 1;
                }
                /*
                 *  sc->captures_mask         1,  captures_mask      ?
                 *     sc         。
                 */
                sc->captures_mask |= 1 << n;
                if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
                    return NGX_ERROR;
                }

                i++;

                continue;
            }
            }
#endif
            
            /*
             *           ,    ,          proxy_pass $host$uritest,
             *          nginx       ,host uri,    $uritest  ,    
             *     ,           uritest          ,          。
             *      ?nginx    "{}"          ,             ,   
             *        ${uri}test,         ,                    
             *          。
             */
            if (sc->source->data[i] == '{') {
                bracket = 1;

                if (++i == sc->source->len) {
                    goto invalid_variable;
                }
                // name            
                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];
                
                //  "{}"           ( break  ),             
                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++;
            //       ,   
            if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
                return NGX_ERROR;
            }

            continue;
        }
        
        /* 
         *                 ,         ,         ,      ”     “
         *               ,    。                     ,    '?'   
         *        ngx_http_script_add_args_code   。
         */
        if (sc->source->data[i] == '?' && sc->compile_args) {
            sc->args = 1;
            sc->compile_args = 0;

            if (ngx_http_script_add_args_code(sc) != NGX_OK) {
                return NGX_ERROR;
            }

            i++;

            continue;
        }
        
        //   name       ”     “
        name.data = &sc->source->data[i];

        //         
        while (i < sc->source->len) {

            //   '$'           
            if (sc->source->data[i] == '$') {
                break;
            }
            /*
             *                        '?',                   ,
             *  sc->compile_args = 0,                     。  ,         
             *  '?' ,  ,     。*/
            if (sc->source->data[i] == '?') {

                sc->args = 1;

                if (sc->compile_args) {
                    break;
                }
            }

            i++;
            name.len++;
        }
        
        //            ,sc->size       ( sc->source) ,         
        sc->size += name.len;

        //                  
        if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
            != NGX_OK)
        {
            return NGX_ERROR;
        }
    }
    
    //   compile  ,         。
    return ngx_http_script_done(sc);

위 에서 우 리 는 copile 과정의 주요 작업 을 분 석 했 습 니 다. 분명 세부 사항 은 논의 되 지 않 았 습 니 다. copile 과정 에서 모두 4 가지 유형 을 처리 해 야 합 니 다. $1 과 같은 capture 변수, 일반적인 변수 ($uri), args 변수, 상수 (즉 상수 문자열)사실 이러한 변수의 처리 과정 은 전체적으로 그다지 번 거 로 운 것 이 아니 라 세부 적 인 부분 은 확실히 어 려 운 것 입 니 다. 우 리 는 여기 서 정리 한 결과, 이전의 블 로 그 는 변수 와 스 크 립 트 엔진 체제 에 대해 연 구 를 한 적 이 있 습 니 다. 여기 서 이야기 한 난점 과 세부 사항 을 구입 하거나, 이전에 잘 알 지 못 했 던 분석 을 다시 한 번 검토 해 보 겠 습 니 다. 당신 과 내 가 모두 얻 을 수 있 기 를 바 랍 니 다.
절차 에 대해 일반적으로 gdb 와 함께 debug 로 그 를 맞 추 면 대체적으로 정리 할 수 있 습 니 다. 어 려 운 점 은 바로 일부 구조 중의 구성원 에 있 습 니 다. 특히 일부 태그 비트 의 사용 은 전체 시스템 을 관통 시 키 는 것 입 니 다. 이해 에 있어 많은 어려움 이 있 습 니 다. 이것 은 우리 가 여기 서 토론 하 는 중심 입 니 다. 이런 부분 에 대해 알 게 되면 절 차 는 큰 문제 가 아 닙 니 다.
먼저 ngx http script copile t 구 조 를 보 세 요. 이 구 조 는 copile 에서 사 용 된 적 이 있 습 니 다.
typedef struct {
    ngx_conf_t                 *cf;             //     
    ngx_str_t                  *source;         //   compile    
    
    /*
     *             index,        ,     
     */
    ngx_array_t               **flushes;
    ngx_array_t               **lengths;         //             
    ngx_array_t               **values;          //             

    ngx_uint_t                  variables;       //        ,      (args  ,$n         )

    /* 
     *             ,    pcre       ,           
     */
    ngx_uint_t                  ncaptures;      //      ,   $n      ,       $3,  ncaptures   3

    /*
     *         $1,$2...$9   ,       1   ,       dup_capture  ,
     *       mask   ,             $n  。
     */
    ngx_uint_t                  captures_mask;  

    /*
     *         rewrite     , ngx_http_rewrite ,
     * if (sc.variables == 0 && !sc.dup_capture) {
     *     regex->lengths = NULL;
     * }
     *      $n,  regex->lengths   NULL,       ,   
     * ngx_http_script_regex_start_code      regex->lengths   ,       ,
     *         $n   ,         captures     $n,       ,
     *   pcre     captures          ,       handler   。
     */
    unsigned                    dup_capture:1;

    ngx_uint_t                  size;           //  compile     ,”     “    
    
    /* 
     *   main    ,         。main        
     * ngx_http_script_regex_code_t   ,    main          ?
     *          。
     */
    void                       *main;

    unsigned                    compile_args:1;       //           
    unsigned                    complete_lengths:1;   //     lengths      , NULL
    unsigned                    complete_values:1;    //     values      
    unsigned                    zero:1;               // values     ,          '\0'  
    unsigned                    conf_prefix:1;        //           ,      
    unsigned                    root_prefix:1;        //  conf_prefix

    unsigned                    args:1;               //  compile          '?'
} ngx_http_script_compile_t;

함수 ngx http script add var code 에 서 는 ngx http core main conf t (뒤에 cmcf 로 대체) 의 variables, 즉 전역 변수 배열 을 사 용 했 습 니 다.
cmcf 이기 때문에 모든 server 블록, location 블록, upstream 블록 을 포함 하여 모두 볼 수 있 습 니 다. 즉, 한 측 이 수정 하면 다른 곳 에서 변화 하 는 이 치 를 나 타 낼 수 있 습 니 다.
각 모듈 의 preconfiguration 함수 에 서 는 이 모듈 이 미리 설정 한 전역 변 수 를 cmcf - > variables keys 에 넣 습 니 다. 또 다른 중요 한 구성원 은?
cmcf - > variables, 앞에서 언급 한 cmcf - > variables keys 는 모든 미리 설 정 된 변수 (set 명령 을 통 해 설 정 된 것) 입 니 다.한편, cmcf - > variables 는 설정 에 실제 사용 되 는 변수 입 니 다. cmcf - > variables 에 있 는 변 수 는 실제 적 으로 하나의 위 치 를 차지 합 니 다. 이 변수의 더 많은 정 보 는 cmcf - > variables keys 에서 유래 되 었 기 때문에 설정 분석 이 끝 난 후에 ngx http variables init vars 함 수 를 통 해 이 변수의 중요 한 정 보 를 채 웁 니 다.
r 에 도 variables 멤버 가 있 습 니 다. 이것 은 배열 이 고 배열 구성원 의 개 수 는 cmcf - > variabels 와 같 습 니 다. cmcf - > variabels 의 멤버 유형 은 다음 과 같 습 니 다.
struct ngx_http_variable_s {
    ngx_str_t                     name;        /*         */
   
    ngx_http_set_variable_pt      set_handler; /*          request        */
    ngx_http_get_variable_pt      get_handler; /*   request   ( uri,args )     ,r->variables         */
    uintptr_t                     data;        /*  set get     ,   r      request    offset */
    ngx_uint_t                    flags;       /*    set get          ,      */
    ngx_uint_t                    index;       /*      r->variabels  cmcf->variabels        */
};

r - > variables 의 멤버 유형 은:
typedef struct {
    unsigned    len:28;               /*        */

    unsigned    valid:1;              /*        */
    unsigned    no_cacheable:1;       /*          ,    ,              ,       ,                   
                                       *    ,        no_cacheable   ,           ,    get_handler  
                                       *    ,     
                                       */
    unsigned    not_found:1;          /*       ,              get        */
    unsigned    escape:1;             /*             */

    u_char     *data;                 /*     */
} ngx_variable_value_t;

이 두 구조의 관 계 는 매우 밀접 하 다. 하 나 는 변수, 하 나 는 변수 값 이다. 그래서 nginx 는 변수 에 설 치 된 이 처리 체 제 는 예 정 된 방정식, 유사 한 연산 과정 처럼 서로 다른 변수 값 으로 운행 하여 우리 가 원 하 는 서로 다른 결 과 를 얻 을 수 있다.

좋은 웹페이지 즐겨찾기