全面了解Nginx中的HTTP协议相关模块配置

2019-10-17 19:25:04王振洲

这个函数中,为所有的 http 模块都分配并创建了配置结构,同时,调用了每个模块相应的初始化回调。

最后,调用 ngx_http_optimize_servers 创建了 http 连接,加入 cycle 的监听数组,并设为监听状态。

nginx 配置文件对 http 模块的配置分为三层:main、sever、location,因此,http 模块上下文 ngx_http_module_t 中定义了以下六个回调函数,用来创建和保存配置信息:

create_main_conf init_main_conf create_srv_conf merge_srv_conf create_loc_conf merge_loc_conf

在 ngx_http_block 中,循环调用了所有 NGX_HTTP_MODULE 的这六个回调函数,创建相关的配置结构。

server、location 配置解析 -- ngx_http_core_server、ngx_http_core_location
在调用所有 HTTP 模块的 create_main_conf、create_srv_conf、create_loc_conf 后,所有需要配置结构的模块都完成了配置结构的创建,于是在调用所有模块的 preconfiguration 回调函数后,配置解析工作正式展开

通过调用 ngx_conf_parse 函数,开始了 http 配置块的解析,并通过解析到的命令调用相应的函数

在首个 NGX_HTTP_MODULE ngx_http_core_module 的 ngx_command_t 域中包含了大量的配置指令,它们都是在http{}块中出现的,其中包括两个重要的指令:

{ ngx_string("listen"),
 NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
 ngx_http_core_listen,
 NGX_HTTP_SRV_CONF_OFFSET,
 0,
 NULL },

{ ngx_string("server"),
 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
 ngx_http_core_server,
 0,
 0,
 NULL },

{ ngx_string("location"),
 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
 ngx_http_core_location,
 NGX_HTTP_SRV_CONF_OFFSET,
 0,
 NULL },

这里配置了 listen、server 与 location 块的解析函数 ngx_http_core_listen、ngx_http_core_server 和 ngx_http_core_location.


server 块解析 -- ngx_http_core_server

// static char *
// ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
// http server 块解析 {{{
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
  char            *rv;
  void            *mconf;
  ngx_uint_t          i;
  ngx_conf_t          pcf;
  ngx_http_module_t      *module;
  struct sockaddr_in     *sin;
  ngx_http_conf_ctx_t     *ctx, *http_ctx;
  ngx_http_listen_opt_t    lsopt;
  ngx_http_core_srv_conf_t  *cscf, **cscfp;
  ngx_http_core_main_conf_t  *cmcf;

  ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  if (ctx == NULL) {
    return NGX_CONF_ERROR;
  }

  http_ctx = cf->ctx;
  ctx->main_conf = http_ctx->main_conf;

  /* the server{}'s srv_conf */

 // 为所有 HTTP 模块分配空间存储 srv_conf
  ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->srv_conf == NULL) {
    return NGX_CONF_ERROR;
  }

  /* the server{}'s loc_conf */

 // 为所有 HTTP 模块分配空间存储 loc_conf
  ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->loc_conf == NULL) {
    return NGX_CONF_ERROR;
  }

 // 循环调用每个模块的 create_srv_conf 与 create_loc_conf 回调,创建配置结构
  for (i = 0; ngx_modules[i]; i++) {
    if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
      continue;
    }

    module = ngx_modules[i]->ctx;

    if (module->create_srv_conf) {
      mconf = module->create_srv_conf(cf);
      if (mconf == NULL) {
        return NGX_CONF_ERROR;
      }

      ctx->srv_conf[ngx_modules[i]->ctx_index] = mconf;
    }

    if (module->create_loc_conf) {
      mconf = module->create_loc_conf(cf);
      if (mconf == NULL) {
        return NGX_CONF_ERROR;
      }

      ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
    }
  }


  /* the server configuration context */

  cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
  cscf->ctx = ctx;


  cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];

  cscfp = ngx_array_push(&cmcf->servers);
  if (cscfp == NULL) {
    return NGX_CONF_ERROR;
  }

  *cscfp = cscf;


  /* parse inside server{} */

  pcf = *cf;
  cf->ctx = ctx;
  cf->cmd_type = NGX_HTTP_SRV_CONF;

 // 解析 server 块配置
  rv = ngx_conf_parse(cf, NULL);

  *cf = pcf;

 // 如果没有监听任何端口,则监听默认的 80 或 8000端口
  if (rv == NGX_CONF_OK && !cscf->listen) {
    ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));

    sin = &lsopt.u.sockaddr_in;

    sin->sin_family = AF_INET;
#if (NGX_WIN32)
    sin->sin_port = htons(80);
#else
    sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
#endif
    sin->sin_addr.s_addr = INADDR_ANY;

    lsopt.socklen = sizeof(struct sockaddr_in);

    lsopt.backlog = NGX_LISTEN_BACKLOG;
    lsopt.rcvbuf = -1;
    lsopt.sndbuf = -1;
#if (NGX_HAVE_SETFIB)
    lsopt.setfib = -1;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
    lsopt.fastopen = -1;
#endif
    lsopt.wildcard = 1;

    (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr,
               NGX_SOCKADDR_STRLEN, 1);

    if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
      return NGX_CONF_ERROR;
    }
  }

  return rv;
} // }}}