ngx_conf_parse函数

本文深入探讨了nginx配置文件的解析过程,包括简单和复杂配置的区别,以及配置文件解析函数的工作原理。详细解释了如何通过配置文件解析函数解析配置文件,包括配置项的类型、处理方式和解析流程,帮助开发者更好地理解和使用nginx配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里要先看一下配置文件格式:

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on; 
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }   
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

极其简单的配置文件格式:key-value.

具体把文件格式分为两类:简单和复杂配置.

简单配置:没有大括号的配置如:worker_processes  1;

复杂配置:含有大括号的配置:

events {

    worker_connections  1024;

}

 

我们再看一下解析配置文件的函数:

staticngx_command_t  ngx_http_core_commands[] ={
 
    {
         //配置项的key,用于定位处理配置的command函数
        ngx_string("variables_hash_max_size"),
        //配置类型
      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
        //配置的解析函数
      ngx_conf_set_num_slot,
      NGX_HTTP_MAIN_CONF_OFFSET,
      offsetof(ngx_http_core_main_conf_t,variables_hash_max_size),
      NULL },
    ………………………………………………….
      ngx_null_command
};

 

个人理解:

        通过配置文件解析函数ngx_conf_read_token,buf里面的token解析出来.其实在解析过程中,所有以空格间隔的字符串都被看作token,存储在cf->argc.通过分号,左括号,来区分一组token.在一组token,以第一个tokenkey-value对中的key,(重点来了)根据第一个token来对所有模块的command进行扫描,如果匹配,则根据其定义的配置解析函数来处理.

例如:ngx_string("variables_hash_max_size"), 就是key,而以他为首的token组就是value(出去第一个token).

 

在ngx_conf_parse函数中,有这么一段代码:

if(cf->handler) {

    ………………

     rv =(*cf->handler)(cf, NULL, cf->handler_conf);

    ……………

}

该代码含义是,如果定义了cf->handler函数,就先执行该函数,那么该函数的作用是什么呢?我们先来查询一下该函数在哪里赋值:


并且每个函数调用以后紧跟着就会调用ngx_conf_parse函数.例如:


我们注意到,这些模块的配置项的类型都是不定配置项,即一个key可能对应一个以上的value,(例如:text/html html thm shtml;)所以为此,nginx专门为他们准备了一个回调函数处理此种类型.

 

ngx_conf_read_token:把配置文件中的token解析出来,放入cf-args.

ngx_conf_handler:处理配置文件中的key对应多对value的情况.

 ngx_conf_handler(cf, rc):cf-args中的数据存入对应的ngx变量中.

注意一点:ngx_conf_handler函数还可能递归调用ngx_conf_parse,用于解析复杂配置项.

 

//用于标记当前解析的状态.

enum {

        parse_file = 0,

        parse_block,

        parse_param

    } type;

 

parse_file: 正要开始解析一个配置文件.

状态:配置文件已经打开,文件将要被解析.用于新打开一个配置文件,或者解析过程中遇到include指令时候,也将以这种状态调用ngx_conf_parse函数.

parse_block:正要解析一个复杂配置项的值.

状态:配置文件已经打开,且已经进行了部分解析.

parse_param:即将对命令行参数进行解析.

状态:在命令行中遇到-g参数,即处在这种状态.

好了具体函数一看就会明白

char *
ngx_conf_parse(ngx_conf_t*cf, ngx_str_t *filename)
{
    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf;
    ngx_conf_file_t  *prev, conf_file;
  
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;
 
#if(NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif
 
    if (filename) {
 
        /* open configuration file */
 
        fd = ngx_open_file(filename->data,NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG,cf, ngx_errno,
                               ngx_open_file_n" \"%s\" failed",
                              filename->data);
            return NGX_CONF_ERROR;
        }
 
        prev = cf->conf_file;
 
        cf->conf_file = &conf_file;
 
        if (ngx_fd_info(fd,&cf->conf_file->file.info) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG,cf->log, ngx_errno,
                          ngx_fd_info_n "\"%s\" failed", filename->data);
        }
 
        cf->conf_file->buffer = &buf;
 
        buf.start = ngx_alloc(NGX_CONF_BUFFER,cf->log);
        if (buf.start == NULL) {
            goto failed;
        }
 
        buf.pos = buf.start;
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;
        buf.temporary = 1;
 
        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len =filename->len;
        cf->conf_file->file.name.data =filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log =cf->log;
        cf->conf_file->line = 1;
 
        type = parse_file;
 
    } else if (cf->conf_file->file.fd !=NGX_INVALID_FILE) {
 
        type = parse_block;
 
    } else {
        type = parse_param;
    }
 
 
    for ( ;; ) {
        rc = ngx_conf_read_token(cf);
 
        /*
         * ngx_conf_read_token() may return
         *
         *   NGX_ERROR             there iserror
         *   NGX_OK                the tokenterminated by ";" was found
         *   NGX_CONF_BLOCK_START  the tokenterminated by "{" was found
         *   NGX_CONF_BLOCK_DONE   the"}" was found
         *   NGX_CONF_FILE_DONE    theconfiguration file is done
         */
 
        if (rc == NGX_ERROR) {
            goto done;
        }
 
        if (rc == NGX_CONF_BLOCK_DONE) {
 
            if (type != parse_block) {
               ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected\"}\"");
                goto failed;
            }
 
            goto done;
        }
 
        if (rc == NGX_CONF_FILE_DONE) {
 
            if (type == parse_block) {
               ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                  "unexpected end of file, expecting \"}\"");
                goto failed;
            }
 
            goto done;
        }
 
        if (rc == NGX_CONF_BLOCK_START) {
 
            if (type == parse_param) {
               ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "blockdirectives are not supported "
                                   "in -goption");
                goto failed;
            }
        }
 
        /* rc == NGX_OK || rc ==NGX_CONF_BLOCK_START */
      if (cf->handler) {
 
            /*
             * the custom handler, i.e., thatis used in the http's
             * "types { ... }"directive
             */
 
            rv = (*cf->handler)(cf, NULL,cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }
 
            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }
 
            ngx_conf_log_error(NGX_LOG_EMERG,cf, 0, rv);
 
            goto failed;
        }
 
 
        rc = ngx_conf_handler(cf, rc);
 
        if (rc == NGX_ERROR) {
            goto failed;
        }
    }
 
failed:
 
    rc = NGX_ERROR;
 
done:
 
    if (filename) {
        if(cf->conf_file->buffer->start) {
           ngx_free(cf->conf_file->buffer->start);
        }
 
        if (ngx_close_file(fd) ==NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT,cf->log, ngx_errno,
                          ngx_close_file_n" %s failed",
                          filename->data);
            return NGX_CONF_ERROR;
        }
 
        cf->conf_file = prev;
    }
 
    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }
 
    return NGX_CONF_OK;
}
/opt/nginx-sticky-module-ng-master/ngx_http_sticky_module.c: 在函数ngx_http_sticky_header_filter’中: /opt/nginx-sticky-module-ng-master/ngx_http_sticky_module.c:475:63: 错误:‘ngx_http_upstream_headers_in_t’没有名为‘cookies’的成员 if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, &ctx->sticky_conf->cookie_name, &transfer_cookie) == NGX_DECLINED) ^ /opt/nginx-sticky-module-ng-master/ngx_http_sticky_module.c:475:3: 错误:传递‘ngx_http_parse_set_cookie_lines’的第 2 个参数时在不兼容的指针类型间转换 [-Werror] if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, &ctx->sticky_conf->cookie_name, &transfer_cookie) == NGX_DECLINED) ^ In file included from /opt/nginx-sticky-module-ng-master/ngx_http_sticky_module.c:9:0: src/http/ngx_http.h:113:18: 附注:需要类型‘struct ngx_table_elt_t *’,但实参的类型为‘struct ngx_str_t *’ ngx_table_elt_t *ngx_http_parse_set_cookie_lines(ngx_http_request_t *r, ^ /opt/nginx-sticky-module-ng-master/ngx_http_sticky_module.c:475:3: 错误:提供给函数ngx_http_parse_set_cookie_lines’的实参太少 if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, &ctx->sticky_conf->cookie_name, &transfer_cookie) == NGX_DECLINED) ^ In file included from /opt/nginx-sticky-module-ng-master/ngx_http_sticky_module.c:9:0: src/http/ngx_http.h:113:18: 附注:在此声明 ngx_table_elt_t *ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
最新发布
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值