static
ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r)
{
time_t if_modified_since;
if_modified_since = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
r->headers_in.if_modified_since->value.len);
/* step 1: decide whether to operate */
if (if_modified_since != NGX_ERROR &&
if_modified_since == r->headers_out.last_modified_time) {
/* step 2: operate on the header */
r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
r->headers_out.content_type.len = 0;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
}
/* step 3: call the next filter */
return ngx_http_next_header_filter(r);
}
结构headers_out和我们在hander那一节中看到的是一样的(参考http/ngx_http_request.h),也可以随意处置。
4.2. 剖析Body Filter
Anatomy of a Body Filter
因为body filter一次只能操作一个buffer chain(链表),这使得编写body filter需要一定的技巧。模块需要知道什么时候可以覆盖输入buffer,用新申请的buffer替换已有的,或者在现有的某个buffer前或后插入一个新buffer。有时候模块会收到许多buffer使得它不得不操作一个不完整的链表,这使得事情变得更加复杂了。而更加不幸的是,Nginx没有为我们提供上层的API来操作buffer链表,所以body filter是比较难懂(当然也比较难写)。但是,有些操作你还是可以看出来的。
第一个参数是我们的老朋友"请求结构体"(ngx_http_request_t) ,第二个参数则是指向当前部分链表(chain)表头的指针(可能包含0,1,或更多的buffer)。
再来举个例子好了。假设我们想要做的是在每个请求之后插入文本"<l!-- Served by Nginx -->"。首先,我们需要判断给我们的buffer链表中是否已经包含响应的最终buffer。就像之前我说的,这里没有简便好用的API,所以我们只能自己来写个循环:
ngx_chain_t *chain_link;
int chain_contains_last_buffer = 0;
chain_link = in;
for ( ; ; ) {
if (chain_link->buf->last_buf)
chain_contains_last_buffer = 1;
if (chain_link->next == NULL)
break;
chain_link = chain_link->next;
}
如果我们没有最后的缓冲区,就返回:
if (!chain_contains_last_buffer)
return ngx_http_next_body_filter(r, in);
很好,现在最后一个缓冲区已经存在链表中了。接下来我们分配一个新缓冲区:
ngx_buf_t *b;
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
把数据放进去:
b->pos = (u_char *) "<!-- Served by Nginx -->";
b->last = b->pos + sizeof("<!-- Served by Nginx -->") - 1;