Apache 讲解

概述

简单服务器流程

Q1:简述在浏览器中输入 www.baidu.com 之后发生的一系列事情

img

appendix1:http1.0 vs http1.1

I/O 模型

  • 阻塞式 I/O 模型 img
  • 非阻塞 I/O 模型 img
  • I/O 复用 模型 img
  • 异步 I/O 模型 img

UNIX网络编程(卷1):套接字联网API(第3版)

工作模式

查看apache的工作模式

/usr/sbin/apachectl -V

内存管理

内存管理

核心数据结构

img

request的关键元素

The most essential part of any request is the request record. In a call to a handler function, this is represented by the request_rec structure passed along with every call that is made. This struct, typically just referred to as r in modules, contains all the information you need for your module to fully process any HTTP request and respond accordingly.

Some key elements of the request\_recstructure are:

  • r->handler (char*): Contains the name of the handler the server is currently asking to do the handling of this request
  • r->method (char*): Contains the HTTP method being used, f.x. GET or POST
  • r->filename (char*): Contains the translated filename the client is requesting
  • r->args (char*): Contains the query string of the request, if any
  • r->headers_in (apr_table_t*): Contains all the headers sent by the client
  • r->connection (conn_rec*): A record containing information about the current connection
  • r->user (char*): If the URI requires authentication, this is set to the username provided
  • r->useragent_ip (char*): The IP address of the client connecting to us
  • r->pool (apr_pool_t*): The memory pool of this request. We’ll discuss this in the “Memory management” chapter.

核心数据结构

mod_helloworld 模块讲解

modguide

Apache: 启动流程

Apache: 连接 / 请求处理流程

apxs -n helloworld -g

Defining a module

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

/* The sample content handler */
static int helloworld_handler(request_rec *r)
{
    if (strcmp(r->handler, "helloworld")) {
        return DECLINED;
    }
    r->content_type = "text/html";

    if (!r->header_only)
        ap_rputs("The sample page from mod_helloworld.c\n", r);
    return OK;
}


static void helloworld_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
/* 标记服务器能够加载的模块名 */
/* 为模块配置设置一个命名空间 */
module AP_MODULE_DECLARE_DATA helloworld_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    helloworld_directives, /* table of config file commands       */
    helloworld_register_hooks  /* register hooks                      */
};

指令

typedef struct {
    int         enabled;      /* Enable or disable our module */
    const char *path;         /* Some path to...something */
    int         typeOfAction; /* 1 means action A, 2 means action B and so on */
} example_config;

static const command_rec helloworld_directives[] =
{
    AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
    AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"),
    AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"),
    { NULL }
};

img

配置的作用域

  • OR_ALL 所有的地方使用
  • ACCESS_CONF:允许指令出现这Directiory Location 区间以内的顶级命令区,一般是用来设置特定文的指令控制
  • RSRC_CONF: 允许指令出现在 Directiory Location 区间以外的顶级命令区

配置段合并

配置段会按非常特别的顺序依次生效,由于这会对配置指令的处理结果产生重大影响,因此理解它的流程非常重要。

合并的顺序是:

  1. <Directory>(除了正则表达式)和.htaccess同时处理;(如果允许的话,.htaccess的设置会覆盖<Directory>的设置)
  2. <DirectoryMatch>(和<Directory ~>)
  3. <Files><FilesMatch>同时处理
  4. <Location><LocationMatch>同时处理

除了<Directory>,每个组都按它们在配置文件中出现的顺序被依次处理,而<Directory>(上面的第1组),会按字典顺序由短到长被依次处理。例如:<Directory /var/web/dir>会先于<Directory /var/web/dir/subdir>被处理。如果有多个指向同一个目录的<Directory>段,则按它们在配置文件中的顺序被依次处理。用Include指令包含进来的配置被视为按原样插入到Include指令的位置。

位于<VirtualHost>容器中的配置段在外部对应的段处理完毕*以后*再处理,这样就允许虚拟主机覆盖主服务器的设置。

代码示例

void *create_dir_conf(apr_pool_t *pool, char *context) {
    context = context ? context : "(undefined context)";
    example_config *cfg = apr_pcalloc(pool, sizeof(example_config));
    if(cfg) {
        /* Set some default values */
        strcpy(cfg->context, context);
        cfg->enabled = 0;
        cfg->path = "/foo/bar";
        cfg->typeOfAction = 0x11;
    }
    return cfg;
}

void *merge_dir_conf(apr_pool_t *pool, void *BASE, void *ADD) {
    example_config *base = (example_config *) BASE ; /* This is what was set in the parent context */
    example_config *add = (example_config *) ADD ;   /* This is what is set in the new context */
    example_config *conf = (example_config *) create_dir_conf(pool, "Merged configuration"); /* This will be the merged configuration */
    
    /* Merge configurations */
    conf->enabled = ( add->enabled == 0 ) ? base->enabled : add->enabled ;
    conf->typeOfAction = add->typeOfAction ? add->typeOfAction : base->typeOfAction;
    strcpy(conf->path, strlen(add->path) ? add->path : base->path);
    
    return conf ;
}

module AP_MODULE_DECLARE_DATA   example_module =
{
    STANDARD20_MODULE_STUFF,
    create_dir_conf, /* Per-directory configuration handler */
    merge_dir_conf,  /* Merge handler for per-directory configurations */
    NULL,            /* Per-server configuration handler */
    NULL,            /* Merge handler for per-server configurations */
    directives,      /* Any directives we may have for httpd */
    register_hooks   /* Our hook registering function */
};

hook 钩子

img

钩子的处理

  • /*在这个钩子处按照顺序运行所有的被注册函数*/
    AP_IMPLEMENT_HOOK_VOID(do_something, (request_rec *r, int n), (r, n))
    
  • /*在这个钩子处运行所有的被注册函数直到返回了一个不是DECLINED的值*/
    AP_IMPLEMENT_HOOK_RUN_FIRST(int, do_something, (request_rec *r, int n), (r, n), DECLINED)
    
  • /*运行所有的函数直到或者除非返回一个错误*/
    AP_IMPLEMENT_HOOK_RUN_ALL(int, do_something, (request_rec *r, int n), (r, n), OK, DECLINED)
    

其它有用的钩子

Hooking into the request handling phase is but one of many hooks that you can create. Some other ways of hooking are:

  • ap_hook_child_init: Place a hook that executes when a child process is spawned (commonly used for initializing modules after the server has forked)

  • ap_hook_pre_config: Place a hook that executes before any configuration data has been read (very early hook)

  • ap_hook_post_config: Place a hook that executes after configuration has been parsed, but before the server has forked

  • ap_hook_translate_name: Place a hook that executes when a URI needs to be translated into a filename on the server (think mod_rewrite)

  • ap_hook_quick_handler: Similar to ap_hook_handler, except it is run before any other request hooks (translation, auth, fixups etc)

  • ap_hook_log_transaction: Place a hook that executes when the server is about to add a log entry of the current request

代码调试

apache调试