Analysis of nginx http block configuration

In the last article, we explained the storage structure of nginx http module, which is the cornerstone of our understanding of the working principle of http module. This article mainly explains how nginx builds the storage structure of http module step by step by parsing the http configuration block in nginx.conf.

1. Analysis of HTTP configuration block

The resolution method of http configuration block is defined in the NGX command T structure corresponding to http configuration block, as follows:

static ngx_command_t ngx_http_commands[] = {

    {ngx_string("http"),
     NGX_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS,
     ngx_http_block,
     0,
     0,
     NULL},

    ngx_null_command
};

From this definition, we can see that the parsing of HTTP configuration block is mainly done by ngx_http_block() method. The source code of this method is as follows:

static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
  char *rv;
  ngx_uint_t mi, m, s;
  ngx_conf_t pcf;
  ngx_http_module_t *module;
  ngx_http_conf_ctx_t *ctx;
  ngx_http_core_loc_conf_t *clcf;
  ngx_http_core_srv_conf_t **cscfp;
  ngx_http_core_main_conf_t *cmcf;

  if (*(ngx_http_conf_ctx_t **) conf) {
    return "is duplicate";
  }

  // Create an array of structures to store http module configuration data
  ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  if (ctx == NULL) {
    return NGX_CONF_ERROR;
  }

  *(ngx_http_conf_ctx_t **) conf = ctx;

  // Calculate the number of modules of NGX ﹣ http ﹣ module type, and assign a value to CTX ﹣ index of each module
  ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);

  // Apply to store the memory space of the main conf object
  ctx->main_conf = ngx_pcalloc(cf->pool,sizeof(void *) * ngx_http_max_module);
  if (ctx->main_conf == NULL) {
    return NGX_CONF_ERROR;
  }

  // Apply for memory space to store srv conf objects
  ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->srv_conf == NULL) {
    return NGX_CONF_ERROR;
  }

  // Request memory space to store loc conf objects
  ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->loc_conf == NULL) {
    return NGX_CONF_ERROR;
  }

  // Here, we call create main conf(), create SRV conf() and create LOC conf() of each http module respectively
  // Method to generate the configuration object of the corresponding module, and then place the generated object in CTX - > main conf, CTX - > SRV \ \ conf and CTX - > LOC \ \ conf
  // Array. It should be noted that when the generated object is placed in the corresponding array, the relative location is through the CTX - > index of each module
  // Property, that is, its relative position in the module of the current type
  for (m = 0; cf->cycle->modules[m]; m++) {
    if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }

    // For the http module, the ctx field here points to an NGX http module structure object
    module = cf->cycle->modules[m]->ctx;
    mi = cf->cycle->modules[m]->ctx_index;

    if (module->create_main_conf) {
      // Here, the main conf corresponds to the instruction of type NGX, http, main, conf, offset in the http block
      ctx->main_conf[mi] = module->create_main_conf(cf);
      if (ctx->main_conf[mi] == NULL) {
        return NGX_CONF_ERROR;
      }
    }

    if (module->create_srv_conf) {
      // The SRV conf here corresponds to the instruction of type NGX http SRV conf offset in the http block
      ctx->srv_conf[mi] = module->create_srv_conf(cf);
      if (ctx->srv_conf[mi] == NULL) {
        return NGX_CONF_ERROR;
      }
    }

    if (module->create_loc_conf) {
      // Here, LOC conf corresponds to the instruction of parsing NGX http SRV conf offset type in http block
      ctx->loc_conf[mi] = module->create_loc_conf(cf);
      if (ctx->loc_conf[mi] == NULL) {
        return NGX_CONF_ERROR;
      }
    }
  }

  pcf = *cf;
  cf->ctx = ctx;  // Here ctx is of type NGX? HTTP? Conf? ctx? T

  for (m = 0; cf->cycle->modules[m]; m++) {
    if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }

    module = cf->cycle->modules[m]->ctx;

    // This is mainly to call the preconfiguration() method of each module for pre configuration,
    // As you can see, the preconfiguration() method here is mainly called before parsing the http module
    if (module->preconfiguration) {
      if (module->preconfiguration(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
      }
    }
  }
  
  cf->module_type = NGX_HTTP_MODULE;
  cf->cmd_type = NGX_HTTP_MAIN_CONF;
  // Because the http block is parsed here, filename does not need to pass values, and only needs to start parsing according to the current location.
  // Note that after calling this method, the initialization method of each configuration item is resolved
  // In addition, it should be noted that the current parsing is the http module. After calling here, the sub modules of the http module will be parsed, that is to say,
  // After the current method call, the server, location and other modules have been resolved
  rv = ngx_conf_parse(cf, NULL);

  if (rv != NGX_CONF_OK) {
    goto failed;
  }
  
  for (m = 0; cf->cycle->modules[m]; m++) {
    if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }

    // ngx_http_module_t
    // mi records the CTX [u] index of the configuration of the currently traversed module, that is, the corresponding location of the configuration created by the module parameter
    // Note that the module object here only defines the methods that the current module needs to execute for the corresponding process processing, and there is no data object related to the specific module stored inside
    module = cf->cycle->modules[m]->ctx;
    mi = cf->cycle->modules[m]->ctx_index;

    /* init http{} main_conf's */

    if (module->init_main_conf) {
      // The main task here is to initialize the data objects of each module. For example, for some parameters, the configuration file does not configure the related properties. The default value will be set here
      rv = module->init_main_conf(cf, ctx->main_conf[mi]);
      if (rv != NGX_CONF_OK) {
        goto failed;
      }
    }

    // This is mainly to merge the configuration objects of each module, because some configuration items can be configured in either http block or server block,
    // It can also be configured in the location block. Here, the corresponding configuration blocks will be merged according to the requirements of the current module
    rv = ngx_http_merge_servers(cf, cmcf, module, mi);
    if (rv != NGX_CONF_OK) {
      goto failed;
    }
  }
  
  // Omit part of code
  
  // Call the postconfiguration() method of each module for processing after the configuration analysis is completed
  for (m = 0; cf->cycle->modules[m]; m++) {
    if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }

    module = cf->cycle->modules[m]->ctx;

    if (module->postconfiguration) {
      if (module->postconfiguration(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
      }
    }
  }
  
  // Omit some codes
  
  return NGX_OK;
}

The source code of the ngx_http_block() method shown here only shows the code related to the initialization of the HTTP module structure. The omitted code will be explained in later articles. The NGX ﹣ http ﹣ block() method can be said to be the entry method for parsing HTTP configuration blocks. This method is mainly completed as follows:

  • Create a structure for storing the configuration data of the entire HTTP module, NGX ﹣ http ﹣ conf ﹣ CTX ﹣ T;
  • Calculate the number of currently owned http modules, and initialize the value of CTX ﹣ index attribute in each module, mark it as the relative position of the module in all http modules, which also corresponds to the positions of the current module in the main ﹣ conf, SRV ﹣ conf and LOC ﹣ conf arrays to be explained later;
  • Apply memory space for the main conf, SRV conf and LOC conf arrays of the created NGX ﹣ http ﹣ conf ﹣ CTX ﹣ T structure, and the length of these arrays is the number of all HTTP modules calculated previously;
  • Traverse all modules. As long as they are http modules, call their create ﹣ main ﹣ conf(), create ﹣ SRV ﹣ conf(), and create ﹣ LOC ﹣ conf() methods in turn to create configuration item structures in each module for storing http configuration blocks. Note that the attributes of these structures are only default data at this time;
  • Traverse all http modules, call their preconfiguration() method to preprocess the configuration file before parsing;
  • Call the NGX ﹣ conf ﹣ parse() method to continue to parse the HTTP configuration block. The parsing here is actually to parse the sub configuration items in the HTTP configuration block, including not only the basic configuration items, but also the configuration blocks such as server and location. After the current method call is completed, the entire http configuration block has been resolved;
  • Traverse all HTTP modules, call its init main conf() method to set default values for configuration structure attributes of each module. Since the HTTP configuration block has been parsed in the previous step, the configured attributes in the configuration file already have values. The init main conf() method here mainly sets default values for those attributes that are not configured. When initializing the configuration items of each module, NGX ﹣ http ﹣ merge ﹣ servers() is also called to merge the configuration items. Its main function is to select which value is the valid value when a configuration item is configured in two or more configuration blocks of HTTP block, server block or location block. Here, we will explain the merging principle in the following article;
  • Traverse each http module, call its postconfiguration() method, and process after configuration analysis.

The above method can be said to process the whole process of parsing http configuration block. The entry here mainly initializes some data structures, and the final parsing of each configuration item is mainly done by NGX ﹣ conf ﹣ parse() method. It includes the parsing of server block and location block.

2. Analysis of server configuration block

For the resolution of the server block, the configuration of its corresponding NGX ﹣ command ﹣ T structure is as follows:

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

As you can see, the parsing of the server block is mainly done by the method NGX ﹣ http ﹣ core ﹣ server(). The source code of this method is as follows:

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;
  }

  // Here, the type of HTTP ABCD CTX is NGX ABCD HTTP ABCD conf ABCD CTX ABCD structure, which stores three main ABCD conf, SRV ‐ conf and LOC ‐ conf
  // We need to pay special attention to the array of attributes. In CT - > CTX, it is also a structure of NGX ﹣ http ﹣ conf ﹣ CTX ﹣ T type. This attribute parses http
  // The module has been initialized, that is to say, CTX - > main \ \ conf = http \ \ CTX - > main \ \ conf; it is a newly created module
  // The main conf of ctx points to the main conf of the http module in which it is located, so it can be reused.
  // It can be seen from this that when nginx parses each server block, it will create a new NGX ﹣ http ﹣ conf ﹣ T structure for each server block,
  // It is used to store the current server block to be resolved, and the main conf of the structure will point to the main conf of the http block where the current server block is located,
  // This can save memory, and another advantage of this is that when the configuration of the server and the http configuration block is merged in the future,
  // It is only necessary to call the corresponding merging method in the corresponding structure of each server block.
  http_ctx = cf->ctx; // NGX ﹣ http ﹣ conf ﹣ T structure storing HTTP blocks
  ctx->main_conf = http_ctx->main_conf;

  // Request memory for the current server block to be resolved
  ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->srv_conf == NULL) {
    return NGX_CONF_ERROR;
  }

  // Request memory for location
  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; cf->cycle->modules[i]; i++) {
    if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
      continue;
    }

    module = cf->cycle->modules[i]->ctx;

    // Call the create ﹣ SRV ﹣ conf() method of each module to create the structure object needed by each module to store data
    if (module->create_srv_conf) {
      mconf = module->create_srv_conf(cf);
      if (mconf == NULL) {
        return NGX_CONF_ERROR;
      }

      ctx->srv_conf[cf->cycle->modules[i]->ctx_index] = mconf;
    }

    // Call the create? LOC? Conf() method of each module to create the structure object needed by each module to store data
    if (module->create_loc_conf) {
      mconf = module->create_loc_conf(cf);
      if (mconf == NULL) {
        return NGX_CONF_ERROR;
      }

      ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
    }
  }

  // Here, NGX ﹣ http ﹣ core ﹣ module is the module definition of the server configuration item, and here is a configuration object to obtain the module,
  // That is, an object of type NGX? HTTP? Core? SRV? Conf? T.
  // Here, the value of NGX ﹣ http ﹣ core ﹣ module.ctx ﹣ index is 0
  cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
  cscf->ctx = ctx;

  // Get the configuration object of the core module. The main conf here only points to the main conf array created by the http block, so here
  // It also gets the same core module configuration object used in the http module
  cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];

  // Set the currently created
  cscfp = ngx_array_push(&cmcf->servers);
  if (cscfp == NULL) {
    return NGX_CONF_ERROR;
  }

  *cscfp = cscf;

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

  // Here we start to parse the rest of the configuration items, such as the location configuration block
  rv = ngx_conf_parse(cf, NULL);

  *cf = pcf;

  if (rv == NGX_CONF_OK && !cscf->listen) {
    // The main task here is to create an NGX HTTP listen opt structure and initialize each attribute
    ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));

    sin = &lsopt.sockaddr.sockaddr_in;

    sin->sin_family = AF_INET;
#if (NGX_WIN32)
    sin->sin_port = htons(80);
#else
    // If the current user does not have permission for port 80, use port 8000
    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;

    // This is mainly to organize the current address and port type into lsopt.sockaddr.sockaddr
    (void) ngx_sock_ntop(&lsopt.sockaddr.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;
}

For the resolution of the server configuration block, it is mainly divided into the following steps:

  • To create a structure array for storing configuration items of SRV type and LOC type modules, it should be noted that there is no structure array for storing MAIN type modules. Since the configuration items are configured in the server block, it must not be of MAIN type, so here we only point the MAIN \ \ conf to the MAIN \ \ conf array of http block;
  • Call the create ﹣ SRV ﹣ conf() method and create ﹣ LOC ﹣ conf() method of each http module in turn, and create configuration structures for storing SRV type and LOC type of these modules;
  • Find the configuration structure of the core module in the configuration array obtained by parsing the HTTP module, add the NGX ﹣ http ﹣ core ﹣ SRV ﹣ conf ﹣ structure corresponding to the current server block to the servers array of the configuration structure of the core module, in this way, associate the structure obtained by parsing the HTTP configuration block with the structure obtained by parsing each server block;
  • Call the NGX ﹣ conf ﹣ parse() method to continue to parse the sub configuration items under the current server block, including each sub location. After the current method is called, it means that the parsing of the current server block has been completed;
  • Add the port to be monitored configured in the current server block to the existing port list for subsequent monitoring;

3. Analysis of location configuration block

The processing of location configuration block resolution is essentially similar to that of server block, but the url matching rule specified after location configuration item will be processed in the process of location configuration block resolution, and whether the current matching rule uses regular expression will be judged. In addition, when parsing the location configuration block, it should be noted that there can be multiple sub location configuration blocks inside the location configuration block. These sub location configuration blocks are equivalent to a supplement to the configuration of the parent location configuration block. As for the number of levels of the sub location configuration blocks, nginx has no limit. The following is the NGX command T structure that defines the location configuration block:

{
  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
}

It can be seen that the parsing of the location configuration block here is mainly done by the ngx_http_core_location() method. The source code of this method is as follows:

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;

  // A ctx object is created here to store and parse the attribute values in the current location configuration block
  ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  if (ctx == NULL) {
    return NGX_CONF_ERROR;
  }

  pctx = cf->ctx;
  // Here, point the main conf and SRV conf of the current ctx to the corresponding structure object of the server and http block where the current location block is located
  ctx->main_conf = pctx->main_conf;
  ctx->srv_conf = pctx->srv_conf;

  // Apply space for LOC ﹣ conf to store the attribute values of each module obtained by parsing the current location block
  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; cf->cycle->modules[i]; i++) {
    if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
      continue;
    }

    module = cf->cycle->modules[i]->ctx;
    // If the create? LOC? Conf() method of the current module is not empty, call this method to generate the corresponding configuration
    if (module->create_loc_conf) {
      ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = module->create_loc_conf(cf);
      if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) {
        return NGX_CONF_ERROR;
      }
    }
  }

  // Get the value of LOC ﹣ conf of the core module
  clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
  // This is actually to point the core module's LOC conf to the corresponding LOC conf value of the current location block
  clcf->loc_conf = ctx->loc_conf;

  // Here, elts is the number of parameters in the location configuration block, such as
  // location / {
  //            root   html;
  //        }
  // So the number of parameters here is 2, which are location and/
  // Here we need to explain the syntax of location first:
  // - Syntax:
  //  location [=|~|~*|^~] uri {...}
  //  location @name {...}
  //-Rules of use:
  //  -Prefix string match:
  //    -Regular strings, such as' / html ', match URI s prefixed with' / html ';
  //    -'=': exact match, then the URI must be equal to the following string;
  //    -'^ ~': if it is matched, regular expression matching will not be carried out any more;
  //  -Regular expression matching:
  //    -'~': case sensitive regular matching;
  //    -'~ *': ignore regular matching of case;
  //  -Named location for internal jump:
  //    - `@`
  //  -Merge consecutive '/' symbols:
  //    - `merge_slashes on;`
  value = cf->args->elts;

  // Determine whether the number of current parameters is 3
  if (cf->args->nelts == 3) {

    // Here, the parameter with subscript 1 is the second parameter
    len = value[1].len;
    mod = value[1].data;
    name = &value[2];

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

      // Here, the exact match field indicates whether the current matching method is a perfect match,
      // Since it is currently = operation, it is marked as 1
      clcf->name = *name;
      clcf->exact_match = 1;

      // If it is ^ ~, regular matching will not be performed
    } else if (len == 2 && mod[0] == '^' && mod[1] == '~') {

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

      // If it is ~, it means it is a case sensitive regular match
    } else if (len == 1 && mod[0] == '~') {

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

      // If it is ~ *, it means it is a case insensitive regular match
    } 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 {

    // Here, the function of else branch is basically the same as that of if branch above. The main difference is that the second and third elements are allowed to be
    // There is no space. In addition, the following else branch also deals with the case that the parameter after location starts with the @ sign,
    // In this case, the current request will be forwarded to other location s
    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;

      // Handling cases starting with the @ symbol
      if (name->data[0] == '@') {
        clcf->named = 1;
      }
    }
  }

  // If the current location is embedded in a location, pclcf points to the resolution value of the parent location,
  // If there is no parent location, then the CF - > CMD? Type here is not equal to NGX? HTTP? LOC? Conf
  pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];

  if (cf->cmd_type == NGX_HTTP_LOC_CONF) {

    /* nested location */

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

    // If the parent location is an exact match, it cannot have a child location
    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 the parent location uses @ for redirection, it cannot have a child location
    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;
    }

    // Locations redirected with @ are only allowed under the server block, not in nested child location s
    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)
    // Here len is the length of the expression of the parent location, so here is to compare whether the child location starts with the parent location as the prefix,
    // If not, an exception is returned
    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;
    }
  }

  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;

  // Continue resolving submodule configuration for profile
  rv = ngx_conf_parse(cf, NULL);

  *cf = save;

  return rv;
}

Here, the analysis of the location configuration block is mainly divided into the following steps:

  • Apply for the structure array used to store the configuration items of each module in the location configuration block, and save it to the LOC conf attribute, while its main conf and SRV conf are directly inherited from the main conf and SRV conf of the corresponding structure of the server block where the current location block is located;
  • Call the create LOC conf() method of each http module in turn to create a structure for storing configuration items of each module;
  • Parse the expression used to match the url after the location configuration item;
  • Check the parent-child location. For example, if the parent location is exactly matched, there can be no child location at this time. This verification is mainly used in the case of nested locations;
  • Continue to call the NGX ﹣ conf ﹣ parse() method to resolve the sub configuration items under the current location configuration block, including the sub location resolution. It can be seen that the parsing process of sub location here is actually a recursive parsing process, and the method used for parsing is the above ngx_http_core_location() method.

4. summary

This paper mainly explains how nginx parses http block, server block and location block from the source point of view, and focuses on how it constructs the configuration structure of nginx http module.

Keywords: Programming Nginx Attribute REST

Added by xposed on Tue, 18 Feb 2020 06:21:52 +0200