"Nginx" develops an HTTP filtering module

Source: Internet
Author: User
Tags response code

differs from HTTP processing module. The HTTP Filtering module works by doing some processing of the HTTP response sent to the user.

A response returned by the server can be handled sequentially by multiple HTTP filtering modules in a sequential manner. The HTTP response is divided into headers and packages, and the Ngx_http_send_header and Ngx_http_output_filter functions are responsible for sending headers and packages respectively. They call each filter module in turn to treat the sent response.
The HTTP filtering module can handle both the head of the response or the package individually or at the same time. The method prototypes for handling headers and packages are, for example, the following, which are defined in the HTTP Framework module Ngx_http_core_module.h:

Filter module Processing HTTP header method prototype typedef ngx_int_t (*NGX_HTTP_OUTPUT_HEADER_FILTER_PT) (ngx_http_request_t *r); The filtering module deals with the method prototype of the HTTP packet body typedef ngx_int_t (*NGX_HTTP_OUTPUT_BODY_FILTER_PT) (ngx_http_request_t *r, ngx_chain_t *chain);


Above is the declaration of two function pointers, the HTTP filter module is dependent on such a pointer string into a single-linked list, each HTTP filter module at least one of the above function pointers defined. The entry list is as follows:
HTTP Filter Module link list entry extern ngx_http_output_header_filter_pt  Ngx_http_top_header_filter;extern ngx_http_output_body _filter_pt    Ngx_http_top_body_filter;


When the HTTP module calls Ngx_http_send_header to send the header, it starts by traversing the entire HTTP header filtering module from the Ngx_http_top_header_filter point to the module and processing; When the HTTP module calls NGX_HTTP_ Output_filter when sending the package body. Start by traversing the entire HTTP packet filtering module and processing from the module that the Ngx_http_top_body_filter points to. The function Ngx_http_send_header code such as the following:
Ngx_int_tngx_http_send_header (ngx_http_request_t *r) {    if (r->header_sent) {        Ngx_log_error (NGX_LOG_ ALERT, R->connection->log, 0,                      "header already sent");        return ngx_error;    }     if (r->err_status) {        r->headers_out.status = r->err_status;        R->headers_out.status_line.len = 0;    }     Traverse the HTTP Header filter module from the beginning to    return Ngx_http_top_header_filter (r);}


The function Ngx_http_top_header_filter code such as the following:
Ngx_int_tngx_http_output_filter (ngx_http_request_t *r, ngx_chain_t *in) {    ngx_int_t          RC;    ngx_connection_t  *c;     c = r->connection;     Ngx_log_debug2 (ngx_log_debug_http, C->log, 0,                   "HTTP output filter \"%v?%v\ "", &r->uri, &r->args) ;     Traverse the HTTP Package Body Filter module    rc = Ngx_http_top_body_filter (R, in);     if (rc = = ngx_error) {/* Ngx_error May is returned by any        filter */        c->error = 1;    }     return RC;}


At least one of the above two function pointers exists in each HTTP filter module. Declarations such as the following:
Static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;static ngx_http_output_body_filter_pt    Ngx_http_next_body_filter;


The method for adding a single list of HTTP filter modules is as follows:
Static Ngx_int_tngx_http_addition_filter_init (ngx_conf_t *cf) {    //increment from head    ngx_http_next_header_filter = ngx_ Http_top_header_filter;    Ngx_http_top_header_filter = Ngx_http_addition_header_filter;     Increase    Ngx_http_next_body_filter = Ngx_http_top_body_filter from head;    Ngx_http_top_body_filter = Ngx_http_addition_body_filter;     return NGX_OK;}


When the module is initialized. Call the above function. Add yourself to the list header.

Similar to the above Ngx_http_addition_filter_init, when is this initialization function called? The answer is depending on which member of the ngx_http_module_t structure the method is placed in.

In general, most official HTTP filtering modules are usually placed in the Ngx_http_module_t.postconfiguration function pointer and are called back after reading the complete configuration item. What is the sequence of initialization of each module? This is determined by the sort order of the ngx_modules array in the NGX_MODULES.C file generated by the Configure command. The preceding module in the array is initialized first. Because the filter module inserts itself into the list header, the filtering modules in the Ngx_modules array are arranged in the opposite order as they actually run. The order of arrangement in the Ngx_modules array is also determined by other scripts.
The following is the process of developing a simple HTTP filtering module.

First, define two structures:

typedef struct{    ngx_flag_t  enable;     Save on or off} ngx_http_myfilter_conf_t; typedef struct{    ngx_int_t  add_prefix;} ngx_http_myfilter_ctx_t;  HTTP Context Structure Body


Ngx_http_myfilter_conf_t is used to save a configuration item that flags whether the filter function is turned on, and we use the default configuration item resolution method to parse this configuration item. Ngx_http_myfilter_ctx_t is used to hold the context of an HTTP request, since the processing of the HTTP packet is not completed once, that is, the function that handles the package body is called multiple times, so we need a flag to record whether the filter module is currently being processed. The HTTP context is equivalent to a table in which the current processing record for the request is recorded.

Such When a request is split into multiple processing. The same handler functions to understand where the request has been run, and then process the current progress.


The HTTP module structure ngx_http_module_t definitions such as the following:

Static ngx_http_module_t  ngx_http_myfilter_module_ctx ={    NULL,/                             * preconfiguration */    NGX_HTTP_ Myfilter_init,/           * postconfiguration */     NULL,/                             * create_main_conf */    NULL,/                             * init_main_conf */     NULL,/                             * create_srv_conf */    NULL,/                             * merge_srv_conf */     ngx_http_myfilter_create_conf, /    * create_loc_conf */    ngx_http_myfilter_merge_conf/      * merge_loc_conf */};


The functions of the three function excuses are as follows:
    • Ngx_http_myfilter_init: initializes the filter module. That is, the module is inserted into the HTTP Filter module single-link list, the insertion method has been described above.
    • Ngx_http_myfilter_create_conf: Allocates space and initializes struct members ngx_http_myfilter_conf_t the struct body that holds the configuration item
    • ngx_http_myfilter_merge_conf: Merging a configuration item with the same name now in Main, SRV level

Another important structural ngx_command_t definition is as follows:
Static ngx_command_t  ngx_http_myfilter_commands[] ={    {        ngx_string ("Myfilter"),        Ngx_http_main_ CONF | ngx_http_srv_conf | ngx_http_loc_conf | ngx_http_lmt_conf | Ngx_conf_flag,        Ngx_conf_set_flag_slot,     //The Analytic function        Ngx_http_loc_conf_offset,        offsetof (ngx_http_ myfilter_conf_t, enable),        NULL    },    Ngx_null_command};


We use the default configuration item resolution function Ngx_conf_set_flag_slot to parse the configuration item myfilter, and the parsed configuration item number is stored in the enable member of the struct ngx_http_myfilter_conf_t. The configuration item myfilter can only be "on" or "off".


Note that the HTTP filter module still belongs to an HTTP module, which means: Ngx_module_t.type = Ngx_http_module
The following is the core part of the HTTP Filtering module, which is the function that the two pointers point to each other.

Let's take a look at the functions that handle HTTP response headers:

Handle the requested head static ngx_int_t Ngx_http_myfilter_header_filter (ngx_http_request_t *r) {ngx_http_myfilter_ctx_t *ctx;     ngx_http_myfilter_conf_t *conf; The assumption is not to return success. It is not necessary to ignore the prefix, directly to the next filter module//Processing response code is not 200 if (r->headers_out.status! = NGX_HTTP_OK) return Ngx_http_next_h     Eader_filter (R);    Gets the HTTP context ctx = Ngx_http_get_module_ctx (R, Ngx_http_myfilter_module); if (CTX)//The context of the request already exists, indicating that the module has been called 1 times.     Directly to the next filter module to process return Ngx_http_next_header_filter (R);     Gets the ngx_http_myfilter_conf_t structure body of the storage configuration item conf = ngx_http_get_module_loc_conf (R, Ngx_http_myfilter_module); Assume that the enable member is 0. That is, the configuration file does not configure the Add_prefix configuration item,//or Add_prefix configuration item is off, then directly to the next Filter module processing if (conf->enable = = 0) return Ngx_htt     P_next_header_filter (R);    Constructs the HTTP context structure body ngx_http_myfilter_ctx_t CTX = ngx_pcalloc (r->pool, sizeof (ngx_http_myfilter_ctx_t));     if (CTX = = NULL) return ngx_error;     Add_prefix of 0 means no prefix ctx->add_prefix = 0; To set the constructed context to the current request   Ngx_http_set_ctx (R, CTX, Ngx_http_myfilter_module); The Myfilter filter module only handles Content-type is the "text/plain" type of HTTP response if (R->headers_out.content_type.len >= sizeof ("text/ Plain ")-1 && ngx_strncasecmp (r->headers_out.content_type.data, (U_char *)" Text/plain ", sizeof (" text/p    Lain ")-1) = = 0) {ctx->add_prefix = 1; 1 indicates the need to prefix the HTTP package body//Assume that the processing module has been written in content-length the length of the HTTP packet, because//we added the prefix string, so we need to increase the length of the string to//conten T-length if (r->headers_out.content_length_n > 0) r->headers_out.content_length_n + = FILTER_PR    Efix.len; }//By the next filter module to continue processing return Ngx_http_next_header_filter (r);}


Here are a few things to note. When the module encounters an incorrect response or the module itself is faulted, it should not exit the program but should be referred to the next HTTP Filtering module, which is why the Ngx_http_next_header_filter function was called multiple times in the preceding code. Also, the function first infers whether the filter is turned on in the configuration file and examines the type of response. The flowchart is as follows:

Next is the function that handles the HTTP package:
This prefix will be added to the package body static ngx_str_t Filter_prefix = Ngx_string ("~~~~~~~this is a prefix~~~~~~~\n"); Package body to process the request static ngx_int_t Ngx_http_myfilter_body_filter (ngx_http_request_t *r, ngx_chain_t *in) {Ngx_http_myfilter_      ctx_t *ctx;      Get the HTTP Context ctx = Ngx_http_get_module_ctx (R, Ngx_http_myfilter_module);        If the context is not obtained, or if the add_prefix in the context structure is 0 or 2 o'clock,//Neither prefix is added, then the next HTTP Filter module is passed directly to handle if (CTX = = NULL | | Ctx->add_prefix! = 1)      Return Ngx_http_next_body_filter (R, in); Set Add_prefix to 2 so that even if Ngx_http_myfilter_body_filter callback again.      The prefix Ctx->add_prefix = 2 is not added repeatedly;      Allocates memory from the requested memory pool for storing string prefixes ngx_buf_t* B = ngx_create_temp_buf (R->pool, Filter_prefix.len);    The pointer in ngx_buf_t correctly points to the Filter_prefix string b->start = B->pos = Filter_prefix.data;      B->last = B->pos + Filter_prefix.len; Generate the ngx_chain_t linked list from the requested memory pool, set the newly assigned ngx_buf_t to//its BUF member, and add it to the original HTTP packet to be sent ngx_chain_t *CL = Ngx_alloc_chain_link (r    ->pool);    Cl->buf = b;     Cl->next = in; Invokes the HTTP package body processing method for the next module. Note that the newly generated CL-linked list return Ngx_http_next_body_filter (R, CL) is passed in.


According to this sentence Cl->next = in can be inferred. We added the Filter_prefix included string to the front of the HTTP response package body.

The flowchart for the above functions is as follows:

watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvbmvzdgxlcg==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">

The following is a compilation and presentation process. We add prefixes to the information we send on the basis of the first mytest module. In order to compile the two modules into nginx at the same time, we enter the following command at config:

./configure--add-module= "/work/nginx/modules/mytest/work/nginx/modules/myfilter"


Then check if the success includes two modules, where we can view an array of all the modules ngx_modules[]:
Vim OBJS/NGX_MODULES.C


The results are as follows:

Can be seen, HTTP Module mytest and HTTP Filter module Myfilter are included in the.

The next step is make and make install. After a successful installation. We also want to change the configuration file:

Vim/usr/local/nginx/conf/nginx.conf


After the configuration file changes, for example, as seen:

when the client input URI is/nestle, the mytest and Myfilter two modules are started, and the results are as follows:

watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvbmvzdgxlcg==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">

It is possible to see that the HTTP Filtering module succeeded in adding our pre-set string to the content of the response package body.
The complete code for the entire HTTP filtering module is as follows:

#include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h>//configuration item struct typedef struct {Ngx_flag _t enable;} ngx_http_myfilter_conf_t;//Context structure typedef struct {ngx_int_t add_prefix;} ngx_http_myfilter_ctx_t;ngx_module_t ngx_ http_myfilter_module;//forward declaration static ngx_http_output_header_filter_pt Ngx_http_next_header_filter;static NGX_HTTP_ Output_body_filter_pt ngx_http_next_body_filter;//the prefix content that needs to be added static ngx_str_t Filter_prefix = Ngx_string ("~~~~~~~This is a prefix~~~~~~~\n "), Static ngx_int_t Ngx_http_myfilter_header_filter (ngx_http_request_t *r) {Ngx_http_myfilter_ ctx_t *ctx;ngx_http_myfilter_conf_t *conf;if (r->headers_out.status! = NGX_HTTP_OK) return Ngx_http_next_header_ Filter (R);//The next filter module handles CTX = Ngx_http_get_module_ctx (R, Ngx_http_myfilter_module); if (CTX) return Ngx_http_next_ Header_filter (R);//The context already exists, no longer processed conf = ngx_http_get_module_loc_conf (R, Ngx_http_myfilter_module);//Gets the configuration item struct if (conf- >enable = = 0) return Ngx_http_next_header_filter (R);//This filter module is not open CTX = nGx_pcalloc (R->pool, sizeof (ngx_http_myfilter_ctx_t));//create Context Structure body if (CTX = = NULL) return ngx_error;ctx->add_ prefix = 0;//0 means that no prefix ngx_http_set_ctx (r, CTX, Ngx_http_myfilter_module) is required;//only the HTTP request for Content-type type is processed if (R->headers_out.content_type.len >= sizeof ("Text/plain")-1 &&ngx_strncasecmp (R->headers_ Out.content_type.data, (U_char *) "Text/plain", sizeof ("Text/plain")-1) = = 0) {Ctx->add_prefix = 1;//1 indicates the need to add a prefix if (r-& Gt;headers_out.content_length_n > 0) r->headers_out.content_length_n + = filter_prefix.len;//Response Package Body length Add}return Ngx_http_next_header_filter (r);} Static ngx_int_t Ngx_http_myfilter_body_filter (ngx_http_request_t *r, ngx_chain_t *in) {ngx_http_myfilter_ctx_t *ctx; CTX = Ngx_http_get_module_ctx (R, Ngx_http_myfilter_module);//Gets the context structure if (CTX = = NULL | | Ctx->add_prefix! = 1) return ng X_http_next_body_filter (R, in);//do not prefix Ctx->add_prefix = 2;//2 means prefix is added ngx_buf_t *b = ngx_create_temp_buf (r->pool , filter_prefix.len); B->start = B->pos = Filter_prefix.data;b->last = B->pos + filter_prefix.len;//chain to the head of the packet to be sent ngx_chain_t *CL = Ngx_alloc_chain_link (r-& Gt;pool); cl->buf = B;cl->next = In;return Ngx_http_next_body_filter (r, CL);//Skip to next Filter Module}//initialize HTTP filter module static NGX_ int_t ngx_http_myfilter_init (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;return Ngx_ok;} Create a structure that stores configuration items static void* ngx_http_myfilter_create_conf (ngx_conf_t *cf) {ngx_http_myfilter_conf_t *MYCF;MYCF = (ngx_ http_myfilter_conf_t *) Ngx_pcalloc (cf->pool, sizeof (ngx_http_myfilter_conf_t)), if (MYCF = = NULL) return null;mycf- >enable = Ngx_conf_unset;return mycf;} Merge configuration Items static char* ngx_http_myfilter_merge_conf (ngx_conf_t *cf, void *parent, void *child) {ngx_http_myfilter_conf_t * Prev = (ngx_http_myfilter_conf_t *) parent;ngx_http_myfilter_conf_t *conf = (ngx_http_myfilter_conf_t *) Child;ngx_conf_merge_value (conf->enable, prev->enable, 0);//merge function return NGX_CONF_OK;} Static ngx_command_t ngx_http_myfilter_commands[] = {{ngx_string ("Myfilter"), ngx_http_main_conf | ngx_http_srv_conf | ngx_http_loc_conf | ngx_http_lmt_conf | Ngx_conf_flag, Ngx_conf_set_flag_slot, Ngx_http_loc_conf_offset, Offsetof (ngx_http_myfilter_conf_t, E nable), NULL,}, Ngx_null_command};     The eight functions that were called when the HTTP framework was initialized are static ngx_http_module_t Ngx_http_myfilter_module_ctx = {NULL, ngx_http_myfilter_init, NULL, NULL, NULL, NULL, NGX_HTTP_MYFILTER_CREATE_CONF, ngx_http_myfilter_merge_conf,}; Define an HTTP module ngx_module_t ngx_http_myfilter_module = {NGX_MODULE_V1,//0,0,0,0,0,0,1 &ngx_http_myfilter_modul    E_ctx, ngx_http_myfilter_commands, ngx_http_module, NULL, NULL, NULL, NULL, NULL, NULL, NULL, Ngx_module_v1_padding,//0,0,0,0,0,0,0,0, reserved field};



Reference: "Deep Understanding Nginx" sixth chapter.

"Nginx" develops an HTTP filtering 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.