Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_read_token

news/2025/3/5 5:14:44/

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. 初始化

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


  1. 初始化状态变量

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

    • 获取配置文件的缓冲区 (b) 和当前文件大小 (file_size)。
    • 设置缓冲区的起始位置 (start) 和当前行号 (start_line)。
  3. 清空参数数组

    • 重置 cf->args->nelts 为 0,准备存储解析出的 token。

2. 循环部分

作用
  • 逐个字符读取配置文件内容,并根据字符类型解析出 token。
  • 管理解析过程中的状态变化,并处理文件结束和错误情况。

  1. 读取字符

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

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

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

    • 根据字符类型更新状态变量(如 quotedd_quotedsharp_comment 等)。
    • 重置标志变量(如 found),准备解析下一个 token。
  5. 文件结束处理

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

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

http://www.ppmy.cn/news/1576738.html

相关文章

7.1.2 计算机网络的分类

文章目录 分布范围交换方式 分布范围 计算机网络按照分布范围可分为局域网、广域网、城域网。局域网的范围在10m~1km&#xff0c;例如校园网&#xff0c;网速高&#xff0c;主要用于共享网络资源&#xff0c;拓扑结构简单&#xff0c;约束少。广域网的范围在100km&#xff0c;例…

Windows10 Xming6 + Xshell7 实现远程 ubuntu-24.04.1-desktop gui 界面本地展示

Windows10 Xming6 + Xshell7 实现远程 ubuntu-24.04.1-desktop gui 界面本地展示 1 运行环境2 实现思路3 XMing3.1 工具下载安装与配置3.2 XMing 配置3.3 XMing配置4 Xshell 7 配置5 远程机器配置6 测试1 运行环境 本地Windows系统:Windows10 专业版 远程Linux系统: ubuntu-…

AI本地化部署强劲驱动GPU,LPU等AI芯片和服务器的爆发性寻求

人工智能技术正在经历从云端到边缘的深刻变革&#xff0c;这一转变催生了AI基础设施建设的全新需求。在数据安全、实时响应和成本优化的多重驱动下&#xff0c;AI本地化部署已成为不可逆转的趋势&#xff0c;推动GPU、LPU等AI芯片及配套服务器系统进入爆发性增长周期。这场变革…

【leetcode hot 100 560】和为K的子数组

解法一&#xff1a;用左右指针寻找字串&#xff0c;如果和>k&#xff0c;则减少一个数&#xff08;left&#xff09;&#xff1b;如果和<k&#xff0c;则加上一个数&#xff08;right&#xff09;。 class Solution {public int subarraySum(int[] nums, int k) {int nu…

从 Transformer 到 DeepSeek-R1:大型语言模型的变革之路与前沿突破

本文参考引用&#xff1a;medium-大型语言模型简史 2025年初&#xff0c;DeepSeek开源了一款开创性且高性价比的「大型语言模型」&#xff08;Large Language Model, LLM&#xff09; — — DeepSeek-R1&#xff0c;引发了AI领域的巨大变革。 本文回顾LLM的发展历程&#xff0…

Android Studio 新版本Gradle发布本地Maven仓库示例

发布代码到JitPack示例&#xff1a;https://blog.csdn.net/loutengyuan/article/details/145938967 以下是基于 Android Studio 24.2.2&#xff08;Gradle 8.10.2 AGP 8.8.0 JDK17&#xff09; 的本地 Maven 仓库发布示例&#xff0c;包含aar和jar的不同配置&#xff1a; 1.…

【java--数据结构】顺序表

1. 线性表的概念 线性表&#xff08;Linear List&#xff09;是一种基本的数据结构&#xff0c;它是由相同类型的元素组成的有限序列。线性表中的元素具有一对一的线性关系&#xff0c;即除了第一个元素和最后一个元素外&#xff0c;每个元素都有且仅有一个直接前驱和一个直接…

Ubuntu中dpkg命令和apt命令的关系与区别

在 Ubuntu 中&#xff0c;dpkg 和 apt 是软件包管理的核心工具&#xff0c;但二者的角色和功能有显著区别&#xff1a; ​一、功能定位 ​特性​​**dpkg**​​**apt**​​层级​底层工具&#xff08;直接操作 .deb 文件&#xff09;高层工具&#xff08;管理软件仓库和依赖关…