主页 > 手机  > 

Ubuntu下nginx-1.24.0源码分析-ngx_conf_read_token

Ubuntu下nginx-1.24.0源码分析-ngx_conf_read_token
ngx_conf_read_token

定义在src\core\ngx_conf_file.c

static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; off_t file_size; size_t len; ssize_t n, size; ngx_uint_t found, need_space, last_space, sharp_comment, variable; ngx_uint_t quoted, s_quoted, d_quoted, start_line; ngx_str_t *word; ngx_buf_t *b, *dump; found = 0; need_space = 0; last_space = 1; sharp_comment = 0; variable = 0; quoted = 0; s_quoted = 0; d_quoted = 0; cf->args->nelts = 0; b = cf->conf_file->buffer; dump = cf->conf_file->dump; start = b->pos; start_line = cf->conf_file->line; file_size = ngx_file_size(&cf->conf_file->file.info); for ( ;; ) { if (b->pos >= b->last) { if (cf->conf_file->file.offset >= file_size) { if (cf->args->nelts > 0 || !last_space) { if (cf->conf_file->file.fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of parameter, " "expecting \";\""); return NGX_ERROR; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, " "expecting \";\" or \"}\""); return NGX_ERROR; } return NGX_CONF_FILE_DONE; } len = b->pos - start; if (len == NGX_CONF_BUFFER) { cf->conf_file->line = start_line; if (d_quoted) { ch = '"'; } else if (s_quoted) { ch = '\''; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "too long parameter \"%*s...\" started", 10, start); return NGX_ERROR; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "too long parameter, probably " "missing terminating \"%c\" character", ch); return NGX_ERROR; } if (len) { ngx_memmove(b->start, start, len); } size = (ssize_t) (file_size - cf->conf_file->file.offset); if (size > b->end - (b->start + len)) { size = b->end - (b->start + len); } n = ngx_read_file(&cf->conf_file->file, b->start + len, size, cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } if (n != size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_read_file_n " returned " "only %z bytes instead of %z", n, size); return NGX_ERROR; } b->pos = b->start + len; b->last = b->pos + n; start = b->start; if (dump) { dump->last = ngx_cpymem(dump->last, b->pos, size); } } ch = *b->pos++; if (ch == LF) { cf->conf_file->line++; if (sharp_comment) { sharp_comment = 0; } } if (sharp_comment) { continue; } if (quoted) { quoted = 0; continue; } if (need_space) { if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { last_space = 1; need_space = 0; continue; } if (ch == ';') { return NGX_OK; } if (ch == '{') { return NGX_CONF_BLOCK_START; } if (ch == ')') { last_space = 1; need_space = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"%c\"", ch); return NGX_ERROR; } } if (last_space) { start = b->pos - 1; start_line = cf->conf_file->line; if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { continue; } switch (ch) { case ';': case '{': if (cf->args->nelts == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"%c\"", ch); return NGX_ERROR; } if (ch == '{') { return NGX_CONF_BLOCK_START; } return NGX_OK; case '}': if (cf->args->nelts != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); return NGX_ERROR; } return NGX_CONF_BLOCK_DONE; case '#': sharp_comment = 1; continue; case '\\': quoted = 1; last_space = 0; continue; case '"': start++; d_quoted = 1; last_space = 0; continue; case '\'': start++; s_quoted = 1; last_space = 0; continue; case '$': variable = 1; last_space = 0; continue; default: last_space = 0; } } else { if (ch == '{' && variable) { continue; } variable = 0; if (ch == '\\') { quoted = 1; continue; } if (ch == '$') { variable = 1; continue; } if (d_quoted) { if (ch == '"') { d_quoted = 0; need_space = 1; found = 1; } } else if (s_quoted) { if (ch == '\'') { s_quoted = 0; need_space = 1; found = 1; } } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF || ch == ';' || ch == '{') { last_space = 1; found = 1; } if (found) { word = ngx_array_push(cf->args); if (word == NULL) { return NGX_ERROR; } word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1); if (word->data == NULL) { return NGX_ERROR; } for (dst = word->data, src = start, len = 0; src < b->pos - 1; len++) { if (*src == '\\') { switch (src[1]) { case '"': case '\'': case '\\': src++; break; case 't': *dst++ = '\t'; src += 2; continue; case 'r': *dst++ = '\r'; src += 2; continue; case 'n': *dst++ = '\n'; src += 2; continue; } } *dst++ = *src++; } *dst = '\0'; word->len = len; if (ch == ';') { return NGX_OK; } if (ch == '{') { return NGX_CONF_BLOCK_START; } found = 0; } } } }

ngx_conf_read_token 是 Nginx 配置解析的核心函数,负责从配置文件中读取并解析下一个 token(如指令、参数、块等)。


函数签名 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); 返回类型:ngx_int_t 类型:Nginx 自定义的整型状态码。含义: NGX_OK:成功解析一个完整的指令(以 ; 结尾)。NGX_CONF_BLOCK_START:遇到 {,表示进入一个新的配置块。NGX_CONF_BLOCK_DONE:遇到 },表示当前配置块结束。NGX_CONF_FILE_DONE:配置文件解析完毕。NGX_ERROR:解析过程中发生错误(如语法错误、未闭合的引号等)。 参数:ngx_conf_t *cf 类型:指向 ngx_conf_t 结构体的指针,包含配置解析的上下文信息。关键字段: conf_file:指向当前解析的配置文件对象(类型为 ngx_conf_file_t),包含文件句柄、缓冲区、行号等。args:动态数组(ngx_array_t),用于存储当前解析出的参数(token)。pool:内存池,用于分配参数存储空间。
详解

详解(1)

详解(2)

详解(3)


主要逻辑
1. 初始化

初始化函数运行所需的各种状态变量和上下文。 准备配置文件的缓冲区,并设置初始状态。


初始化状态变量:

设置标志变量,例如: found:是否找到一个完整的 token。need_space:是否需要空格来分隔 token。last_space:上一个字符是否是空格。sharp_comment:是否在注释中(以 # 开头)。quoted:是否遇到转义字符(\)。d_quoted 和 s_quoted:是否在双引号或单引号字符串中。variable:是否在解析变量(以 $ 开头)。 这些变量用于管理解析过程中的上下文。

初始化缓冲区:

获取配置文件的缓冲区 (b) 和当前文件大小 (file_size)。设置缓冲区的起始位置 (start) 和当前行号 (start_line)。

清空参数数组:

重置 cf->args->nelts 为 0,准备存储解析出的 token。
2. 循环部分 作用: 逐个字符读取配置文件内容,并根据字符类型解析出 token。管理解析过程中的状态变化,并处理文件结束和错误情况。

读取字符:

从缓冲区中逐个字符读取配置文件内容。如果缓冲区的内容已经读取完毕,则从文件中读取更多数据到缓冲区。

字符处理:

根据当前字符的类型,执行不同的逻辑: 处理换行符 (LF)、注释 (#)、转义字符 (\)、引号 (" 和 ')、变量符号 ($) 等。处理分隔符(如空格、制表符、回车、换行)以及特殊字符(如分号 ;、大括号 { 和 })。

提取 token:

当遇到分隔符或特殊字符时,提取完整的 token 并存入 cf->args 数组。处理转义字符(例如 \t、\n、\r 等)。

状态管理:

根据字符类型更新状态变量(如 quoted、d_quoted、sharp_comment 等)。重置标志变量(如 found),准备解析下一个 token。

文件结束处理:

如果文件已经读取完毕,检查是否有未结束的 token。如果有未结束的 token,报错并返回 NGX_ERROR。如果没有未结束的 token,返回 NGX_CONF_FILE_DONE。

错误处理:

在解析过程中,如果遇到不合法的字符或语法错误(例如未闭合的引号、过长的 token 等),记录错误日志并返回 NGX_ERROR。
标签:

Ubuntu下nginx-1.24.0源码分析-ngx_conf_read_token由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Ubuntu下nginx-1.24.0源码分析-ngx_conf_read_token