当前位置: 首页 > news >正文

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

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


  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

相关文章:

  • 矩阵压缩存储
  • 大白话TypeScript 第十章TypeScript 学习全阶段详细总结
  • Unity TMP_InputField 多行输入时的高度适应
  • Spring生命周期都有哪些阶段
  • k8s命名空间和资源配额
  • redis 与 DB 的一致性 7 种策略
  • 软考教材重点内容 信息安全工程师 第18章 网络安全测评技术与标准
  • 【C语言】高内聚低耦合:结构体、联合体、数组、字符串、枚举和指针的综合实践
  • 显式 GC 的使用:留与去,如何选择?
  • [RN]React Native知识框架图详解
  • GPU架构分类
  • win11远程桌面连接报错(出现身份验证错误。要求的函数不受支持。可能是CredSSP 加密数据库修正)的解决办法整理
  • 左值引用与指针的区别
  • rpc学习
  • 网络安全系统分为几级_网络安全系统的分级与软考要点解析
  • 解决样式隔离的方法
  • Live2d官方项目运行
  • c++头文件和命名空间
  • 在线量化算法(QAT) --学习记录1
  • Android 常见View的防抖
  • 江山有做网站开发吗/seo常用工具
  • 重庆网站建设网络推广/北京自动网络营销推广
  • 可以做别人的网站上挂一个网页吗/app推广兼职是诈骗吗
  • 网站整站优化推广方案/指数基金有哪些
  • 建一个优化网站多少钱/在百度平台如何做营销
  • 临沂建设企业网站/全网推广