This is the 24th day of my participation in Gwen Challenge
background
This is the sixth Nginx learning notes collection, continuing the previous article with notes related to custom development of Nginx plug-ins
Custom development of Nginx plug-ins
Module context structure
The context structure of a module is stored in a static variable of type ngX_HTTP_module_T
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;
Copy the code
It is a pointer to a set of callback functions, including those that create objects that store configuration information, and those that are called before and after creation, all of which will be called by Nginx at the appropriate time
Postconfiguration: create_main_conf: create_main_conf: postconfiguration: create_main_conf: postconfiguration: create_main_conf: postconfiguration: create_main_conf Call this function to create the configuration information storage structure of the module in the HTTP block. On success, this function returns the created configuration object, on failure, NULL init_main_conf: Call this function to initialize the configuration information storage structure of the module in the HTTP block. On success, NGX_CONF_OK is returned; on failure, NGX_CONF_ERROR or create_srv_conf is returned: Call this function to create the configuration information store structure of the module in the HTTP server block. Each server block creates one. This function returns the created configuration object on success, and NULL merge_srv_conf on failure: Since some configuration instructions can appear in either HTTP Block or HTTP Server block, each server will have its own storage structure to store the configuration of that server, but in this case the configuration of the HTTP Block is the same as that of the server When configuration information in a block conflicts, this function needs to be called to merge. This function does not have to be provided, but it is not required to be provided when it is expected that the need to merge will never occur. For security purposes, this function returns NGX_CONF_OK on success and NGX_CONF_ERROR or create_loc_conf on failure: Call merge_loc_conf to create a configuration structure for each location specified in the configuration block. This function returns the created configuration object on success, or NULL on failure: Similar to merge_srv_conf, this is where configuration value merging takes place, returning NGX_CONF_OK on success and NGX_CONF_ERROR or an error string on failureCopy the code
Nginx configuration information is nested layer by layer, for a specific location, for the same configuration, if the current level is not defined, then use the upper level configuration, otherwise use the current level configuration This configuration information should be set to an uninitialized value by default. For this purpose,Nginx defines a series of macro definitions to represent the uninitialized value of the data type for each configuration:
#define NGX_CONF_UNSET -1
#define NGX_CONF_UNSET_UINT (ngx_uint_t) -1
#define NGX_CONF_UNSET_PTR (void *) -1
#define NGX_CONF_UNSET_SIZE (size_t) -1
#define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1
Copy the code
If have configured in this level, that is, the value of the configuration items have been read came in, just use the level of value as a result of incorporating definitions, otherwise, use the upper value, if the value of the upper and the UNSET the value of the class that is assigned as the default value, otherwise, use the upper value as a result of the merger, for such similar operations, Nginx defines a Some macro operations to do this, for example:
#define ngx_conf_merge_uint_value(conf, prev, default) \ if (conf == NGX_CONF_UNSET_UINT) { \ conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev; The \}Copy the code
Definition of a context named Hello module:
static ngx_http_module_t ngx_http_hello_module_ctx = {
NULL, /* preconfiguration */
ngx_http_hello_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_hello_create_loc_conf, /* create location configuration */
NULL /* merge location configuration */
};
Copy the code
Note: the merge_loc_conf function is not provided here, because the configuration instructions for this module are determined to occur only at the NGX_HTTP_LOC_CONF level, and no need to merge occurs
Module definition
Development module need to define a ngx_module_t variables of type information to illustrate the module itself, this is the module is one of the most important information, which tells the Nginx the module is some information, the above definition of configuration information, and module context information is through this structure to tell Nginx system, namely load module The upper layer code needs to get this information through the structure defined
Ngx_module_t structure definition:
typedef struct ngx_module_s ngx_module_t;
struct ngx_module_s {
ngx_uint_t ctx_index;
ngx_uint_t index;
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t abi_compatibility;
ngx_uint_t major_version;
ngx_uint_t minor_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;
};
#define NGX_NUMBER_MAJOR 3
#define NGX_NUMBER_MINOR 1
#define NGX_MODULE_V1 0, 0, 0, 0, \
NGX_DSO_ABI_COMPATIBILITY, NGX_NUMBER_MAJOR, NGX_NUMBER_MINOR
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
Copy the code
Example: The module definition of the Hello module
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context */
ngx_http_hello_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
};
Copy the code
Modules can provide callback functions to Nginx that are called when Nginx creates or terminates a process thread, but most modules don’t need to do anything at these times, so they simply assign the value NULL
Handler handler function
The handler module must provide a handler function for handling requests from clients. This function can either generate content directly, reject it and let subsequent handlers handle it, or dump it to a subsequent filter for processing
Function prototype declaration:
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
Copy the code
R is the HTTP request, which contains all the information requested The function returns NGX_OK on success, NGX_ERROR on error, and NGX_DECLINE on rejection. Otherwise, NGX_ERROR indicates that the response to the client has been generated
Mount the Handler module
The handler module’s handler functions are mounted to the process in two ways:
- Mount by processing stage
- According to the need to mount
Mount the Handler module by processing stage
In order to fine-control the processing of client requests,Nginx divides the processing into 11 stages, from front to back:
NGX_HTTP_POST_READ_PHASE: read request content phase NGX_HTTP_SERVER_REWRITE_PHASE: Server request address rewrite phase NGX_HTTP_FIND_CONFIG_PHASE: NGX_HTTP_REWRITE_PHASE: Location Request address rewrite phase NGX_HTTP_POST_REWRITE_PHASE: Request address rewrite submission phase NGX_HTTP_PREACCESS_PHASE: Access check Preparation phase NGX_HTTP_ACCESS_PHASE: Access check phase NGX_HTTP_POST_ACCESS_PHASE: Access check submission phase NGX_HTTP_TRY_FILES_PHASE: Try_files Processing phase NGX_HTTP_CONTENT_PHASE: content generation phase NGX_HTTP_LOG_PHASE: log module processing phaseCopy the code
Custom modules are mostly mounted in the NGX_HTTP_CONTENT_PHASE, and the mounting action is usually in the postConfiguration function called in the module context
Note: There are a few phases that are special in that they don’t call any of the handler’s at the mount point, so you don’t need to mount them:
NGX_HTTP_FIND_CONFIG_PHASE
NGX_HTTP_POST_ACCESS_PHASE
NGX_HTTP_POST_REWRITE_PHASE
NGX_HTTP_TRY_FILES_PHASE
Copy the code
So there are really seven phases to mount the handler
The mounted code is as follows:
static ngx_int_t
ngx_http_hello_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_hello_handler;
return NGX_OK;
}
Copy the code
Handlers mounted in this way are also called Content Phase Handlers
Mount handler modules as required
Handlers mounted in this way are also called content Handler, when a request comes in,Nginx executes all of the handlers in each phase, starting with the NGX_HTTP_POST_READ_PHASE phase, to the NGX_HTTP_CONTENT_PHASE phase if the location has a co Ntent Handler module, then execute the content Handler module’s actual handler function, otherwise continue to execute all content Phases in the NGX_HTTP_CONTENT_PHASE phase in sequence Handlers, until a function processing returns either NGX_OK or NGX_ERROR, i.e., when a location is processed to the NGX_HTTP_CONTENT_PHASE, if there is content Handler module, then all Content Phase Handlers mounted by NGX_HTTP_CONTENT_PHASE are not executed
The handler mounted using this method has a feature that it must be executed in the NGX_HTTP_CONTENT_PHASE phase. If you want your handler to be executed in an earlier phase, you should not mount this method
Use scenario: for example, when a module handles a location and finds that it is logical to handle it and there is no need to call other handlers in the NGX_HTTP_CONTENT_PHASE phase to handle it, it dynamically mounts this handler
Mount the sample
static char *
ngx_http_circle_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_circle_gif_handler;
return NGX_CONF_OK;
}
Copy the code
This section describes how to write handler modules
The steps to implement a Handler module;
- Write basic module structure: including module definition, module context structure, module configuration structure, etc
- Implement the mount function of handler: Select the correct mount party according to the requirements of the module
- Write the handler function: this function is used to complete the function of the module