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

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

location 块解析 -- ngx_http_core_location

// static char *
// ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
// location 块配置解析 {{{
static char *
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
  char           *rv;
  u_char          *mod;
  size_t           len;
  ngx_str_t         *value, *name;
  ngx_uint_t         i;
  ngx_conf_t         save;
  ngx_http_module_t     *module;
  ngx_http_conf_ctx_t    *ctx, *pctx;
  ngx_http_core_loc_conf_t *clcf, *pclcf;

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

  pctx = cf->ctx;
  ctx->main_conf = pctx->main_conf;
  ctx->srv_conf = pctx->srv_conf;

  ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->loc_conf == NULL) {
    return NGX_CONF_ERROR;
  }

  for (i = 0; ngx_modules[i]; i++) {
    if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
      continue;
    }

    module = ngx_modules[i]->ctx;

    if (module->create_loc_conf) {
      ctx->loc_conf[ngx_modules[i]->ctx_index] =
                          module->create_loc_conf(cf);
      if (ctx->loc_conf[ngx_modules[i]->ctx_index] == NULL) {
         return NGX_CONF_ERROR;
      }
    }
  }

  clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
  clcf->loc_conf = ctx->loc_conf;

  value = cf->args->elts;

  if (cf->args->nelts == 3) {

    len = value[1].len;
    mod = value[1].data;
    name = &value[2];

    if (len == 1 && mod[0] == '=') {

      clcf->name = *name;
      clcf->exact_match = 1;

    } else if (len == 2 && mod[0] == '^' && mod[1] == '~') {

      clcf->name = *name;
      clcf->noregex = 1;

    } else if (len == 1 && mod[0] == '~') {

      if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
      }

    } else if (len == 2 && mod[0] == '~' && mod[1] == '*') {

      if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
        return NGX_CONF_ERROR;
      }

    } else {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "invalid location modifier "%V"", &value[1]);
      return NGX_CONF_ERROR;
    }

  } else {

    name = &value[1];

    if (name->data[0] == '=') {

      clcf->name.len = name->len - 1;
      clcf->name.data = name->data + 1;
      clcf->exact_match = 1;

    } else if (name->data[0] == '^' && name->data[1] == '~') {

      clcf->name.len = name->len - 2;
      clcf->name.data = name->data + 2;
      clcf->noregex = 1;

    } else if (name->data[0] == '~') {

      name->len--;
      name->data++;

      if (name->data[0] == '*') {

        name->len--;
        name->data++;

        if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
          return NGX_CONF_ERROR;
        }

      } else {
        if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
          return NGX_CONF_ERROR;
        }
      }

    } else {

      clcf->name = *name;

      if (name->data[0] == '@') {
        clcf->named = 1;
      }
    }
  }

  pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];

  if (pclcf->name.len) {

    /* nested location */

#if 0
    clcf->prev_location = pclcf;
#endif

    if (pclcf->exact_match) {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "location "%V" cannot be inside "
                "the exact location "%V"",
                &clcf->name, &pclcf->name);
      return NGX_CONF_ERROR;
    }

    if (pclcf->named) {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "location "%V" cannot be inside "
                "the named location "%V"",
                &clcf->name, &pclcf->name);
      return NGX_CONF_ERROR;
    }

    if (clcf->named) {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "named location "%V" can be "
                "on the server level only",
                &clcf->name);
      return NGX_CONF_ERROR;
    }

    len = pclcf->name.len;

#if (NGX_PCRE)
    if (clcf->regex == NULL
      && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#else
    if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#endif
    {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "location "%V" is outside location "%V"",
                &clcf->name, &pclcf->name);
      return NGX_CONF_ERROR;
    }
  }

 // 将 location 配置加入到 locations 配置链表中
  if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
    return NGX_CONF_ERROR;
  }

  save = *cf;
  cf->ctx = ctx;
  cf->cmd_type = NGX_HTTP_LOC_CONF;

  rv = ngx_conf_parse(cf, NULL);

  *cf = save;

  return rv;
} // }}}