char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { int m, rc, found, valid; char *rv; void *conf, **confp; ngx_fd_t fd; ngx_str_t *name; ngx_conf_file_t *prev; ngx_command_t *cmd; #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); if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_open_file_n " %s failed", filename->data); return NGX_CONF_ERROR; } prev = cf->conf_file; if (!(cf->conf_file = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t)))) { return NGX_CONF_ERROR; } if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " %s failed", filename->data); } if (!(cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, 1024))) { return NGX_CONF_ERROR; } 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; } for ( ;; ) { rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() returns NGX_OK, NGX_ERROR, * NGX_CONF_FILE_DONE or NGX_CONF_BLOCK_DONE */ #if 0 ngx_log_debug(cf->log, "token %d" _ rc); #endif if (rc == NGX_ERROR) { break; } if (rc != NGX_OK) { break; } if (cf->handler) { /* custom handler, i.e. used in http "types { ... }" directive */ rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; } else if (rv == NGX_CONF_ERROR) { rc = NGX_ERROR; break; } else { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%s in %s:%d", rv, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } } name = (ngx_str_t *) cf->args->elts; found = 0; for (m = 0; rc != NGX_ERROR && !found && ngx_modules[m]; m++) { /* look up the directive in the appropriate modules */ if (ngx_modules[m]->type != NGX_CONF_MODULE && ngx_modules[m]->type != cf->module_type) { continue; } cmd = ngx_modules[m]->commands; if (cmd == NULL) { continue; } while (cmd->name.len) { if (name->len == cmd->name.len && ngx_strcmp(name->data, cmd->name.data) == 0) { found = 1; #if 0 ngx_log_debug(cf->log, "command '%s'" _ cmd->name.data); #endif /* is the directive's location right ? */ if ((cmd->type & cf->cmd_type) == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "directive \"%s\" in %s:%d " "is not allowed here", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } /* is the directive's argument count right ? */ if (cmd->type & NGX_CONF_ANY) { valid = 1; } else if (cmd->type & NGX_CONF_FLAG) { if (cf->args->nelts == 2) { valid = 1; } else { valid = 0; } } else if (cmd->type & NGX_CONF_1MORE) { if (cf->args->nelts > 1) { valid = 1; } else { valid = 0; } } else if (cmd->type & NGX_CONF_2MORE) { if (cf->args->nelts > 2) { valid = 1; } else { valid = 0; } } else if (cf->args->nelts <= 10 && (cmd->type & argument_number[cf->args->nelts - 1])) { valid = 1; } else { valid = 0; } if (!valid) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid number arguments in " "directive \"%s\" in %s:%d", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } /* set up the directive's configuration context */ conf = NULL; if (cmd->type & NGX_DIRECT_CONF) { conf = ((void **) cf->ctx)[ngx_modules[m]->index]; } else if (cmd->type & NGX_MAIN_CONF) { conf = &(((void **) cf->ctx)[ngx_modules[m]->index]); } else if (cf->ctx) { confp = *(void **) ((char *) cf->ctx + cmd->conf); if (confp) { conf = confp[ngx_modules[m]->ctx_index]; } } rv = cmd->set(cf, cmd, conf); #if 0 ngx_log_debug(cf->log, "rv: %d" _ rv); #endif if (rv == NGX_CONF_OK) { break; } else if (rv == NGX_CONF_ERROR) { rc = NGX_ERROR; break; } else { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "the \"%s\" directive %s in %s:%d", name->data, rv, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } } cmd++; } } if (!found) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "unknown directive \"%s\" in %s:%d", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } if (rc == NGX_ERROR) { break; } } if (filename) { cf->conf_file = prev; if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", cf->conf_file->file.name.data); return NGX_CONF_ERROR; } } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
//解析filename中的配置项 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; } //令cf->conf_file指向临时的conf_file结构体 prev = cf->conf_file; cf->conf_file = &conf_file; //获取配置文件的inode信息 if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } //我们将文件读取到cf->conf_file->buffer中 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; //这是一个临时buf 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 ( ;; ) { //读取配置文件并解析, 每次返回NGX_OK,说明已经解析到一条配置项, //我们会调用响应的回调函数进行处理 rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration 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, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ //在解析到配置项以后,如果自定义了handler函数则调用handler函数, //否则调用默认的set方法设置参数 if (cf->handler) { /* * the custom handler, i.e., that is 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; } //调用cf->set方法设置配置项,一次只能设置一个配置项,当出现子模块时 //set方法会递归解析子模块,并进行配置 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; }
/* * 解析配置文件 */ 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); //默认4K的缓冲区 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 is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration 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, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ if (rc == NGX_CONF_BLOCK_START) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\""); goto failed; } 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); rc = NGX_ERROR; } cf->conf_file = prev; } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
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 *b; ngx_uint_t block; ngx_conf_file_t *prev; #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 = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t)); if (cf->conf_file == NULL) { return NGX_CONF_ERROR; } if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } b = ngx_calloc_buf(cf->pool); if (b == NULL) { return NGX_CONF_ERROR; } cf->conf_file->buffer = b; b->start = ngx_alloc(ngx_pagesize, cf->log); if (b->start == NULL) { return NGX_CONF_ERROR; } b->pos = b->start; b->last = b->start; b->end = b->last + ngx_pagesize; b->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; block = 0; } else { block = 1; } for ( ;; ) { rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { goto done; } if (rc == NGX_CONF_BLOCK_DONE) { if (!block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } block = 0; } if (rc == NGX_CONF_FILE_DONE && block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting \"}\""); goto failed; } if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) { goto done; } if (cf->handler) { /* * the custom handler, i.e., that is 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) { ngx_free(cf->conf_file->buffer->start); cf->conf_file = prev; if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", cf->conf_file->file.name.data); return NGX_CONF_ERROR; } } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { //第二个数为保存的配置文件路径的字符串,如/usr/local/nginx/conf/nginx.conf_file 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) { //指向一个配置文件路径字符串,需要函数ngx_conf_parse打开该文件并获取相关的文件信息 /* 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) == -1) { 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; //4K,到末尾 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; //刚刚打开的新文件,包括include指令 } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { //说明此时仅解析了部分解析,当遇到复杂配置项,比如events,http等,此时解析的内容还是来自当前文件 type = parse_block; } else { //正要开始解析命令行参数配置项值,在对用户通过命令行-g参数输入的配置信息进行解析,如nginx -g 'daemon on' type = parse_param; } for ( ;; ) { rc = ngx_conf_read_token(cf); //读取token,每次读取一个buffer /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration 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, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ if (cf->handler) { //进行这些token转换为Nginx内控制变量的值,针对“text/html html htm shtml”等这样的配置项或geo模块里的“192.168.0.0/16 local”这样的不定配置项,进行特殊的处理 /* * the custom handler, i.e., that is 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; }
//这个函数的详细解析 //请参看:http://www.pagefault.info/?p=188 nginx的启动流程分析(一) // http://www.pagefault.info/?p=368 //第二个参数可以为空的,如果为空,则说明将要解析的是block中的内容或者param 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); // NGX_INVALID_FILE 为宏定义,值为-1 ,定义在/os/unix/ngx_files.h 中 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; // 获取配置文件的stat信息,并存储到cf->conf_file->file.info这个stat结构体中 // ngx_fd_info 这个函数是fstat这个函数的宏包装。参考./os/unix/ngx_files.h if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } cf->conf_file->buffer = &buf; // 申请一个NGX_CONF_BUFFER大小的buffer,用于 ngx_conf_read_token() 函数解析配置文件 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 ( ;; ) { //读入一个token,一般是一行 //读到的配置参数放到: (ngx_str_t*)(*((*cf).args)).elts rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration 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, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ //判断cf是否有handler回调,如果有的话,优先调用handler回调,如果没有,则会进入ngx_conf_handler进行一般处理 //特别说一下,http的模块使用handler是ngx_http_block,具体请看ngx_http.c if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ //使用handler处理 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; } //否则进入一般处理, 调用ngx_conf_handler对当前的token进行处理 // 参数中的rc 为ngx_read_conf_token的返回值 rc = ngx_conf_handler(cf, rc); if (rc == NGX_ERROR) { goto failed; } } //end for failed: rc = NGX_ERROR; done: //恢复现存、关闭已经打开的文件 //NGX_CONF_FILE_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; } // NGX_ERROR NGX_CONF_FILE_DONE NGX_CONF_BLOCK_DONE 时都需要处理的部分 if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; u_char *p; off_t size; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t buf, *tbuf; ngx_conf_file_t *prev, conf_file; ngx_conf_dump_t *cd; 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; if (ngx_dump_config #if (NGX_DEBUG) || 1 #endif ) { p = ngx_pstrdup(cf->cycle->pool, filename); if (p == NULL) { goto failed; } size = ngx_file_size(&cf->conf_file->file.info); tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size); if (tbuf == NULL) { goto failed; } cd = ngx_array_push(&cf->cycle->config_dump); if (cd == NULL) { goto failed; } cd->name.len = filename->len; cd->name.data = p; cd->buffer = tbuf; cf->conf_file->dump = tbuf; } else { cf->conf_file->dump = NULL; } } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; } else { type = parse_param; } /*这里解析指令的方式是"读取一条、检查一条、解析一条"的方式解析配置文件,这里的一条是以分号或者花括号"{"、"}"为单位,如果遇到嵌套的花括号,则先处理嵌套的指令*/ for ( ;; ) { /*将配置文件中当前的一条配置指令读取到内存中,判断配置语法是否使用正确,并将该指令保存到cycle->args数组中*/ rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration 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, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ /*如果该指令定义了自定义处理函数,则调用自定义处理函数进行解析*/ if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ if (rc == NGX_CONF_BLOCK_START) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\""); goto failed; } 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); rc = NGX_ERROR; } cf->conf_file = prev; } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; u_char *p; off_t size; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t buf, *tbuf; ngx_conf_file_t *prev, conf_file; ngx_conf_dump_t *cd; enum { parse_file = 0, //解析配置文件(初始配置文件解析) parse_block, //解析配置文件中的块 parse_param //解析-g选项携带的参数 } type; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; prev = NULL; #endif if (filename) { /* open configuration file */ /*打开配置文件nginx.conf*/ 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; } /*保存之前的cf->conf_file*/ prev = cf->conf_file; cf->conf_file = &conf_file; /*获取文件信息,如uid gid等*/ 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); } /* * 函数ngx_conf_read_token对配置文件内容逐个字符扫描并解析为单个的token,当然,该函数并不会频繁的去读取 * 配置文件,它每次从文件内读取足够多的内容以填满一个大小为NGX_CONF_BUFFER的缓存区(除了最后一次,即配置 * 文件剩余内容本来就不够了),这个缓存区在函数 ngx_conf_parse内申请并保存引用到变量cf->conf_file->buffer内, * 函数 ngx_conf_read_token反复使用该缓存区 */ /*构建cf->conf_file->buffer缓冲区*/ 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指向当前配置文件/usr/local/nginx/conf/nginx.conf*/ 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; /*复制一份配置文件*/ if (ngx_dump_config #if (NGX_DEBUG) || 1 #endif ) { p = ngx_pstrdup(cf->cycle->pool, filename); if (p == NULL) { goto failed; } size = ngx_file_size(&cf->conf_file->file.info); tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size); if (tbuf == NULL) { goto failed; } cd = ngx_array_push(&cf->cycle->config_dump); if (cd == NULL) { goto failed; } cd->name.len = filename->len; cd->name.data = p; cd->buffer = tbuf; cf->conf_file->dump = tbuf; } else { cf->conf_file->dump = NULL; } } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; } else { type = parse_param; } for ( ;; ) { /* * 读取文件中的内容放到缓冲区中cf->conf_file->buffer,并进行解析,把解析的结果放到了cf->args 里面, 指令的每个单词都在数组中 * 占一个位置,比如 set debug off ,那么数组中存三个位置。 */ rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { goto done; } /*NGX_CONF_BLOCK_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, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ if (rc == NGX_CONF_BLOCK_START) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\""); goto failed; } 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); rc = NGX_ERROR; } cf->conf_file = prev; } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }