1. ngx_http_top_header_filter

该链表主要是用于构造响应消息的消息报头。

ngx_http_top_header_filter 单链表有如下模块插入了操作:

  1. ngx_http_not_modified_filter_module: ngx_http_not_modified_header_filter
  2. ngx_http_headers_filter_module:ngx_http_headers_filter
  3. ngx_http_userid_filter_module: ngx_http_userid_filter
  4. ngx_http_charset_filter_module:ngx_http_charset_header_filter
  5. ngx_http_ssi_filter_module: ngx_http_ssi_header_filter
  6. ngx_http_gzip_filter_module: ngx_http_gzip_header_filter
  7. ngx_http_range_filter_module: ngx_http_range_header_filter
  8. ngx_http_chunked_filter_module: ngx_http_chunked_header_filter
  9. ngx_http_header_filter_module: ngx_http_header_filter

1.1 ngx_http_not_modified_header_filter

static ngx_int_t
ngx_http_not_modified_header_filter(ngx_http_request_t *r)
{
if (r->headers_out.status != NGX_HTTP_OK
|| r != r->main
|| r->disable_not_modified)
{
return ngx_http_next_header_filter(r);
} /* If-Modified-Since: 当客户端请求服务器判断自己缓存的内容是否变化时,可以设置
* If-Modified-Since 请求头,如果服务器上的内容修改时间比这个头的时间值还新,
* 那么将返回新的内容,否则不返回。这个与 If-Unmodified-Since 类似,是用来判断
* 资源变化的另一种方式 */
if (r->headers_in.if_unmodified_since
&& !ngx_http_test_if_unmodified(r))
{
return ngx_http_filter_finalize_request(r, NULL,
NGX_HTTP_PRECONDITION_FAILED);
} /* If-Match: 与 ETag 一起用来判断已缓存的内容是否被修改过。比如,客户端在获取
* 内容时会获取一个与内容相同的实体标签 ETag (内容变化会使 ETag 变化),下次
* 再请求同样的内容时,会在请求头的 If-Match 中包含这个 ETag,然后发给可能存有
* 更新内容的服务器。服务器将收到的 ETag 与本地目前的 ETag 进行比较,如果匹配
* 返回所请求内容。这种方法在断点续传的时候使用较多 */
if (r->headers_in.if_match
&& !ngx_http_test_if_match(r, r->headers_in.if_match, 0))
{
return ngx_http_filter_finalize_request(r, NULL,
NGX_HTTP_PRECONDITION_FAILED);
} /* If-Modified-Since: 当客户端请求服务器判断自己缓存的内容是否变化时,可以设置
* If-Modified-Since 头,如果服务器上的内容修改时间比这个头的时间值还要新,那么将
* 返回新的内容,否则不返回。这个与 If-Unmodified-Since 类似,是用来判断资源变化的
* 另一种方式。
*
* If-None-Match: 与 If-Match 类似,结果相反。如果 If-None-Match 中包含了 ETag 的值,
* 服务器在进行比较后发现如果不匹配,则返回所请求的内容,否则不返回相关内容。这种
* 方法在网页刷新的时候使用较多。
*/
if (r->headers_in.if_modified_since || r->headers_in.if_none_match) { if (r->headers_in.if_modified_since
&& ngx_http_test_if_modified(r))
{
return ngx_http_next_header_filter(r);
} if (r->headers_in.if_none_match
&& !ngx_http_test_if_match(r, r->headers_in.if_none_match, 1))
{
return ngx_http_next_header_filter(r);
} /* not modified */ r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
r->headers_out.status_line.len = 0;
r->headers_out.content_type.len = 0;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r); if (r->headers_out.content_encoding) {
r->headers_out.content_encoding->hash = 0;
r->headers_out.content_encoding = NULL;
} return ngx_http_next_header_filter(r);
} return ngx_http_next_header_filter(r);
}

此时 ngx_http_next_header_filter 回调的函数为 ngx_http_headers_filter。

1.2 ngx_http_headers_filter

static ngx_int_t
ngx_http_headers_filter(ngx_http_request_t *r)
{
ngx_str_t value;
ngx_uint_t i, safe_status;
ngx_http_header_val_t *h;
ngx_http_headers_conf_t *conf; if (r != r->main) {
return ngx_http_next_header_filter(r);
} /* 获取 ngx_http_headers_filter_module 模块与 location 相关的配置 */
conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); /* 若对 expires、headers、trailers 都没有相应的配置,则执行
* ngx_http_top_header_filter 链表的下一个函数 */
if (conf->expires == NGX_HTTP_EXPIRES_OFF
&& conf->headers == NULL
&& conf->trailers == NULL)
{
return ngx_http_next_header_filter(r);
} switch (r->headers_out.status) { case NGX_HTTP_OK:
case NGX_HTTP_CREATED:
case NGX_HTTP_NO_CONTENT:
case NGX_HTTP_PARTIAL_CONTENT:
case NGX_HTTP_MOVED_PERMANENTLY:
case NGX_HTTP_MOVED_TEMPORARILY:
case NGX_HTTP_SEE_OTHER:
case NGX_HTTP_NOT_MODIFIED:
case NGX_HTTP_TEMPORARY_REDIRECT:
case NGX_HTTP_PERMANENT_REDIRECT:
safe_status = 1;
break; default:
safe_status = 0;
break;
} if (conf->expires != NGX_HTTP_EXPIRES_OFF && safe_status) {
if (ngx_http_set_expires(r, conf) != NGX_OK) {
return NGX_ERROR;
}
} if (conf->headers) {
h = conf->headers->elts;
for (i = 0; i < conf->headers->nelts; i++) { if (!safe_status && !h[i].always) {
continue;
} if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
return NGX_ERROR;
} if (h[i].handler(r, &h[i], &value) != NGX_OK) {
return NGX_ERROR;
}
}
} if (conf->trailers) {
h = conf->trailers->elts;
for (i = 0; i < conf->trailers->nelts; i++) { if (!safe_status && !h[i].always) {
continue;
} r->expect_trailers = 1;
break;
}
} return ngx_http_next_header_filter(r);
}

1.3 ngx_http_userid_filter

static ngx_int_t
ngx_http_userid_filter(ngx_http_request_t *r)
{
ngx_http_userid_ctx_t *ctx;
ngx_http_userid_conf_t *conf; /* 若为子请求,直接执行 ngx_http_top_header_filter 链表的下一个函数 */
if (r != r->main) {
return ngx_http_next_header_filter(r);
} /* 获取 ngx_http_userid_filter_module 模块 loc 级别的配置 */
conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); /* 若没有使能该模块,则执行下一个函数 */
if (conf->enable < NGX_HTTP_USERID_V1) {
return ngx_http_next_header_filter(r);
} ctx = ngx_http_userid_get_uid(r, conf); if (ctx == NULL) {
return NGX_ERROR;
} if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) {
return ngx_http_next_header_filter(r);
} return NGX_ERROR;
}

1.4 ngx_http_charset_header_filter

static ngx_int_t
ngx_http_charset_header_filter(ngx_http_request_t *r)
{
ngx_int_t charset, source_charset;
ngx_str_t dst, src;
ngx_http_charset_t *charsets;
ngx_http_charset_main_conf_t *mcf; /* 若当前请求为父请求 */
if (r == r->main) {
charset = ngx_http_destination_charset(r, &dst); } else {
charset = ngx_http_main_request_charset(r, &dst);
} if (charset == NGX_ERROR) {
return NGX_ERROR;
} /* 执行下一个 */
if (charset == NGX_DECLINED) {
return ngx_http_next_header_filter(r);
} /* charset: charset index or NGX_HTTP_NO_CHARSET */ source_charset = ngx_http_source_charset(r, &src); if (source_charset == NGX_ERROR) {
return NGX_ERROR;
} /*
* source_charset: charset index, NGX_HTTP_NO_CHARSET,
* or NGX_HTTP_CHARSET_OFF
*/ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"charset: \"%V\" > \"%V\"", &src, &dst); if (source_charset == NGX_HTTP_CHARSET_OFF) {
ngx_http_set_charset(r, &dst); return ngx_http_next_header_filter(r);
} if (charset == NGX_HTTP_NO_CHARSET
|| source_charset == NGX_HTTP_NO_CHARSET)
{
if (source_charset != charset
|| ngx_strncasecmp(dst.data, src.data, dst.len) != 0)
{
goto no_charset_map;
} ngx_http_set_charset(r, &dst); return ngx_http_next_header_filter(r);
} if (source_charset == charset) {
r->headers_out.content_type.len = r->headers_out.content_type_len; ngx_http_set_charset(r, &dst); return ngx_http_next_header_filter(r);
} /* source_charset != charset */ if (r->headers_out.content_encoding
&& r->headers_out.content_encoding->value.len)
{
return ngx_http_next_header_filter(r);
} mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
charsets = mcf->charsets.elts; if (charsets[source_charset].tables == NULL
|| charsets[source_charset].tables[charset] == NULL)
{
goto no_charset_map;
} r->headers_out.content_type.len = r->headers_out.content_type_len; ngx_http_set_charset(r, &dst); return ngx_http_charset_ctx(r, charsets, charset, source_charset); no_charset_map: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"no \"charset_map\" between the charsets \"%V\" and \"%V\"",
&src, &dst); return ngx_http_next_header_filter(r);
}

1.4.1 ngx_http_destination_charset

static ngx_int_t
ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name)
{
ngx_int_t charset;
ngx_http_charset_t *charsets;
ngx_http_variable_value_t *vv;
ngx_http_charset_loc_conf_t *mlcf;
ngx_http_charset_main_conf_t *mcf; /* 若还没有设置当前响应的 Content-Type 头 */
if (r->headers_out.content_type.len == 0) {
return NGX_DECLINED;
} if (r->headers_out.override_charset
&& r->headers_out.override_charset->len)
{
*name = *r->headers_out.override_charset; charset = ngx_http_get_charset(r, name); if (charset != NGX_HTTP_NO_CHARSET) {
return charset;
} ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"unknown charset \"%V\" to override", name); return NGX_DECLINED;
} mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
charset = mlcf->charset; /* 若没有开启 charset */
if (charset == NGX_HTTP_CHARSET_OFF) {
return NGX_DECLINED;
} if (r->headers_out.charset.len) {
if (mlcf->override_charset == 0) {
return NGX_DECLINED;
} } else {
if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
return NGX_DECLINED;
}
} if (charset < NGX_HTTP_CHARSET_VAR) {
mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
charsets = mcf->charsets.elts;
*name = charsets[charset].name;
return charset;
} vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR); if (vv == NULL || vv->not_found) {
return NGX_ERROR;
} name->len = vv->len;
name->data = vv->data; return ngx_http_get_charset(r, name);
}

1.5 ngx_http_ssi_header_filter

static ngx_int_t
ngx_http_ssi_header_filter(ngx_http_request_t *r)
{
ngx_http_ssi_ctx_t *ctx;
ngx_http_ssi_loc_conf_t *slcf; /* 获取 ngx_http_ssi_filter_module 模块 loc 级别的配置 */
slcf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); /* 若没有启用该模块 */
if (!slcf->enable
|| r->headers_out.content_length_n == 0
|| ngx_http_test_content_type(r, &slcf->types) == NULL)
{
return ngx_http_next_header_filter(r);
} ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_ssi_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
} ngx_http_set_ctx(r, ctx, ngx_http_ssi_filter_module); ctx->value_len = slcf->value_len;
ctx->last_out = &ctx->out; ctx->encoding = NGX_HTTP_SSI_ENTITY_ENCODING;
ctx->output = 1; ctx->params.elts = ctx->params_array;
ctx->params.size = sizeof(ngx_table_elt_t);
ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N;
ctx->params.pool = r->pool; ctx->timefmt = ngx_http_ssi_timefmt;
ngx_str_set(&ctx->errmsg,
"[an error occurred while processing the directive]"); r->filter_need_in_memory = 1; if (r == r->main) {
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r); if (!slcf->last_modified) {
ngx_http_clear_last_modified(r);
ngx_http_clear_etag(r); } else {
ngx_http_weak_etag(r);
}
} return ngx_http_next_header_filter(r);
}

1.6 ngx_http_gzip_header_filter

static ngx_int_t
ngx_http_gzip_header_filter(ngx_http_request_t *r)
{
ngx_table_elt_t *h;
ngx_http_gzip_ctx_t *ctx;
ngx_http_gzip_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); /* 若没有使能该模块 */
if (!conf->enable
|| (r->headers_out.status != NGX_HTTP_OK
&& r->headers_out.status != NGX_HTTP_FORBIDDEN
&& r->headers_out.status != NGX_HTTP_NOT_FOUND)
|| (r->headers_out.content_encoding
&& r->headers_out.content_encoding->value.len)
|| (r->headers_out.content_length_n != -1
&& r->headers_out.content_length_n < conf->min_length)
|| ngx_http_test_content_type(r, &conf->types) == NULL
|| r->header_only)
{
return ngx_http_next_header_filter(r);
} r->gzip_vary = 1; #if (NGX_HTTP_DEGRADATION)
{
ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->gzip_disable_degradation && ngx_http_degraded(r)) {
return ngx_http_next_header_filter(r);
}
}
#endif if (!r->gzip_tested) {
if (ngx_http_gzip_ok(r) != NGX_OK) {
return ngx_http_next_header_filter(r);
} } else if (!r->gzip_ok) {
return ngx_http_next_header_filter(r);
} ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
} ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); ctx->request = r;
ctx->buffering = (conf->postpone_gzipping != 0); ngx_http_gzip_filter_memory(r, ctx); h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
return NGX_ERROR;
} h->hash = 1;
ngx_str_set(&h->key, "Content-Encoding");
ngx_str_set(&h->value, "gzip");
r->headers_out.content_encoding = h; r->main_filter_need_in_memory = 1; ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
ngx_http_weak_etag(r); return ngx_http_next_header_filter(r);
}

1.7 ngx_http_range_header_filter

static ngx_int_t
ngx_http_range_header_filter(ngx_http_request_t *r)
{
time_t if_range_time;
ngx_str_t *if_range, *etag;
ngx_uint_t ranges;
ngx_http_core_loc_conf_t *clcf;
ngx_http_range_filter_ctx_t *ctx; if (r->http_version < NGX_HTTP_VERSION_10
|| r->headers_out.status != NGX_HTTP_OK
|| (r != r->main && !r->subrequest_ranges)
|| r->headers_out.content_length_n == -1
|| !r->allow_ranges)
{
return ngx_http_next_header_filter(r);
} /* 获取 ngx_http_core_module 模块 loc 级别的配置 */
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->max_ranges == 0) {
return ngx_http_next_header_filter(r);
} if (r->headers_in.range == NULL
|| r->headers_in.range->value.len < 7
|| ngx_strncasecmp(r->headers_in.range->value.data,
(u_char *) "bytes=", 6)
!= 0)
{
goto next_filter;
} if (r->headers_in.if_range) { if_range = &r->headers_in.if_range->value; if (if_range->len >= 2 && if_range->data[if_range->len - 1] == '"') { if (r->headers_out.etag == NULL) {
goto next_filter;
} etag = &r->headers_out.etag->value; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http ir:%V etag:%V", if_range, etag); if (if_range->len != etag->len
|| ngx_strncmp(if_range->data, etag->data, etag->len) != 0)
{
goto next_filter;
} goto parse;
} if (r->headers_out.last_modified_time == (time_t) -1) {
goto next_filter;
} if_range_time = ngx_parse_http_time(if_range->data, if_range->len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http ir:%T lm:%T",
if_range_time, r->headers_out.last_modified_time); if (if_range_time != r->headers_out.last_modified_time) {
goto next_filter;
}
} parse: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
} ctx->offset = r->headers_out.content_offset; ranges = r->single_range ? 1 : clcf->max_ranges; switch (ngx_http_range_parse(r, ctx, ranges)) { case NGX_OK:
ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
r->headers_out.status_line.len = 0; if (ctx->ranges.nelts == 1) {
return ngx_http_range_singlepart_header(r, ctx);
} return ngx_http_range_multipart_header(r, ctx); case NGX_HTTP_RANGE_NOT_SATISFIABLE:
return ngx_http_range_not_satisfiable(r); case NGX_ERROR:
return NGX_ERROR; default: /* NGX_DECLINED */
break;
} next_filter: /* Accept-Ranges: 可以请求网页实体的一个或多个子范围字段,
* 值为 bytes 表示支持断点续传,为 none 表示不支持 */
r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.accept_ranges == NULL) {
return NGX_ERROR;
} r->headers_out.accept_ranges->hash = 1;
ngx_str_set(&r->headers_out.accept_ranges->key, "Accept-Ranges");
ngx_str_set(&r->headers_out.accept_ranges->value, "bytes"); return ngx_http_next_header_filter(r);
}

1.8 ngx_http_chunked_header_filter

static ngx_int_t
ngx_http_chunked_header_filter(ngx_http_request_t *r)
{
ngx_http_core_loc_conf_t *clcf;
ngx_http_chunked_filter_ctx_t *ctx; if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
|| r->headers_out.status == NGX_HTTP_NO_CONTENT
|| r->headers_out.status < NGX_HTTP_OK
|| r != r->main
|| r->method == NGX_HTTP_HEAD)
{
return ngx_http_next_header_filter(r);
} if (r->headers_out.content_length_n == -1
|| r->expect_trailers)
{
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->http_version >= NGX_HTTP_VERSION_11
&& clcf->chunked_transfer_encoding)
{
if (r->expect_trailers) {
ngx_http_clear_content_length(r);
} r->chunked = 1; ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_filter_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
} ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); } else if (r->headers_out.content_length_n == -1) {
r->keepalive = 0;
}
} return ngx_http_next_header_filter(r);
}

1.9 ngx_http_header_filter

static ngx_int_t
ngx_http_header_filter(ngx_http_request_t *r)
{
u_char *p;
size_t len;
ngx_str_t host, *status_line;
ngx_buf_t *b;
ngx_uint_t status, i, port;
ngx_chain_t out;
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
u_char addr[NGX_SOCKADDR_STRLEN]; /* 标志位,为 1 表示该 header 已经发送了 */
if (r->header_sent) {
return NGX_OK;
} /* 设置该标志位为 1 */
r->header_sent = 1; /* 若为子请求,则直接返回 */
if (r != r->main) {
return NGX_OK;
} if (r->http_version < NGX_HTTP_VERSION_10) {
return NGX_OK;
} /* 若当前方法为 HEAD 则仅发送 header */
if (r->method == NGX_HTTP_HEAD) {
r->header_only = 1;
} if (r->headers_out.last_modified_time != -1) {
if (r->headers_out.status != NGX_HTTP_OK
&& r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
&& r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
{
r->headers_out.last_modified_time = -1;
r->headers_out.last_modified = NULL;
}
} /* 状态行的长度 */
len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
/* the end of the header */
+ sizeof(CRLF) - 1; /* status line */ if (r->headers_out.status_line.len) {
len += r->headers_out.status_line.len;
status_line = &r->headers_out.status_line;
#if (NGX_SUPPRESS_WARN)
status = 0;
#endif } else { status = r->headers_out.status; if (status >= NGX_HTTP_OK
&& status < NGX_HTTP_LAST_2XX)
{
/* 2XX */ /* 204:该响应没有响应正文 */
if (status == NGX_HTTP_NO_CONTENT) {
r->header_only = 1;
ngx_str_null(&r->headers_out.content_type);
r->headers_out.last_modified_time = -1;
r->headers_out.last_modified = NULL;
r->headers_out.content_length = NULL;
r->headers_out.content_length_n = -1;
} /* 计算该状态在 ngx_http_status_lines 数组中的索引 */
status -= NGX_HTTP_OK;
/* 从该数组中 status 索引处获取字符串形式的状态行 */
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
&& status < NGX_HTTP_LAST_3XX)
{
/* 3XX */ if (status == NGX_HTTP_NOT_MODIFIED) {
r->header_only = 1;
} status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_BAD_REQUEST
&& status < NGX_HTTP_LAST_4XX)
{
/* 4XX */
status = status - NGX_HTTP_BAD_REQUEST
+ NGX_HTTP_OFF_4XX; status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
&& status < NGX_HTTP_LAST_5XX)
{
/* 5XX */
status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
+ NGX_HTTP_OFF_5XX; status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len; } else {
len += NGX_INT_T_LEN + 1 /* SP */;
status_line = NULL;
} if (status_line && status_line->len == 0) {
status = r->headers_out.status;
len += NGX_INT_T_LEN + 1 /* SP */;
status_line = NULL;
}
} /* 获取 ngx_http_core_module 模块在 loc 级别的配置 */
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.server == NULL) {
if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
/* Server: web 服务器表明自己是什么版本及版本信息 */
len += sizeof(ngx_http_server_full_string) - 1; } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
len += sizeof(ngx_http_server_build_string) - 1; } else {
len += sizeof(ngx_http_server_string) - 1;
}
} if (r->headers_out.date == NULL) {
/* Date: 发送该 HTTP 消息的时间 */
len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
} if (r->headers_out.content_type.len) {
len += sizeof("Content-Type: ") - 1
+ r->headers_out.content_type.len + 2; if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{
len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
}
} if (r->headers_out.content_length == NULL
&& r->headers_out.content_length_n >= 0)
{
/* Content-Length: 实体内容的大小 */
len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
} if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
/* Last-Modified: 指定所访问内容的最后更新时间 */
len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
} c = r->connection; if (r->headers_out.location
&& r->headers_out.location->value.len
&& r->headers_out.location->value.data[0] == '/'
&& clcf->absolute_redirect)
{
r->headers_out.location->hash = 0; if (clcf->server_name_in_redirect) {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
host = cscf->server_name; } else if (r->headers_in.server.len) {
host = r->headers_in.server; } else {
host.len = NGX_SOCKADDR_STRLEN;
host.data = addr; if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
return NGX_ERROR;
}
} port = ngx_inet_get_port(c->local_sockaddr); len += sizeof("Location: https://") - 1
+ host.len
+ r->headers_out.location->value.len + 2; if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL)
if (c->ssl)
port = (port == 443) ? 0 : port;
else
#endif
port = (port == 80) ? 0 : port; } else {
port = 0;
} if (port) {
len += sizeof(":65535") - 1;
} } else {
ngx_str_null(&host);
port = 0;
} if (r->chunked) {
len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
} if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
len += sizeof("Connection: upgrade" CRLF) - 1; } else if (r->keepalive) {
len += sizeof("Connection: keep-alive" CRLF) - 1; /*
* MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header.
* MSIE keeps the connection alive for about 60-65 seconds.
* Opera keeps the connection alive very long.
* Mozilla keeps the connection alive for N plus about 1-10 seconds.
* Konqueror keeps the connection alive for about N seconds.
*/ if (clcf->keepalive_header) {
len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
} } else {
len += sizeof("Connection: close" CRLF) - 1;
} #if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
if (clcf->gzip_vary) {
len += sizeof("Vary: Accept-Encoding" CRLF) - 1; } else {
r->gzip_vary = 0;
}
}
#endif /* 从 headers_out.headers 链表中取出第一个 数组元素 */
part = &r->headers_out.headers.part;
/* header 执行该数组 part 的第一个元素 */
header = part->elts; /* 统计响应消息中响应头部的总大小 */
for (i = 0; /* void */; i++) { if (i >= part->nelts) {
if (part->next == NULL) {
break;
} part = part->next;
header = part->elts;
i = 0;
} if (header[i].hash == 0) {
continue;
} len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
+ sizeof(CRLF) - 1;
} /* 为该响应消息分配临时缓存 */
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
return NGX_ERROR;
} /* 响应消息分四部分:状态行、消息报头、空行和响应正文 */
/* "HTTP/1.x " */
b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); /* status line */
if (status_line) {
b->last = ngx_copy(b->last, status_line->data, status_line->len); } else {
b->last = ngx_sprintf(b->last, "%03ui ", status);
}
*b->last++ = CR; *b->last++ = LF; /* 下面依次向该缓存中写入消息报头 */
if (r->headers_out.server == NULL) {
if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
p = ngx_http_server_full_string;
len = sizeof(ngx_http_server_full_string) - 1; } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
p = ngx_http_server_build_string;
len = sizeof(ngx_http_server_build_string) - 1; } else {
p = ngx_http_server_string;
len = sizeof(ngx_http_server_string) - 1;
} b->last = ngx_cpymem(b->last, p, len);
} if (r->headers_out.date == NULL) {
b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
ngx_cached_http_time.len); *b->last++ = CR; *b->last++ = LF;
} if (r->headers_out.content_type.len) {
b->last = ngx_cpymem(b->last, "Content-Type: ",
sizeof("Content-Type: ") - 1);
p = b->last;
b->last = ngx_copy(b->last, r->headers_out.content_type.data,
r->headers_out.content_type.len); if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{
b->last = ngx_cpymem(b->last, "; charset=",
sizeof("; charset=") - 1);
b->last = ngx_copy(b->last, r->headers_out.charset.data,
r->headers_out.charset.len); /* update r->headers_out.content_type for possible logging */ r->headers_out.content_type.len = b->last - p;
r->headers_out.content_type.data = p;
} *b->last++ = CR; *b->last++ = LF;
} if (r->headers_out.content_length == NULL
&& r->headers_out.content_length_n >= 0)
{
b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
r->headers_out.content_length_n);
} if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
b->last = ngx_cpymem(b->last, "Last-Modified: ",
sizeof("Last-Modified: ") - 1);
b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); *b->last++ = CR; *b->last++ = LF;
} if (host.data) { p = b->last + sizeof("Location: ") - 1; b->last = ngx_cpymem(b->last, "Location: http",
sizeof("Location: http") - 1); #if (NGX_HTTP_SSL)
if (c->ssl) {
*b->last++ ='s';
}
#endif *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
b->last = ngx_copy(b->last, host.data, host.len); if (port) {
b->last = ngx_sprintf(b->last, ":%ui", port);
} b->last = ngx_copy(b->last, r->headers_out.location->value.data,
r->headers_out.location->value.len); /* update r->headers_out.location->value for possible logging */ r->headers_out.location->value.len = b->last - p;
r->headers_out.location->value.data = p;
ngx_str_set(&r->headers_out.location->key, "Location"); *b->last++ = CR; *b->last++ = LF;
} if (r->chunked) {
b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
sizeof("Transfer-Encoding: chunked" CRLF) - 1);
} if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF,
sizeof("Connection: upgrade" CRLF) - 1); } else if (r->keepalive) {
b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
sizeof("Connection: keep-alive" CRLF) - 1); if (clcf->keepalive_header) {
b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
clcf->keepalive_header);
} } else {
b->last = ngx_cpymem(b->last, "Connection: close" CRLF,
sizeof("Connection: close" CRLF) - 1);
} #if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
sizeof("Vary: Accept-Encoding" CRLF) - 1);
}
#endif part = &r->headers_out.headers.part;
header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) {
if (part->next == NULL) {
break;
} part = part->next;
header = part->elts;
i = 0;
} if (header[i].hash == 0) {
continue;
} b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
*b->last++ = ':'; *b->last++ = ' '; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
*b->last++ = CR; *b->last++ = LF;
} ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"%*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */
*b->last++ = CR; *b->last++ = LF; r->header_size = b->last - b->pos; if (r->header_only) {
b->last_buf = 1;
} out.buf = b;
out.next = NULL; return ngx_http_write_filter(r, &out);
}

1.9.1 ngx_http_write_filter

ngx_int_t
ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
off_t size, sent, nsent, limit;
ngx_uint_t last, flush, sync;
ngx_msec_t delay;
ngx_chain_t *cl, *ln, **ll, *chain;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf; c = r->connection; if (c->error) {
return NGX_ERROR;
} size = 0;
flush = 0;
sync = 0;
last = 0;
/* 指向该链表的头部 */
ll = &r->out; /* 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: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
cl->buf->file_pos,
cl->buf->file_last - cl->buf->file_pos); #if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"zero size buf in writer "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
cl->buf->temporary,
cl->buf->recycled,
cl->buf->in_file,
cl->buf->start,
cl->buf->pos,
cl->buf->last,
cl->buf->file,
cl->buf->file_pos,
cl->buf->file_last); ngx_debug_point();
return NGX_ERROR;
}
#endif size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->recycled) {
flush = 1;
} if (cl->buf->sync) {
sync = 1;
} if (cl->buf->last_buf) {
last = 1;
}
} /* add the new chain to the existent one */ for (ln = in; ln; ln = ln->next) {
/* 分配一个 ngx_chain_t */
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
} /* 指向保存着将要发送的数据的缓存的首地址 */
cl->buf = ln->buf;
/* 将该 cl 添加到 r->out 链表中 */
*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: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
cl->buf->file_pos,
cl->buf->file_last - cl->buf->file_pos); #if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"zero size buf in writer "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
cl->buf->temporary,
cl->buf->recycled,
cl->buf->in_file,
cl->buf->start,
cl->buf->pos,
cl->buf->last,
cl->buf->file,
cl->buf->file_pos,
cl->buf->file_last); ngx_debug_point();
return NGX_ERROR;
}
#endif /* 计算该 cl->buf 中缓存的数据大小 */
size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->recycled) {
flush = 1;
} if (cl->buf->sync) {
sync = 1;
} if (cl->buf->last_buf) {
last = 1;
}
} *ll = NULL; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter: l:%ui f:%ui s:%O", last, flush, size); /* 获取 ngx_http_core_module 模块 loc 级别的配置 */
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /*
* avoid the output if there are no last buf, no flush point,
* there are the incoming bufs and the size of all bufs
* is smaller than "postpone_output" directive
*/ if (!last && !flush && in && size < (off_t) clcf->postpone_output) {
return NGX_OK;
} if (c->write->delayed) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
} if (size == 0
&& !(c->buffered & NGX_LOWLEVEL_BUFFERED)
&& !(last && c->need_last_buf))
{
if (last || flush || sync) {
for (cl = r->out; cl; /* void */) {
ln = cl;
cl = cl->next;
ngx_free_chain(r->pool, ln);
} r->out = NULL;
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;
} if (r->limit_rate) {
if (r->limit_rate_after == 0) {
r->limit_rate_after = clcf->limit_rate_after;
} limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
- (c->sent - r->limit_rate_after); if (limit <= 0) {
c->write->delayed = 1;
delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1);
ngx_add_timer(c->write, delay); c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN;
} if (clcf->sendfile_max_chunk
&& (off_t) clcf->sendfile_max_chunk < limit)
{
limit = clcf->sendfile_max_chunk;
} } else {
limit = clcf->sendfile_max_chunk;
} sent = c->sent; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter limit %O", limit); 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;
} if (r->limit_rate) { nsent = c->sent; if (r->limit_rate_after) { sent -= r->limit_rate_after;
if (sent < 0) {
sent = 0;
} nsent -= r->limit_rate_after;
if (nsent < 0) {
nsent = 0;
}
} delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) {
limit = 0;
c->write->delayed = 1;
ngx_add_timer(c->write, delay);
}
} if (limit
&& c->write->ready
&& c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))
{
c->write->delayed = 1;
ngx_add_timer(c->write, 1);
} for (cl = r->out; cl && cl != chain; /* void */) {
ln = cl;
cl = cl->next;
ngx_free_chain(r->pool, ln);
} r->out = chain; if (chain) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
} c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
return NGX_AGAIN;
} return NGX_OK;
}

1.9.2 ngx_alloc_chain_link

ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t *pool)
{
ngx_chain_t *cl; cl = pool->chain; if (cl) {
pool->chain = cl->next;
return cl;
} /* 重新分配一个 ngx_chain_t */
cl = ngx_palloc(pool, sizeof(ngx_chain_t));
if (cl == NULL) {
return NULL;
} return cl;
}

Nginx-HTTP之ngx_http_top_header_filter的更多相关文章

  1. nginx入门

    1.   前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Ngi ...

  2. 《深入理解Nginx》阅读与实践(四):简单的HTTP过滤模块

    一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或调用ngx_http_o ...

  3. Emiller's Advanced Topics In Nginx Module Development

    Emiller的Nginx模块开发指南 By Evan Miller DRAFT: August 13, 2009 (changes) 翻译:Kongch @2010年1月5日 0:04am -- 2 ...

  4. nginx自定义模块记录上游服务器特定响应头

    功能,服务器通过扩展自定义命令,记录上游的服务器返回的特定响应头内容,记录到本地文件中 代码如下: /* * Copyright (C) Ciaos */ #include <ngx_confi ...

  5. nginx服务器屏蔽上游错误码

    平时的开发工作中,有时会遇到脚本权限不对导致403,文件被删除导致404,甚至后端业务异常导致5xx等情况,其实我们可以在服务器加上判断,检测当后端服务出现异常的时候前端返回一个指定的静态文件(也可以 ...

  6. nginx源代码分析--模块分类

    ngx-modules Nginx 基本的模块大致能够分为四类: handler – 协同完毕client请求的处理.产生响应数据.比方模块, ngx_http_rewrite_module, ngx ...

  7. Nginx 模块开发

    Nginx 模块概述 Nginx 模块有三种角色: 处理请求并产生输出的 Handler 模块 : 处理由  Handler  产生的输出的 Filter (滤波器)模块: 当出现多个后台 服务器时, ...

  8. nginx源代码分析--nginx模块解析

    nginx的模块很之多.能够觉得全部代码都是以模块的形式组织.这包含核心模块和功能模块,针对不同的应用场合.并不是全部的功能模块都要被用到,附录A给出的是默认configure(即简单的httpser ...

  9. Nginx:HTTP过滤模块

    参考资料<深入理解Nginx> HTTP过滤模块也是一种HTTP模块,与普通HTTP处理模块不同在于: 1.一个请求仅由一个HTTP处理模块处理,而可以被任意个HTTP过滤模块处理 2.普 ...

  10. 【Nginx】开发一个HTTP过滤模块

    与HTTP处理模块不同.HTTP过滤模块的工作是对发送给用户的HTTP响应做一些加工. server返回的一个响应能够被随意多个HTTP过滤模块以流水线的方式依次处理.HTTP响应分为头部和包体,ng ...

随机推荐

  1. Python中import导入上一级目录模块及循环import问题的解决

    转自:https://www.cnblogs.com/sjy18039225956/p/9265461.html 使用python进行程序编写时,经常会使用第三方模块包.这种包我们可以通过python ...

  2. Vue项目中使用AES加密

    1.在vue中安装crypto-js        备注:千万不要安装错了,中间是 ‘-’连接,不是‘.’ 2.在项目的工具文件夹中新建 encryption.js,用于定义加密和解密的方法,方便调用 ...

  3. java web开发跨域问题

    分布式环境,前后端分离背景下跨域问题 1.1 设置页面document.domain去把2个页面之间的跨域交互统一 一级域名相同的情况下 调用者和页面提供者进行一个协调 页面提供者要在document ...

  4. qt打包发布

    需要用到qt自带工具windeployqt.exe 安装 以qt 5.8.0为例 安装qt-opensource-windows-x86-mingw530-5.8.0.exe即可 构建Release版 ...

  5. bash shell脚本之使用expr运算

    bash shell中的数学运算 cat test7: #!/bin/bash # An example of using the expr command var1= var2= var3=`exp ...

  6. Java虚拟机内存基础、垃圾收集算法及JVM优化

    1 JVM 简单结构图   1.1 类加载子系统与方法区 类加载子系统负责从文件系统或者网络中加载 Class 信息,加载的类信息存放于一块称 为方法区的内存空间.除了类的信息外,方法区中可能还会存放 ...

  7. vs code 开发小程序会用到的插件

    主要介绍一下几个vscode插件,在vscode中搜索插件关键字点击安装即可. 1) vscode weapp api,  语法结构api; 2) minapp-vscode 3) vscode wx ...

  8. 手写走通HTTP server 第三版本

    后台 后端 服务端 功能:逻辑处理 算法处理    磁盘交互(数据库   静态文件处理) 要求:健壮性,安全性 并发性能和处理速度 架构合理便于维护扩展 网站后端 httpserver + WebFr ...

  9. 翻译应用将在Win8.1系统中取消下载安装

    自Windows8.Windows Phone 7.1和Windows Phone 8受到影响之后,微软又正式宣布停止对翻译应用提供支持服务.Microsoft Translator这款应用将从Win ...

  10. Hadoop_15_MapRduce_案例1_Wordcount 单词统计

    1.Wordcount示例编写: MapReduce采用”分而治之”的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个分节点共同完成,然后通过整合各 个节点的中间结果,得到最终结果.简单地说 ...