Apache源代码全景分析(第1卷):体系结构与核心模块
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 Apache核心功能层

尽管在2.2节中我们简要描述了Apache核心功能层,但是对于理解Apache核心及本书所要描述的内容还远远不够。本节将对Apache核心功能层展开描述。但并不涉及其内在的实现细节。

2.3.1 核心与可选模块的关系

Apache核心与Apache模块之间的关系是调用和被调用的关系,所有的模块都直接与核心进行交互,如图2-5所示。

图2-5 核心和模块的关系

Apache核心模块和Apache可选模块的接口完全相同,并且它们对于Apache核心而言也是完全相同的。在处理的过程中,核心并不会去关心谁是核心模块,谁是可选模块,它们都是一视同仁地被调用。核心模块和非核心模块的唯一区别就是加载的时间不同。核心模块通常必须静态加载,而非核心模块则既可以静态加载,也可以动态加载。因此核心模块是Apache中必不可少的部分。

2.3.2 核心组件

对于Apache而言,Apache的核心组件包括下面几大部分。

■ 配置文件组件(HTTP_CONFIG)。

■ 进程并发处理组件(MPM)。

■ 连接处理组件(HTTP_CONNECTION)。

■ HTTP协议处理组件(HTTP_PROTOCOL)。

■ HTTP请求处理组件(HTTP_REQUEST)。

■ HTTP核心组件(HTTP_CORE)。

■ 核心模块组件(MOD_CORE)。

Apache核心组件之间的相互关系可以用图2-6进行描述。

图2-6 Apache各组件之间的交互关系

main

main.c是整个Apache的入口,它内部包含了main()函数,该函数的功能包含下面几个部分。

1. 命令行处理

Apache解析用户的命令行参数,并根据这些参数对Apache做不同的启动处理。

2. 配置文件处理

Apache的配置文件决定了Apache的各个方面,在Apache运行的过程中,它必须能够读取各种配置信息。因此,读取配置文件是Apache启动后首先要完成的事情。函数中将配置文件最终处理为配置树结构。

3. 构建虚拟主机信息

Apache 支持虚拟主机技术。虚拟主机的配置信息保存在配置文件中。因此,一旦解析配置文件成功,其中的虚拟主机配置信息也会被解析出来。main 函数将根据这些虚拟主机配置构建相应的虚拟主机,最终形成一系列的server_rec结构链表。

4. 进入主循环

在主循环中,Apache所做的事情就是执行MPM模块。MPM将产生多个进程或多个线程侦听指定端口,并处理该端口上的连接。当MPM执行失败的时候,main函数才会执行下一次循环,大致如下:

    for(;;)
    {
              ….
              if(ap_mpm_run(…))
              break;
              ….
    }

HTTP配置文件组件(HTTP_CONFIG)

HTTP_CONFIG组件主要位于http_config.h和config.c中,它的主要作用是对配置文件进行解析、处理和保存。另外,HTTP_CONFIG组件还必须提供对配置数据访问的接口,其余组件在配置数据的任何时候都能够快地返回配置信息。它是一个基础的模块,几乎所有的组件都会与之打交道。

进程并发处理组件(MPM)

MPM组件主要位于mpm目录下的各个文件中,比如Prefork MPM对应的就是prefork.c。MPM负责为Apache系统提供可靠、稳定、高效的进程和线程的并发处理。任何时候,Apache中只能有一个MPM在运行,而且MPM必须在编译的时候指定,不允许动态加载。

HTTP连接处理组件(HTTP_CONNECTION)

HTTP_CONNECTION组件主要位于http_connection.h和connection.c中。该组件主要负责处理与HTTP连接相关的事情。

HTTP协议处理组件(HTTP_PROTOCOL)

在Apache 2.x系列中,HTTP_PROTOCOL组件主要位于http_protocol.h和http_protocol.c中,主要负责处理HTTP/1.0及HTTP/1.1协议的解析,比如解析http请求头、生成返回给客户端的响应包等。所有与协议相关的处理都由该组件完成。

在Apache 1.3中,HTTP_PROTOCOL组件还必须管理与HTTP客户端的连接。

HTTP请求处理组件(HTTP_REQUEST)

HTTP_REQUEST组件主要位于http_request.h、http_request.c及request.c三个文件中。与Apache 1.3相比,它增加了request.c文件。与请求相关的函数全部定义在http_request.h中,函数实现则分散在两个.c中。

这三个文件组合起来称之为“请求处理组件”。请求处理组件的请求内容包括三方面。

1. 请求的总入口函数ap_process_request及请求终止函数

对于特定的请求,ap_process_request将进入到实质的请求处理阶段。当请求处理失败的时候,则调用ap_die终止该请求。

2. 请求本身属性相关的操作

组件中定义了一系列的函数,使得允许对请求的属性进行更改,比如ap_update_mtime、ap_allow_methods等。

3. 子请求相关的操作

在Apache 2.0中执行一些特定操作的时候,为了加快处理速度,会从当前请求中派生出多个子请求,由这些子请求去并发地处理。比如当mod_autoindex模块进行索引的时候会针对目录中的每一个文件产生一个子请求。当子请求处理完毕后再返回到父请求中。

组件中提供的与子请求相关的函数包括:

■ ap_sub_req_lookup_uri。

■ ap_sub_req_lookup_file。

■ ap_sub_req_lookup_dirent。

■ ap_sub_req_method_uri。

■ ap_run_sub_req。

■ ap_destroy_sub_req。

4. 重定向请求操作

在Apache处理请求的过程中,任何时候,当前请求都可能被重定向,比如请求处理发生错误,或者请求被rewrite等。当重定向发生时,当前请求将产生一个新的请求,由新请求继续处理。与子请求不同的是,子请求执行完毕后总会返回到父请求,而重定向请求则不一定会返回。它通常会直接返回客户端浏览器。组件中提供的与重定向相关的函数包括以下几点。

■ ap_internal_redirect。

■ ap_internal_redirect_handler。

■ ap_internal_fast_redirect。

5. 请求挂钩声明

组件中另外一项重要的工作就是声明请求处理阶段所须要使用的各种挂钩,包括create_request、translate_name、map_to_storage、check_user_id 等。这些挂钩我们在后面会进行详细的分析。

6. 请求相关的配置处理

当一个请求被处理的时候,它须查找与该请求相关联的一些配置信息,这些配置信息的查找也由HTTP_REQUEST组件完成。

HTTP核心组件(HTTP_CORE)

在 Apache 2.x 系列中还增加了一个 HTTP_CORE 模块,它位于文件 http_core.h 和http_core.c中,该组件主要是将与HTTP协议相关的内容从原来的核心模块中提取出来的。最早的时候,一些与HTTP协议相关的指令(如KeepAliveTimeout、MaxKeepAliveRequests及KeepAlive)都是直接由core.c核心模块完成的。这样,核心模块就与HTTP协议紧紧捆绑在一起。在2.x的设计中,设计者已经开始考虑将Apache设计为一个通用的服务器框架,而不仅仅是一个HTTP Web服务器,以后它也可以支持FTP等协议。因此,有必要将http协议的处理从核心中剥离出来。有理由相信,如果Apache支持FTP,与FTP相关的核心指令处理肯定位于ftp_core.h和ftp_core.c类似的文件中。

核心模块组件(MOD_CORE)

核心模块(MOD_CORE)由mod_core.h和core.c组成,该模块的主要任务就是对核心需要的指令进行比较,比如<Directory>、<Location>、DocumentRoot 等。该模块在HTTP_CONFIG中被调用。

其余模块

在Apache中,除了上面提及的一些非常重要的组件之外,还包括一些相对重要的组件,这些组件包括日志处理组件、虚拟主机处理组件,以及过滤器模块组件。

顾名思义,日志处理组件就是进行日志记录,该组件包括http_log.h和log.c。虚拟主机处理组件则为Apache提供虚拟主机支持。过滤器模块组件则是更加重要的组件,它是HTTP数据在核心内部传输的重要机制。