nginx框架---配置项内容读取ngx_conf_read_token函数

该函数的就是纯粹的读取内容出来,在源码中有这样的注释

        /*
         * 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
         */

每次在读取到上诉中的特殊符号都会返回,一开始会很迷惑,返回这玩意有啥用,那配置项那些内容怎么读到内存中来?
其实内容存储在cf->args中,也就是ngx_conf_read_token的入参结构体cf;

下面给出2张图,上面的是nginx.conf的内容,下面是第一张图的字符打印(gdb调试输出的内容),这样更方便阅读源码时比对
在这里插入图片描述
在这里插入图片描述
要理解该函数也不难,该函数主体是个for循环,大概分为这几步

  • 遍历字符前,都会检查buffer内容是否已经遍历完,遍历完就需要从文件读新的内容进来
  • 开始遍历字符,更新标志位及指针位置
  • 拷贝数据到cf->args

需要特意几个指针 ngx_buf_t *b的b->pos指针、b->start和函数局部变量的start指针

  • b->start在每次从文件内读取新的内容时会更新b->start
  • start在是在配置项的名字或内容读完时更新
  • b->pos每次遍历都会pos++

当found 为1时才会进行数据拷贝,当found 为1 且遇到";“和”{"才会返回,严谨点的话这里不应该叫数据拷贝,因为他是一个一个字符赋值的

	if (ch == ';') 
	{
    
    
        return NGX_OK;
    }
    if (ch == '{') 
	{
    
    
        return NGX_CONF_BLOCK_START;
    }

当遇到了";“代表一个配置项的名字和值都读取到了,可以返回去处理了,这是返回NGX_OK
在这里插入图片描述
遇到了”{“,那么”{“之前的模块名字也读取到了,也可以返回去处理了,返回NGX_CONF_BLOCK_START
在这里插入图片描述
那么NGX_CONF_BLOCK_DONE 和 NGX_CONF_FILE_DONE的返回呢?之前说了只有found为1时才会从文件读取内容赋值到cf->args中,那么当这2个宏定义返回时,cf->args是没有内容的,那他处理什么?顾名思义,2个宏定义一个是块结束,一个是文件结束,文件结束好理解,因为整个文件内容已经处理完了,不需要额外的内容了,而块结束符确实也没有额外的更多内容处理了,因为在这个符号”}“之前一定是有符号”;“,而这个”;“会返回NGX_OK去处理内容,”}"只是纯粹的结束这个块

这是之前参考过的博客
ngx_conf_read_token
这是自己阅读源码时根据自己的理解写的一些注释,

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;//大小 NGX_CONF_BUFFER 4096
    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 ( ;; ) {
    
    
        //pos 为当前遍历的位置,
        //last为有内容的末尾位置
        //当遍历超过时,应该从文件继续读取内容到buff
        //同时更新b->pos b->last
        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);
            //buff中未使用的空间 与文件剩余大小,取小值作为size大小
            if (size > b->end - (b->start + len)) {
    
    
                size = b->end - (b->start + len);
            }
            //从文件offset个偏移字节开始读取size字节内容放入b中
            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++;
        //遇到换行,才将sharp_comment置为0
        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记录每个字段的起始位置,方便拷贝数据到cf->args中
            //到查找到有效字符时,类似worker_processes,
            //当ch == 'w'时,由于指针此时已经+1了会指向'a'
            //此时start 指向 'w',last_space为0,
            start = b->pos - 1;
            start_line = cf->conf_file->line;

            if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
    
    
                continue;
            }

            switch (ch) {
    
    

            case ';':
            case '{':
                //cf->args必须已经存储了元素
                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;
            }
            /**
             *  
             * 依照上面代码的特殊字符判断一个字段的结束
             * 没找到之前都会偏移b->pos指针
             * 然后将根据start 及 b->pos 将数据拷贝进cf->args
             */
            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++)
                {
    
    
                    //判断转义字符,有则偏移2个位置
                    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;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/dai1396734/article/details/126119001
今日推荐