Nginx Source Code Analysis (9)--filter module

Source: Internet
Author: User
Tags flush

Phase handler describes the content handler used to generate the response, and randomly find a module of a content phase, such as: NGX_HTTP_STATIC_MODULE.C, will find in the content Ngx_http_send_header is called in handler, and then the Ngx_http_output_filter is called last. These two functions are sent in response to the head and response body, in Nginx output content is done through the filter.

The filter module is used to filter and output the response content, and Nginx organizes all the filters into a single-linked list with only the head node (actually the stack), the head node being Ngx_http_top_header_filter (filter head) and NGX_HTTP_TOP_. Body_filter (filter response body). Each time a filter module is initialized, the head node Ngx_http_top_header_filter and Ngx_http_top_body_filter of the current filter list are saved as Ngx_http_next_. Header_filter and Ngx_http_next_body_filter, while saving the filter function of this module as Ngx_http_top_header_filter and Ngx_http_top_body_filter, The Ngx_http_next_header_filter and Ngx_http_next_body_filter are then called in the last part of the filter function of this module, thus implementing the chained invocation of all filter modules. Because the filter module is added to the list of the head push node, so the added module than the first added module in the filter chain in front.

Let's take a look at the Ngx_http_send_header function:

ngx_int_t
Ngx_http_send_header (ngx_http_request_t *r)
{
    if (r->err_status) {
        R->headers_ Out.status = r->err_status;
        R->headers_out.status_line.len = 0;
    }

    return Ngx_http_top_header_filter (R);
}
The implementation is simply called the Ngx_http_top_header_filter function, which then calls the next filter until the filter chain has been traversed. Similar to Ngx_http_output_filter, call Ngx_http_top_body_filter.

The addition of the filter is done in the postconfiguration callback function of the HTTP module, which is called in the Ngx_http_block:

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

        module = ngx_modules[m]->ctx;

        if (module->postconfiguration) {
            if (module->postconfiguration (cf)! = NGX_OK) {
                return ngx_conf_error ;
            }
        }
    }

The order in which the callback function is called is to traverse the ngx_modules array and then call the Postconfiguration function one at a-the order of the filter module in the Ngx_modules array determines the position of its filter function in the filter chain. Here is the contents of the Ngx_modules array:

ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    //...
    &ndk_http_module,
    &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_headers_filter_module,
    &ngx_http_set_misc_module,
    &ngx_http_echo_module,
    &ngx_http_copy_filter_module,
    &ngx_http_range_body_filter_module,
    &ngx_http_not_modified_filter_module,
    NULL
};
You can see that the Ngx_http_write_filter_module and ngx_http_header_filter_module two modules are the top two filter modules, so they are at the very end of the filter chain, which is the last execution. These two modules are used to output headers and body, the following specific analysis of Ngx_http_write_filter_module,ngx_http_header_filter_module and similar.

The Ngx_http_write_filter_module module is used to output the response body, which needs to pass in two parameters ngx_request_t and ngx_chain_t in the call, the first is the request, the second parameter is the buffer linked list of the output content, The last buffer is identified by buffer. The filter function of this module is ngx_http_write_filter, and the function is simply to traverse the buffer list and output the response content. It is also important to note that ngx_request_t has an out field to hold the last chain that was not sent, and when a new chain is received, the new chain needs to be connected to the old chain. Take a look at the code below.

    c = r->connection;

    if (c->error) {
        return ngx_error;
    }

    size = 0;		/* The size of the content to be output */
    flush = 0;		/* Whether to flush */Last
    = 0;		/* is the last buffer */
    LL = &r->out;	/* Save ngx_buf_t last time without output */
The variables used are initialized here.
/* Find the size, the flush point and the last link of the saved chain */for (CL = r->out; cl ;

        CL = cl->next) {ll = &cl->next;
                       Ngx_log_debug7 (ngx_log_debug_event, C->log, 0, "write old buf t:%d f:%d%p, pos%p, Size:%z"
                       "File:%O, Size:%z", Cl->buf->temporary, Cl->buf->in_file, Cl->buf->start, Cl->buf->pos, Cl->buf->last-cl->buf->po S, Cl->buf->file_pos, cl->buf->file_last-cl->buf->file_p

 OS);

        #if 1//... #endif size + ngx_buf_size (CL->BUF);
        if (Cl->buf->flush | | cl->buf->recycled) {flush = 1;
        } if (cl->buf->last_buf) {last = 1; }
    }
This code counts the size of the last chain that was not sent, and whether flush is required or not the last buffer.
    /* Add the new chain to the existent one */for (ln =; ln; ln = ln->next) {cl = Ngx_alloc_chain_li
        NK (R->pool);
        if (cl = = NULL) {return ngx_error;
        } cl->buf = ln->buf;
        /* The next address of the last node of the old buf is originally saved, and the new buf is connected to the old buf after */*ll = CL;

        LL = &cl->next;
                       Ngx_log_debug7 (ngx_log_debug_event, C->log, 0, "write new buf t:%d f:%d%p, pos%p, Size:%z"
                       "File:%O, Size:%z", Cl->buf->temporary, Cl->buf->in_file, Cl->buf->start, Cl->buf->pos, Cl->buf->last-cl->buf->po S, Cl->buf->file_pos, cl->buf->file_last-cl->buf->file_p

OS);

        #if 1//... #endif size + ngx_buf_size (CL->BUF);
        if (Cl->buf->flush | | cl->buf->recycled) {    flush = 1;
        }/* The last BUF/if (CL->BUF->LAST_BUF) that needs to be output = 1; }
    }
Adds the new chain after the old chain, and counts the size, flush, and last.
The next step is to deal with the chain, which involves some markup, first of all, to deal with them:

1. Clcf->postpone_output: The threshold value for setting the delay output due to the processing of the postpone_output instruction. For example, the command "postpone S", when the output content size is less than s, and not the last buffer, and does not need to flush, then the delay output.

2. C->write->delayed: Indicates whether the current connection requires a delay output for some reason, such as exceeding the send rate limit, to continue the output only if the delayed tag is canceled elsewhere. In the case of delayed settings, you need to set c->buffered and return Ngx_again.

3. C->buffered: In the case where buffer is not finished, the tag is in the buffer of which module is specified. Value of buffered:

#define NGX_HTTP_LOWLEVEL_BUFFERED         0xf0
#define ngx_http_write_buffered            0x10
#define Ngx_http_ gzip_buffered             0x20
#define ngx_http_ssi_buffered              0x01
#define Ngx_http_sub_buffered              0x02
#define Ngx_http_copy_buffered             0x04
4. R->limit_rate: Corresponds to the limit_rate instruction, which indicates the send rate limit value of the request. Generally, by setting the c->write->delayed, the c->write->delayed is set when the sending rate exceeds limit, in which case the send is delayed, thus reducing the send rate of the request.

    /* * Avoid the output if there is no last buf, no flush point, * There is the incoming bufs and the size O F All Bufs * is smaller than "postpone_output" directive */* In the case of not the last buf, and no flush is required, the Postpone_output command can be To set when the response content is less than a certain value, the delay output */if (!last &&!flush && in && size < (off_t) clcf->postpone_output
    ) {return NGX_OK; }/* Request is delay, set buffered tag, return directly */if (c->write->delayed) {c->buffered |= Ngx_http_write_buffer
        ED;
    return ngx_again; }/* Output content size is 0, and no buffered tag is set, go to cleanup work */if (size = = 0 &&! C->buffered & ngx_lowlevel_buffered)) {/* If this is the last tag, clear the buffered flag */if (last) {R->ou
            t = NULL;

            C->buffered &= ~ngx_http_write_buffered;
        return NGX_OK; }/* If you need flush */if (flush) {/* This piece is unclear what to do with */do {r->out = R
  >out->next;          } while (r->out);

            /* Empty buffered Mark */c->buffered &= ~ngx_http_write_buffered;
        return NGX_OK;

        } ngx_log_error (Ngx_log_alert, C->log, 0, "The HTTP output chain is empty");

        Ngx_debug_point ();
    return ngx_error; }/* Set limit rate */if (r->limit_rate) {limit = R->limit_rate * (Ngx_time ()-r->start_sec +

        1)-(c->sent-clcf->limit_rate_after);
            /* Exceed Send rate limit */if (limit <= 0) {/* Set delayed tag, delay send request */c->write->delayed = 1;

            Ngx_add_timer (C->write, (ngx_msec_t) (-Limit * 1000/r->limit_rate + 1));

            /* Set buffered Mark */c->buffered |= ngx_http_write_buffered;
        return ngx_again; }} else if (clcf->sendfile_max_chunk) {/* Sendfile used for the limit/limit = Clcf->sendfile_mAx_chunk;
    } else {limit = 0; }
This code is based on the above tag to do some processing, the specific look at the note. The next step is the process of sending the data and subsequent processing.
    Sent = c->sent;

    NGX_LOG_DEBUG1 (ngx_log_debug_http, C->log, 0, "HTTP Write Filter Limit%O", limit);

    /* Send_chain returned is not finished chain */chain = C->send_chain (c, r->out, limit);

    NGX_LOG_DEBUG1 (ngx_log_debug_http, C->log, 0, "HTTP Write Filter%p", chain);
        if (chain = = ngx_chain_error) {c->error = 1;
    return ngx_error;

        }/* For limit_rate processing, the delayed tag may be set */if (r->limit_rate) {nsent = c->sent;
            if (clcf->limit_rate_after) {Sent-= clcf->limit_rate_after;
            if (Sent < 0) {sent = 0;
            } nsent-= clcf->limit_rate_after;
            if (Nsent < 0) {nsent = 0;

        }} delay = (ngx_msec_t) ((nsent-sent) * 1000/r->limit_rate + 1);
            if (Delay > 0) {c->write->delayed = 1; Ngx_add_timer (C->write, DelAY); }} else if (C->write->ready && clcf->sendfile_max_chunk && (s ize_t) (c->sent-sent) >= clcf->sendfile_max_chunk-2 * ngx_pagesize) {C-&gt
        ; write->delayed = 1;
    Ngx_add_timer (C->write, 1);
        }/* Releases the chain memory that has been sent */for (CL = r->out; CL && cl! = chain;/* void */) {ln = CL;
        CL = cl->next;
    Ngx_free_chain (r->pool, LN);

    }/* Re-assign value not yet sent chain */r->out = chain; /* If chain is not empty, then BUF is not finished, you need to set the buffered tag and return Ngx_again */if (chain) {c->buffered |= ngx_http_write_buffered
        ;
    return ngx_again;

    }/* If there are no unsent chain, empty the buffered flag */c->buffered &= ~ngx_http_write_buffered; /* If the other filter module is buffer chain and postponed is null, then return to Ngx_again, need to continue processing BUF */if (c->buffered & Ngx_lowlevel_ BUFFERED) && r->postponed = = NULL) {return Ngx_agaIn; } return NGX_OK;
The above is the ngx_http_write_filter process, ngx_http_header_filter similar to it, but it is dealing with the response header, and then at the end of the ngx_http_write_filter output.





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.