Lighttpd - Configuration

来源:互联网 发布:淘宝里添加门店库 编辑:程序博客网 时间:2024/05/22 02:29

配置文件应该是lighttpd源代码里面比较难的一部分,其中涉及了大量的结构体、变量、函数,
parser部分还涉及了一些编译原理的知识。这一部分我看了好几天,每天看之前都要复习一下
几个重要的结构体的组成和它们之间的关系。

我打算在对lighttpd的整个框架都理解透了以后再写分析,因为单独去分析某个部分的话会让人
不理解这个部分在整个项目中的作用,而且有些细节只有在理解整体之后才能知道到底为什么要
这样设计。

下面只是简单地分析一下整个配置文件的分析过程,不会涉及到具体的细节。
以下会涉及一点编译原理的知识,如tokenlize, scan, parse等并不特指某个
函数,而是编译过程的特定步骤。

1. server.c -> main

当用户使用-f选项指定了配置文件之后,在getopt中就会调用
config_read(srv, optarg);
这是整个分析的入口函数。后面还有一个配置函数:
config_set_defaults(srv);
这个函数是用来检查一些必要的配置项是否正确,以及设置一些系统相关的配置。

2. 相关变量

在继续分析之前,先来看一下server结构体中的几个与配置信息有关的变量:

array *config;            /* 存放global配置的 */array *config_touched;    /* 记录哪些配置项被使用了,在后面会看到它 */array *config_context;    /* 存放所有的原始配置信息,即使用lemon parse出来                           * 的所有符合语法(但不一定是有效(支持)的)的数据 *//* 把config_context中有效的配置信息提取出来存放在这里 */specific_config **config_storage;  server_config srvconf;    /* 存放与server关系比较大的配置信息 */

3. configfile.c -> config_read

config_t context;         /* 作为Parse的第4个参数,存储parse过程中的信息 */...context->all_configs = srv->config_context;    /* 在parse过程中所有对context->all_configs                                                * 的修改就相当于对srv->config_context */...                                     /* 一些默认的全局配置,var.PID和var.CWD */config_parse_file(srv, &context, fn);   /* 读取文件并分析 */

4. configfile.c -> config_parse_file

tokenlizer_t t;                          /* 用于控制tokenlize过程的信息 */...                                      /* 与文件路径和stream有关的一些判断 */tokenlizer_init(&t, filename, s.start, s.size);ret = config_parse(srv, context, &t);    /* 真正开始scan和parse */

5. configfile.c -> config_parse

这个函数其实就是执行使用lemon的套路,关于lemon的简单使用之前写过了,这里就不再说了。
简化之后就是这样:

pParser = configparserAlloc(malloc);while (config_tokenlizer(srv, t, &token_id, token))        configparser(pParser, token_id, token, context);configparser(pParser, 0, NULL, context);configparserFree(pParser, free);

6. configfile.c -> config_tokenlizer

config_tokenlizer就相当于一个scanner,把文件流中的字符切成一个一个的token
这个函数比较繁杂,我就不分析了,只需要稍微了解编译原理的知识应该就没什么问题了。

7. configfile.c -> config_read

经过上面几个分析过程之后就回到了这里,这个时候对配置文件的分析其实就结束了,
之后就是要保证"mod_indexfile" "mod_dirlisting" "mod_staticfile"这三个模块
必须要加载,而且"mod_indexfile"必须是所有模块中的第一个,因为接受到客户端的请求
时,是按照配置的顺序传给相应的模块的,这样模块的顺序就需要考虑了,至于为什么
"mod_indexfile"要是第一个就不属于这里要写的内容了。

在这个函数的最后就是要从存放在context->all_configs (srv->config_context)里面的

原始数据中提取出有效(支持)的配置信息,存放在srv->context_storage:

config_insert(srv);

8. configfile.c -> config_insert

srv->config_context中提取有效配置的关键就在于:
config_values_t cv[] = {...};   /* 这里存储了所有支持的配置项,如果srv->config_context                                 * 里面的匹配这里的配置项,那么这一个配置就是有效的 */...                             /* 下面的一大段都是为了初始化cv[]的,其中cv[x]->destination                                 * 指向了每一个配置项的值存放的地方,提取出来的信息就是存放在这里的 */config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv);

9. configfile-glue.c -> config_insert_values_global

这个函数只是简单地把srv->config_context里面使用到的有效配置项记录到srv->config_touched里面,
然后调用config_insert_values_internal

10. configfile-glue.c -> config_insert_values_internal

根据cv[i].typesrv->config_context提取出来的配置项的值复制到相应的cv[i].destination里面。
到了这一步,所有从配置文件读出来的配置项的值就存放到相应的地方了。

11. configparser.y

最后在来看一下这个lemon使用的文件,这个文件比较复杂,这里只是提一下需要注意的地方:
%extra_argument {config_t *ctx}            /* 之前提到的第4个参数 */%name configparser                         /* 生成的代码函数接口的前缀,默认是Parse */...                                        /* 后面是针对每个rule reduce时要执行代码。由于要支持嵌套结构,所以其中要用到一些栈的思想和操作, * 栈的信息存储在ctx->configs_stack中。还有一点值得注意的是,内层嵌套的配置项的值是“继承”外层的, * 也就是说,如果内层出现了和外层一样的配置项的话,那么内层配置项的值要先从外层拷贝进来,然后再在 * 后面加上新的值,而外层的值不会收到内层的影响。*/


好吧,就先分析到这里。分析这一部分确实比较累人,以后可能会结合不同配置项在整个程序中的作用再具体分析。

原创粉丝点击