q29191 发表于 2016-12-25 11:17:51

nginx源码阅读笔记

  

  最近做一个收集客户端数据的项目, 后台使用nginx, 通过实现nginx的模块来处理业务.  nginx的模块编写不难,
  但写完后对nginx的内部机制还是云里雾里, 趁周末好好阅读一下nginx的源代码.  下面记录一些阅读过程中遇
  到的数据结构. 关于nginx的内部实现, 等看懂了源码再写.
  

  模块四要素:
  1 模块实例, 2 模块上下文, 3 模块指令, 4 指令参数
  

  模块定义
  ===================================================
  struct ngx_module_s {
      ngx_uint_t            ctx_index;
      ngx_uint_t            index;
  

      ngx_uint_t            spare0;
      ngx_uint_t            spare1;
      ngx_uint_t            spare2;
      ngx_uint_t            spare3;
  

      ngx_uint_t            version;
  

      void                 *ctx;
      ngx_command_t        *commands;
      ngx_uint_t            type;
  

      ngx_int_t           (*init_master)(ngx_log_t *log);
  

      ngx_int_t           (*init_module)(ngx_cycle_t *cycle);
  

      ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
      ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
      void                (*exit_thread)(ngx_cycle_t *cycle);
      void                (*exit_process)(ngx_cycle_t *cycle);
  

      void                (*exit_master)(ngx_cycle_t *cycle);
  

      uintptr_t             spare_hook0;
      uintptr_t             spare_hook1;
      uintptr_t             spare_hook2;
      uintptr_t             spare_hook3;
      uintptr_t             spare_hook4;
      uintptr_t             spare_hook5;
      uintptr_t             spare_hook6;
      uintptr_t             spare_hook7;
  };  (core/ngx_conf_file.h)
  

  模块实例定义
  ===================================================
  1 核心模块
  ngx_module_t  ngx_core_module = {
      NGX_MODULE_V1,
      &ngx_core_module_ctx,                  /* module context */
      ngx_core_commands,                     /* module directives */
      NGX_CORE_MODULE,                       /* module type */
      NULL,                                  /* init master */
      NULL,                                  /* init module */
      NULL,                                  /* init process */
      NULL,                                  /* init thread */
      NULL,                                  /* exit thread */
      NULL,                                  /* exit process */
      NULL,                                  /* exit master */
      NGX_MODULE_V1_PADDING
  }; (core/nginx.c)
  

  2 http模块
  ngx_module_t  ngx_http_module = {
      NGX_MODULE_V1,
      &ngx_http_module_ctx,                  /* module context */
      ngx_http_commands,                     /* module directives */
      NGX_CORE_MODULE,                       /* module type */
      NULL,                                  /* init master */
      NULL,                                  /* init module */
      NULL,                                  /* init process */
      NULL,                                  /* init thread */
      NULL,                                  /* exit thread */
      NULL,                                  /* exit process */
      NULL,                                  /* exit master */
      NGX_MODULE_V1_PADDING
  };
  

  3 http核心模块
  ngx_module_t  ngx_http_core_module = {
      NGX_MODULE_V1,
      &ngx_http_core_module_ctx,             /* module context */
      ngx_http_core_commands,                /* module directives */
      NGX_HTTP_MODULE,                       /* module type */
      NULL,                                  /* init master */
      NULL,                                  /* init module */
      NULL,                                  /* init process */
      NULL,                                  /* init thread */
      NULL,                                  /* exit thread */
      NULL,                                  /* exit process */
      NULL,                                  /* exit master */
      NGX_MODULE_V1_PADDING
  }; (http/ngx_http_core_module.c)
  

  4 日志模块
  ngx_module_t  ngx_errlog_module = {
      NGX_MODULE_V1,
      &ngx_errlog_module_ctx,                /* module context */
      ngx_errlog_commands,                   /* module directives */
      NGX_CORE_MODULE,                       /* module type */
      NULL,                                  /* init master */
      NULL,                                  /* init module */
      NULL,                                  /* init process */
      NULL,                                  /* init thread */
      NULL,                                  /* exit thread */
      NULL,                                  /* exit process */
      NULL,                                  /* exit master */
      NGX_MODULE_V1_PADDING
  };
  

  5 事件模块
  ngx_module_t  ngx_event_core_module = {
      NGX_MODULE_V1,
      &ngx_event_core_module_ctx,            /* module context */
      ngx_event_core_commands,               /* module directives */
      NGX_EVENT_MODULE,                      /* module type */
      NULL,                                  /* init master */
      ngx_event_module_init,                 /* init module */
      ngx_event_process_init,                /* init process */
      NULL,                                  /* init thread */
      NULL,                                  /* exit thread */
      NULL,                                  /* exit process */
      NULL,                                  /* exit master */
      NGX_MODULE_V1_PADDING
  };
  

  模块上下文定义 
  ===================================================
  1 核心模块上下文定义
  typedef struct {
      ngx_str_t             name;
      void               *(*create_conf)(ngx_cycle_t *cycle);
      char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);
  } ngx_core_module_t;     (见src/core/ngx_conf_file.h)
  

  2 事件模块上下文定义
  typedef struct {
      ngx_str_t              *name;
  

      void                 *(*create_conf)(ngx_cycle_t *cycle);
      char                 *(*init_conf)(ngx_cycle_t *cycle, void *conf);
  

      ngx_event_actions_t     actions;
  } ngx_event_module_t;(见src/event/ngx_event.h)
  

  3 http模块上下文定义
  typedef struct {
      ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
      ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
  

      void       *(*create_main_conf)(ngx_conf_t *cf);
      char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
  

      void       *(*create_srv_conf)(ngx_conf_t *cf);
      char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
  

      void       *(*create_loc_conf)(ngx_conf_t *cf);
      char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
  } ngx_http_module_t;  (见src/http/ngx_http_config.h)
  

  4 事件模块上下文定义
  ngx_event_module_t  ngx_event_core_module_ctx = {
      &event_core_name,
      ngx_event_create_conf,                 /* create configuration */
      ngx_event_init_conf,                   /* init configuration */
  

      { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
  };
  

  模块上下文实例
  ===============================================================
  1 核心模块上下文
  static ngx_core_module_t  ngx_core_module_ctx = {
      ngx_string("core"),
      ngx_core_module_create_conf,
      ngx_core_module_init_conf
  }; (core/nginx.c)
  

  2 http核心模块上下文
  static ngx_http_module_t  ngx_http_core_module_ctx = {
      ngx_http_core_preconfiguration,        /* preconfiguration */
      NULL,                                  /* postconfiguration */
  

      ngx_http_core_create_main_conf,        /* create main configuration */
      ngx_http_core_init_main_conf,          /* init main configuration */
  

      ngx_http_core_create_srv_conf,         /* create server configuration */
      ngx_http_core_merge_srv_conf,          /* merge server configuration */
  

      ngx_http_core_create_loc_conf,         /* create location configuration */
      ngx_http_core_merge_loc_conf           /* merge location configuration */
  }; (http/ngx_http_core_module.c)
  

  

  存储指令参数的结构体
  ===============================================================
  根指令的参数
  typedef struct {
       ngx_flag_t               daemon;
       ngx_flag_t               master;
  

       ngx_msec_t               timer_resolution;
  

       ngx_int_t                worker_processes;
       ngx_int_t                debug_points;
  

       ngx_int_t                rlimit_nofile;
       ngx_int_t                rlimit_sigpending;
       off_t                    rlimit_core;
  

       int                      priority;
  

       ngx_uint_t               cpu_affinity_n;
       u_long                  *cpu_affinity;
  

       char                    *username;
       ngx_uid_t                user;
       ngx_gid_t                group;
  

       ngx_str_t                working_directory;
       ngx_str_t                lock_file;
  

       ngx_str_t                pid;
       ngx_str_t                oldpid;
  

       ngx_array_t              env;
       char                   **environment;
  } ngx_core_conf_t;
  

  http指令的参数
  typedef struct {
  /* 保存所有server的配置信息 */
      ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */
  

      ngx_http_phase_engine_t    phase_engine;
  

      ngx_hash_t                 headers_in_hash;
  

      ngx_hash_t                 variables_hash;
  

      ngx_array_t                variables;       /* ngx_http_variable_t */
      ngx_uint_t                 ncaptures;
  

      ngx_uint_t                 server_names_hash_max_size;
      ngx_uint_t                 server_names_hash_bucket_size;
  

      ngx_uint_t                 variables_hash_max_size;
      ngx_uint_t                 variables_hash_bucket_size;
  

      ngx_hash_keys_arrays_t    *variables_keys;
  

      ngx_array_t               *ports;
  

      ngx_uint_t                 try_files;       /* unsigned  try_files:1 */
  

      ngx_http_phase_t           phases;
  } ngx_http_core_main_conf_t;
  

  

  server指令的参数
  typedef struct {
      /* array of the ngx_http_server_name_t, "server_name" directive */
      ngx_array_t                 server_names;
  

      /* server ctx,初始化http请求ngx_http_init_request时用得到 */
      ngx_http_conf_ctx_t        *ctx;
  

      ngx_str_t                   server_name;
  

      size_t                      connection_pool_size;
      size_t                      request_pool_size;
      size_t                      client_header_buffer_size;
  

      ngx_bufs_t                  large_client_header_buffers;
  

      ngx_msec_t                  client_header_timeout;
  

      ngx_flag_t                  ignore_invalid_headers;
      ngx_flag_t                  merge_slashes;
      ngx_flag_t                  underscores_in_headers;
  

      unsigned                    listen:1;
  

      ngx_http_core_loc_conf_t  **named_locations;
  } ngx_http_core_srv_conf_t;
  

  location指令的参数
  struct ngx_http_core_loc_conf_s {
      ngx_str_t     name;          /* location name */
  

      unsigned      noname:1;   /* "if () {}" block or limit_except */
      unsigned      lmt_excpt:1;
      unsigned      named:1;
  

      unsigned      exact_match:1;
      unsigned      noregex:1;
  

      unsigned      auto_redirect:1;
  

      /* pointer to the modules' loc_conf */
      void        **loc_conf;
  

      uint32_t      limit_except;
      void        **limit_except_loc_conf;
  

      ngx_http_handler_pt  handler;
  

      /* location name length for inclusive location with inherited alias */
      size_t        alias;
      ngx_str_t     root;                    /* root, alias */
      ngx_str_t     post_action;
  

      ngx_array_t  *root_lengths;
      ngx_array_t  *root_values;
  

      ngx_array_t  *types;
      ngx_hash_t    types_hash;
      ngx_str_t     default_type;
  

      off_t         client_max_body_size;    /* client_max_body_size */
      off_t         directio;                /* directio */
      off_t         directio_alignment;      /* directio_alignment */
  

      size_t        client_body_buffer_size; /* client_body_buffer_size */
      size_t        send_lowat;              /* send_lowat */
      size_t        postpone_output;         /* postpone_output */
      size_t        limit_rate;              /* limit_rate */
      size_t        limit_rate_after;        /* limit_rate_after */
      size_t        sendfile_max_chunk;      /* sendfile_max_chunk */
      size_t        read_ahead;              /* read_ahead */
  

      ngx_msec_t    client_body_timeout;     /* client_body_timeout */
      ngx_msec_t    send_timeout;            /* send_timeout */
      ngx_msec_t    keepalive_timeout;       /* keepalive_timeout */
      ngx_msec_t    lingering_time;          /* lingering_time */
      ngx_msec_t    lingering_timeout;       /* lingering_timeout */
      ngx_msec_t    resolver_timeout;        /* resolver_timeout */
  

      ngx_resolver_t  *resolver;             /* resolver */
  

      time_t        keepalive_header;        /* keepalive_timeout */
  };
  

  指令定义
  ===========================================================
  struct ngx_command_s {
      ngx_str_t             name;
      ngx_uint_t            type;初始化http请求: ngx_http_init_request    
      char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
      ngx_uint_t            conf;
      ngx_uint_t            offset;
      void                 *post;
  };
  

  cycle定义
  ===========================================================
  struct ngx_cycle_s {
      void                  ****conf_ctx;
      ngx_pool_t               *pool;
  

      ngx_log_t                *log;
      ngx_log_t                 new_log;
  

      ngx_connection_t        **files;
      ngx_connection_t         *free_connections;
      ngx_uint_t                free_connection_n;
  

      ngx_queue_t               reusable_connections_queue;
  

      ngx_array_t               listening;
      ngx_array_t               pathes;
      ngx_list_t                open_files;
      ngx_list_t                shared_memory;
  

      ngx_uint_t                connection_n;
      ngx_uint_t                files_n;
  

      ngx_connection_t         *connections;
      ngx_event_t              *read_events;
      ngx_event_t              *write_events;
  

      ngx_cycle_t              *old_cycle;
  

      ngx_str_t                 conf_file;
      ngx_str_t                 conf_param;
      ngx_str_t                 conf_prefix;
      ngx_str_t                 prefix;
      ngx_str_t                 lock_file;
      ngx_str_t                 hostname;
  };
  

  http三大配置
  ===========================================================
  typedef struct {
      void        **main_conf;
      void        **srv_conf;
      void        **loc_conf;
  } ngx_http_conf_ctx_t;
  

  解析配置文件的时候, 用结构体ngx_conf_s来暂时存放指令的参数
  ===========================================================
  struct ngx_conf_s {
      char                 *name;
      ngx_array_t          *args;
  

      ngx_cycle_t          *cycle;
      ngx_pool_t           *pool;
      ngx_pool_t           *temp_pool;
      ngx_conf_file_t      *conf_file;
      ngx_log_t            *log;
  

      void                 *ctx;
      ngx_uint_t            module_type;
      ngx_uint_t            cmd_type;
  

      ngx_conf_handler_pt   handler;
      char                 *handler_conf;
  };
  在ngx_init_cycle中声明一个这样的变量
  ngx_conf_t conf;
  然后开始解析配置文件, 这个结构体可以反复使用, 每次遇到一个指令, 就会改变conf的内容
  

  阅读痕迹
  =====================================================================
  * ngx_init_cycle:
      * ngx_conf_t.ctx = cycle->conf_ctx;
  

  解析配置文件
  * 从ngx_init_cycle调用ngx_conf_param开始解析配置文件
  * ngx_conf_param再调用ngx_conf_parse解析配置文件
  * ngx_conf_parse:
      * 打开配置文件
      * for循环:
          * 读取文件, ngx_conf_read_token, 把指令名和参数存到ngx_conf_t结构体,
            每次都一条指令便返回
          * 调用ngx_conf_handler来处理这条指令:
              * 寻找指令所在的模块
              * 检验指令在配置文件中的位置是否正确
              * 检验指令的参数个数是否合法
              * 取得指令参数要存储的地方(比如ngx_core_conf_t,用conf指针指向),这个结构体由
                模块的create_conf来创建, 然后把它安插在 ngx_conf_t.ctx 中
              * 调用指令的 set 函数, 把ngx_conf_t中的参数值转存到conf指向的结构体
  

  解析http block
  如果ngx_conf_read_token返回"http {", 则调用ngx_http_block解析http block下面的配置
  * ngx_http_block:
      * 创建ngx_http_conf_ctx_t结构体, 这时conf指针不再指向ngx_core_conf_t, 
        而是指向ngx_http_conf_ctx_t
      * 数一下有多少个http模块, 并设置每个模块的index
      * 调用所有http模块的create_main_conf钩子,把返回的结构体安插在ngx_http_conf_ctx_t.main_conf表中
        调用所有http模块的create_srv_conf钩子,把返回的结构体安插在ngx_http_conf_ctx_t.srv_conf表中
        调用所有http模块的create_loc_conf钩子,把返回的结构体安插在ngx_http_conf_ctx_t.loc_conf表中
      * ngx_conf_t.ctx不再指向cycle->conf_ctx, 而是指向ngx_http_conf_ctx_t 
      * 调用所有http模块的preconfiguration钩子
      * 再次调用ngx_conf_parse来解析http block里面的指令, 至此http block, 
        server block, location block都解析完毕
      * 调用所有http模块的init_main_conf钩子 
      * 待续...
  

  解析server block
  解析htto block的时候, 如果遇到"server {", 则调用
  server command的set方法:ngx_http_core_server, 开始解析server block
  ngx_http_core_server:
      * 再创建一个ngx_http_conf_ctx_t结构体, 这时ngx_conf_t.ctx不再指向
        http block的ngx_http_conf_ctx_t, 而是指向这个新的ngx_http_conf_ctx_t
        ctx = new ngx_http_conf_ctx_t
        http_ctx = cf->ctx
        cf->ctx = ctx
      * server ctx的main_conf从http ctx继承过来
        ctx->main_conf = http_ctx->main_conf;
      * 调用所有http模块的create_srv_conf钩子,把返回的结构体安插在ctx.srv_conf表中
        调用所有http模块的create_loc_conf钩子,把返回的结构体安插在ctx.loc_conf表中
      
  

  

  http block下面三大conf的偏移量
  -----------------------------------------------------------
  #define NGX_HTTP_MAIN_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, main_conf)
  #define NGX_HTTP_SRV_CONF_OFFSET   offsetof(ngx_http_conf_ctx_t, srv_conf)
  #define NGX_HTTP_LOC_CONF_OFFSET   offsetof(ngx_http_conf_ctx_t, loc_conf)
  

  

  根据ngx_http_request_t得到三大conf
  -----------------------------------------------------------
  #define ngx_http_get_module_main_conf(r, module)                             \
      (r)->main_conf
  #define ngx_http_get_module_srv_conf(r, module)  (r)->srv_conf
  #define ngx_http_get_module_loc_conf(r, module)  (r)->loc_conf
  

  

  根据ngx_conf_t得到三大conf
  -----------------------------------------------------------
  #define ngx_http_conf_get_module_main_conf(cf, module)                        \
      ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf
  #define ngx_http_conf_get_module_srv_conf(cf, module)                         \
      ((ngx_http_conf_ctx_t *) cf->ctx)->srv_conf
  #define ngx_http_conf_get_module_loc_conf(cf, module)                         \
      ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf
  

  

  根据cycyle的conf_ctx得到main conf
  -----------------------------------------------------------
  #define ngx_http_cycle_get_module_main_conf(cycle, module)                    \
      (cycle->conf_ctx ?                                 \
          ((ngx_http_conf_ctx_t *) cycle->conf_ctx)      \
              ->main_conf:                                    \
          NULL)
  

  

  ==================== ngx_http_log_module实例 ==================
  

  ngx_http_log_create_main_conf返回的结构体
  -----------------------------------------------------------
  typedef struct {
      ngx_array_t                 formats;    /* array of ngx_http_log_fmt_t */
      ngx_uint_t                  combined_used; /* unsigned  combined_used:1 */
  } ngx_http_log_main_conf_t;
  

  ngx_http_log_create_loc_conf返回的结构体
  -----------------------------------------------------------
  typedef struct {
      ngx_array_t                *logs;       /* array of ngx_http_log_t */
  

      ngx_open_file_cache_t      *open_file_cache;
      time_t                      open_file_cache_valid;
      ngx_uint_t                  open_file_cache_min_uses;
  

      ngx_uint_t                  off;        /* unsigned  off:1 */
  } ngx_http_log_loc_conf_t;
  

  指令
  -----------------------------------------------------------
  static ngx_command_t  ngx_http_log_commands[] = {
  

      { ngx_string("log_format"),
        NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
        ngx_http_log_set_format,
        NGX_HTTP_MAIN_CONF_OFFSET,
        0,
        NULL },
  

      { ngx_string("access_log"),
        NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                          |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,
        ngx_http_log_set_log,    
        NGX_HTTP_LOC_CONF_OFFSET,
        0,  /* 如果使用自定义的set方法, 而且无须知道参数在结构体中的offset,那么offset就可以设为0 */
        NULL },
  

      { ngx_string("open_log_file_cache"),
        NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
        ngx_http_log_open_file_cache,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL },
  

        ngx_null_command
  };
  

  上下文
  -----------------------------------------------------------
  static ngx_http_module_t  ngx_http_log_module_ctx = {
      NULL,                                  /* preconfiguration */
      ngx_http_log_init,                     /* postconfiguration */
  

      ngx_http_log_create_main_conf,         /* create main configuration */
      NULL,                                  /* init main configuration */
  

      NULL,                                  /* create server configuration */
      NULL,                                  /* merge server configuration */
  

      ngx_http_log_create_loc_conf,          /* create location configration */
      ngx_http_log_merge_loc_conf            /* merge location configration */
  };
  

  模块实例
  -----------------------------------------------------------
  ngx_module_t  ngx_http_log_module = {
      NGX_MODULE_V1,
      &ngx_http_log_module_ctx,              /* module context */
      ngx_http_log_commands,                 /* module directives */
      NGX_HTTP_MODULE,                       /* module type */
      NULL,                                  /* init master */
      NULL,                                  /* init module */
      NULL,                                  /* init process */
      NULL,                                  /* init thread */
      NULL,                                  /* exit thread */
      NULL,                                  /* exit process */
      NULL,                                  /* exit master */
      NGX_MODULE_V1_PADDING
  };
  

  ==================== end of ngx_http_log_module实例 ==================
  

  

  注意ngx_request_s保存有http block里面的三大conf
  --------------------------------------------------------------------
  struct ngx_http_request_s {
      uint32_t                          signature;         /* "HTTP" */
  

      ngx_connection_t                 *connection;
  

      void                            **ctx;
      void                            **main_conf;
      void                            **srv_conf;
      void                            **loc_conf;
  }
  

  

  总共创建多少个ngx_http_conf_ctx_t结构体
  ----------------------------------------------------
  http block下创建ngx_http_conf_ctx_t
  在server block下创建ngx_http_conf_ctx_t
  在location block下创建ngx_http_conf_ctx_t
  在location block下创建ngx_http_conf_ctx_t
  在location block下创建ngx_http_conf_ctx_t
  结论: http block只创建一个, 每个server都会创建一个结构体, 每个location都会创建一个结构体
  疑问:server block创建的ngx_http_conf_ctx_t会保存在ngx_http_core_srv_conf_t中
      那么location block创建的ngx_http_conf_ctx_t保存在哪里呢?
  

  

  调用 ngx_conf_parse 的时候会先保存ngx_conf_t
  ------------------------------------------------
  ngx_conf_t save;
      save = *cf;
      cf->ctx = ctx;
      cf->cmd_type = NGX_HTTP_LOC_CONF;
  

      rv = ngx_conf_parse(cf, NULL);
      
      *cf = save;  
  

  初始化http请求: ngx_http_init_request    
  -----------------------------------------------    
      ngx_http_core_srv_conf_t *cscf = addr_conf->default_server;
  

      r->main_conf = cscf->ctx->main_conf;
      r->srv_conf = cscf->ctx->srv_conf;
      r->loc_conf = cscf->ctx->loc_conf;
  自动收割子进程
  -----------------------------------------------    
  在master process中, 函数 ngx_signal_handler 用来处理信号, 若
  接收到 SIGCHLD 信号, 表示有一个子进程退出了, 然后把变量 ngx_reap 置为 1
  然后在 ngx_master_process_cycle 函数中, 若检查到 ngx_reap 等于 1,则创建
  一个子进程:
  


if (ngx_reap) {            
ngx_reap = 0;               
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");            
live = ngx_reap_children(cycle);      
}
 
页: [1]
查看完整版本: nginx源码阅读笔记