Nginx introduces the five filter modules and implements a simple filter module

Source: Internet
Author: User

1 nginx filter module Introduction

The filter module filters response headers and content. It can process the response headers and content. After obtaining the reply content,
Before sending a response to the user. The processing process is divided into two phases: filter the HTTP response header and body. In these two phases, you can
.

2. filter module execution sequence

2.1 ngx_http_output _ (Head, body) _ filter_pt

Let's take a look at the common filtering modules of nginx. The code in ngx_moudles.c is as follows:

ngx_module_t *ngx_modules[] = {   ......    &ngx_http_write_filter_module,    &ngx_http_header_filter_module,    &ngx_http_chunked_filter_module,    &ngx_http_range_header_filter_module,    &ngx_http_gzip_filter_module,    &ngx_http_postpone_filter_module,    &ngx_http_ssi_filter_module,    &ngx_http_charset_filter_module,    &ngx_http_userid_filter_module,    &ngx_http_myfilter_module,    &ngx_http_headers_filter_module,    &ngx_http_copy_filter_module,    &ngx_http_range_body_filter_module,    &ngx_http_not_modified_filter_module,    NULL};


The execution sequence of the nginx filter module is from ngx_http_not_modified_filter_module to ngx_http_write_filter_module. Next let's take a look at this execution

The sequence is composed of linked lists.

Since it is made up of linked lists, there must be a linked list pointer, and there are two functions, one for processing the header, and the other for processing the package body. Let's take a look at these two functions.

Definition of linked list pointers:

typedef ngx_int_t (ngx_http_output_header_filter_pt)(ngx_http_request_t *r);typedef ngx_int_t (ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *in);


Ngx_http_output_header_filter_pt points to the function pointer to the processing header. If you want to process the header in each filter module, you must define a local pointer and function of this type.

Ngx_http_output_body_filter_pt points to the function pointer for processing the package body. If you want to process the package body in each filter module, you must define a local pointer and function of this type.

2.2 entry to the filter module linked list

The entry to the filter module linked list is two static function pointers:

extern ngx_http_output_header_filter_pt ngx_http_top_header_filter; extern ngx_http_output_body_filter_pt   ngx_http_body_body_filter;


When ngx_http_send_header is executed to send an HTTP header, the ngx_http_tou_header_filter pointer is used to traverse all HTTP header filter modules.

Ngx_http_send_header:

Ngx_int_t ngx_http_send_header (ngx_http_request_t * r) {If (R-> err_status) {r-> headers_out.status = r-> err_status; r-> priority = 0;} return response (R ); // The linked list header pointing to the module function of the first filter header}


When ngx_http_output_filter is executed to send the package body, the ngx_http_top_body_filter pointer is used to traverse all HTTP packet body filtering modules.

Ngx_http_output_filter:

Ngx_int_t ngx_http_output_filter (ngx_http_request_t * r, ngx_chain_t * In) {ngx_int_t RC; ngx_connection_t * C; C = r-> connection; rc = accept (R, In ); if (rc = ngx_error) {C-> error = 1;} return RC; // head of the linked list, pointing to the module function of the first filter package}

So how does nginx use ngx_http_top_header_filter and ngx_http_top_body_filter to link all the modules that filter headers with all the modules that filter packets?

2.3 filter module links

Originally, each filter module defined two static function pointers (assuming that each filter module processes the header and package body:

static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt   ngx_http_next_body_filter;


Ngx_http_next_header_filter to save the processing module function pointed to by ngx_http_top_header_filter, while ngx_http_top_header_filter points to the filtering function of the processing header of this module.

Ngx_http_next_body_filter to save the processing module function pointed to by ngx_http_top_body_filter, while ngx_http_top_body_filter points to the filtering function of the Processing Package body of this module.

The Code is as follows:

Ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = response; // filter function for processing headers ngx_http_next_body_filter = response; response = response; // filter function for processing the package body


In this way, all the filter modules are linked.

For example, two filter modules, filter_a, filter_ B, and filter_a, are defined first, and then filter_ B.

The following code is available in filter_a:

ngx_http_next_header_filter_a = ngx_http_top_header_filter;ngx_http_top_header_filter  = ngx_http_filtera_header_filter;ngx_http_next_body_filter_a   = ngx_http_top_body_filter;ngx_http_top_body_filter    = ngx_http_filtera_body_filter;


Note that ngx_http_header_filter points to the header processing function of filter_a, and ngx_http_top_body_filter points to the package processing function of filter_a.

The following code is available in filter_ B:

ngx_http_next_header_filter_b = ngx_http_top_header_filter;ngx_http_top_header_filter  = ngx_http_filterb_header_filter;ngx_http_next_body_filter_b   = ngx_http_top_body_filter;ngx_http_top_body_filter    = ngx_http_filterb_body_filter;

In this case, ngx_http_next_header_filter_ B will save the ngx_http_filtera_header_filter, that is, the filter function pointing to the processing header in the filelist. The filter linked list of the filelist and filterb will be established.

Similarly, ngx_http_next_body_filter_ B stores the ngx_http_filterb_body_filter, that is, the filter function that points to the Processing Package body in the filelist. The filelist and filterb package body filter linked lists are established.

At this time, ngx_http_top_header_filter stores the filterb header filter function, while ngx_http_top_body_filter stores the filterb package body filter function.

When we implement the filterb header filter function, the code is usually as follows:

Ngx_int_t handle (ngx_http_request_r * r) {// code for processing the header... return ngx_http_next_header_filter_ B (R, In); // call the function of the filelist to process the header}

The code for implementing the filterb package filtering function is usually as follows:

Ngx_int_t ngx_http_next_body_filter_ B (ngx_http_request_t * r, ngx_chain_t * In) {// process the code of the package ...... return ngx_http_header_filter_ B (R, In); // call the filelist function to process the package body}

In this way, the module filelist and module filterb are connected in tandem, and the execution of filterb is prior to the execution of filterb, which explains why the execution of the module in section 2.1 is in reverse order.

Assume that the modules filterc and filterd are all linked to the two linked lists in the form of filelist and filterb links.

3. Implement a simple filter module

Implement a simple filter module to add a string "[my filter prefix]" to the header.

3.1config:

ngx_addon_name=ngx_http_myfilter_moduleHTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_myfilter_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_myfilter_module.c"

Note the difference with handler module: http_filter_modules = "$ http_filter_modules ngx_http_myfilter_module"

At the beginning, I jumped into the trap and looked for it for a long time. It was not the http_modules written in the handler module.

3.2 code writing

In fact, the implementation is quite simple and involves several steps:

1) Implementation of three module structs: ngx_command_t, ngx_http_moudle_t, and ngx_moudle_t

2) link the filter function of the current processing header and package body to a linked list.

3) Implement the filter header function and the filter package body function respectively.

Step 1 code:

Typedef struct {ngx_flag_t arg_flag;} struct; typedef struct {ngx_int_t flag_count;} struct; static ngx_str_t filter_prefix = ngx_string ("[my filter prefix]"); // static: These two variables are valid only in the current file: static variable ngx_http_next_header_filter; static variable; static char * ngx_http_myfilter_set (ngx_conf_t * Cf, ngx_command_t * cmd, void * conf ); static void * Forward (ngx_conf_t * Cf); static char * Forward (ngx_conf_t * Cf, void * parent, void * child); static ngx_int_t ngx_http_myfilter_post_config (ngx_conf_t * Cf ); static ngx_int_t values (optional * r); static ngx_int_t values (ngx_http_request_t * r, ngx_chain_t * In); static ngx_command_t values [] ={{ ngx_string ("add_prefix "), ngx_http_loc_conf | ngx_conf_flag, delimiter, delimiter, offsetof (delimiter, arg_flag), null}, ngx_null_command}; static ngx_http_module_t delimiter = {null, delimiter, null, empty, empty, required}; ngx_module_t ngx_http_myfilter_module = {ngx_module_v1, & tags, metrics, ngx_http_module, null, ngx_module_v1_padding };

Step 2 code:

static ngx_int_t ngx_http_myfilter_post_config(ngx_conf_t *cf){ngx_http_next_header_filter = ngx_http_top_header_filter;    ngx_http_top_header_filter  = ngx_http_myfilter_header_filter;    ngx_http_next_body_filter   = ngx_http_top_body_filter;    ngx_http_top_body_filter    = ngx_http_myfilter_body_filter;    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "post config is called!");        return NGX_OK;}

Step 3 code:

Static ngx_int_t ngx_http_myfilter_header_filter (ngx_http_request_t * r) {If (R-> headers_out.status! = Ngx_http_ OK) {ngx_log_error (ngx_log_emerg, R-> connection-> log, 0, "headers_out.status = % d", R-> headers_out.status); Return ngx_http_next_header_filter (r );} optional * mlcf; mlcf = random (R, ngx_http_myfilter_module); If (mlcf-> arg_flag = 0) // flag = 0, indicating that the prefix {ngx_log_error (ngx_log_emerg, r-> connection-> log, 0, "arg_flag = 0"); Return ngx_http_next_header_filte R (r);} ngx_http_myfilter_ctx_t * mctx; mctx = ngx_http_get_module_ctx (R, ngx_http_myfilter_module); If (mctx! = NULL) // mctx is not empty, indicating that this header has been processed and cannot be processed again {return ngx_http_next_header_filter (r);} mctx = ngx_pcalloc (R-> pool, sizeof (distinct); If (mctx = NULL) {return ngx_error;} ngx_http_set_ctx (R, mctx, ngx_http_myfilter_module); mctx-> flag_count = 0; // 0: the initialization is not prefixed with ngx_str_t type = ngx_string ("text/plain"); If (R-> headers_out.content_type.len> = type. len & ngx_strncasecmp (R-> headers_out.content_type.data, Type. data, type. len) = 0) {mctx-> flag_count = 1; // 1: prefix if the header type is "text/plain" (R-> headers_out.content_length_n> 0) {r-> response + = filter_prefix.len;} return ngx_http_next_header_filter (r);} static ngx_int_t forward (ngx_http_request_t * r, ngx_chain_t * In) {callback * mctx; mctx = ngx_http_get_module_ctx (R, ngx_http_myfilter_module); If (mctx = Null | mctx-> flag_count! = 1) {return ngx_http_next_body_filter (R, In);} mctx-> flag_count = 2; ngx_buf_t * Buf = ngx_create_temp_buf (R-> pool, filter_prefix.len ); buf-> Start = filter_prefix.data; Buf-> Pos = filter_prefix.data; Buf-> last = filter_prefix.data + filter_prefix.len; ngx_chain_t * out = cursor (R-> pool ); out-> Buf = Buf; out-> next = In; return ngx_http_next_body_filter (R, out );}


Http://blog.csdn.net/xiaoliangsky/article/details/39522357


For the complete code, refer:

# Include <ngx_config.h> # include <ngx_core.h> # include <ngx_http.h> typedef struct {ngx_flag_t arg_flag;} identifier; typedef struct {ngx_int_t flag_count;} identifier; static ngx_str_t filter_prefix = ngx_string ("[my filter prefix]"); // static: These two variables are valid only in the current file. Static: ngx_http_next_header_filter; static: ngx_http_nex T_body_filter; static char * ngx_http_myfilter_set (ngx_conf_t * Cf, ngx_command_t * cmd, void * conf); static void * Forward (ngx_conf_t * Cf); static char * Forward (ngx_conf_t * Cf, void * parent, void * child); static ngx_int_t ngx_http_myfilter_post_config (ngx_conf_t * Cf); static ngx_int_t forward (ngx_http_request_t * r); static ngx_int_t Returns (returns * r, ngx_chain_t * In); static ngx_command_t Returns [] ={{ ngx_string ("add_prefix"), ngx_http_loc_conf | ngx_conf_flag, expires, expires, offsetof (outputs, arg_flag), null}, ngx_null_command}; static ngx_http_module_t ngx_http_myfilter_module_ctx = {null, ngx_http_myfilter_post_con Fig, null, empty, empty}; ngx_module_t ngx_http_myfilter_module = {ngx_module_v1, & empty, empty, ngx_http_module, null, null, ngx_module_v1_padding}; static ngx_int_t ngx_http_myfilter_post_config (ngx_conf_t * Cf) {ngx_http_next_header_filter = ngx_http_top_header_filter; n Gx_http_top_header_filter = response; ngx_http_next_body_filter = response; ngx_http_top_body_filter = response; ngx_conf_log_error (ngx_log_emerg, CF, 0, "post config is called! "); Return ngx_ OK;} static char * ngx_http_myfilter_set (ngx_conf_t * Cf, ngx_command_t * cmd, void * conf) {symbol * mlcf = conf; char * rc = ngx_conf_set_flag_slot (CF, CMD, conf); ngx_conf_log_error (ngx_log_emerg, CF, 0, "arg_flag = % d", mlcf-> arg_flag); Return RC;} static void * handle (ngx_conf_t * Cf) {ngx_http_myfilter_loc_conf_t * mlcf; mlcf = ngx_pcalloc (CF-> Pool, sizeof (ngx_http_myfilter_loc_conf_t); If (mlcf = NULL) {return NULL;} mlcf-> arg_flag = ngx_conf_unset; return mlcf ;} static char * cursor (ngx_conf_t * Cf, void * parent, void * Child) {prop * Prev = parent; ngx_http_myfilter_loc_conf_t * conf = Child; ngx_conf_merge_value (conf-> arg_flag, prev-> arg_flag, 0); Return ngx_conf_ OK;} static ngx_int_t ngx_ht Tp_myfilter_header_filter (ngx_http_request_t * r) {If (R-> headers_out.status! = Ngx_http_ OK) {ngx_log_error (ngx_log_emerg, R-> connection-> log, 0, "headers_out.status = % d", R-> headers_out.status); Return ngx_http_next_header_filter (r );} optional * mlcf; mlcf = random (R, ngx_http_myfilter_module); If (mlcf-> arg_flag = 0) // flag = 0, indicating that the prefix {ngx_log_error (ngx_log_emerg, r-> connection-> log, 0, "arg_flag = 0"); Return ngx_http_next_header_filte R (r);} ngx_http_myfilter_ctx_t * mctx; mctx = ngx_http_get_module_ctx (R, ngx_http_myfilter_module); If (mctx! = NULL) // mctx is not empty, indicating that this header has been processed and cannot be processed again {return ngx_http_next_header_filter (r);} mctx = ngx_pcalloc (R-> pool, sizeof (distinct); If (mctx = NULL) {return ngx_error;} ngx_http_set_ctx (R, mctx, ngx_http_myfilter_module); mctx-> flag_count = 0; // 0: the initialization is not prefixed with ngx_str_t type = ngx_string ("text/plain"); If (R-> headers_out.content_type.len> = type. len & ngx_strncasecmp (R-> headers_out.content_type.data, Type. data, type. len) = 0) {mctx-> flag_count = 1; // 1: prefix if the header type is "text/plain" (R-> headers_out.content_length_n> 0) {r-> response + = filter_prefix.len;} return ngx_http_next_header_filter (r);} static ngx_int_t forward (ngx_http_request_t * r, ngx_chain_t * In) {callback * mctx; mctx = ngx_http_get_module_ctx (R, ngx_http_myfilter_module); If (mctx = Null | mctx-> flag_count! = 1) {return ngx_http_next_body_filter (R, In);} mctx-> flag_count = 2; ngx_buf_t * Buf = ngx_create_temp_buf (R-> pool, filter_prefix.len ); buf-> Start = filter_prefix.data; Buf-> Pos = filter_prefix.data; Buf-> last = filter_prefix.data + filter_prefix.len; ngx_chain_t * out = cursor (R-> pool ); out-> Buf = Buf; out-> next = In; return ngx_http_next_body_filter (R, out );}

Note: Because the type of the processing header is "text/plain", it is valid to access TXT text.

Create a test.txt file in the nginx/html file with the content hhhhh.

Enter localhost/test.txt in the browser.


Nginx introduces the five filter modules and implements a simple filter module

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.