nginx中gzip_types是如何匹配content-type的
1.背景
我们系统中有⼀个功能,可以配置content-type类型来决定是否打开gzip压缩。这个配置与nginx官⽅的gzip_type不同的地⽅在于,nginx 官⽅的是写死在配置⽂件中的,所有请求都⽣效;我们⾃研的是,不同⽤户的gzip_type可以不同。
最近发现⼀个问题,content-type配置为:image/jpeg,但是后端响应的Content-Type为"
image/jped;charset:UTF-8"时,由于代码中是将配置的content-type与响应头中字符串作精确⽐较,因此,上述场景,并不能正确打开gzip功能。
nginx对此是如何处理的呢?
后端响应的Content-Type保持为image/jped;charset:UTF-8。
1、配置gzip_type 如下,gzip⽣效:
gzip_type image/jpeg;
2、配置gzip_type如下,gzip不⽣效:(nginx官⽅⽂档中也没有提及下⾯的配置⽅法)
gzip_type "image/jpeg;charset:UTF-8";
在进⾏header_filter时,对content-Type做了校验:
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->t_encoding
&& r->t_encoding->value.len)
||(r->t_length_n !=-1
&& r->t_length_n < conf->min_length)
// ngx_http_test_content_type中对content_type做了校验
||ngx_http_test_content_type(r,&conf->types)==NULL
|| r->header_only)
{
return ngx_http_next_header_filter(r);
}
...
}
ngx_http_test_content_type定义如下:
void*
ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash)
{
u_char      c,*lowcase;
size_t      len;
ngx_uint_t  i, hash;
if(types_hash->size ==0){
return(void*)4;
}
if(r->t_type.len ==0){
return NULL;
}
len = r->t_type_len;
if(r->t_type_lowcase ==NULL){
lowcase =ngx_pnalloc(r->pool, len);
if(lowcase ==NULL){
return NULL;
}
r->t_type_lowcase = lowcase;
hash =0;
for(i =0; i < len; i++){
c =ngx_tolower(r->t_type.data[i]);
hash =ngx_hash(hash, c);
lowcase[i]= c;
}
r->t_type_hash = hash;
}
return ngx_hash_find(types_hash, r->t_type_hash,
r->t_type_lowcase, len);
}
可以看出,将content-type头域内容转换为了⼩写,并使⽤了r->t_type_len长度的内容,与配置的types进⾏⽐较。但是针对第1种情况,配置和实际响应头明明是不相等的啊,是这么匹配成功的?
使⽤gdb打断点,发现
r->t_type为:
{len = 24, data = “image/jpeg;charset=UTF-8”}
但是,
r->t_type_len却是10!这个与上⾯为什么不⼀致呢?
到设置content_type的地⽅:
static ngx_int_t
ngx_http_set_content_type_header(ngx_http_request_t *r,
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
{
ngx_uint_t          i;
// 此时,r->t_type_len与 value->len 还是相等的
r->t_type_len = value->len;
#if 1
for(i =0; i < value->len; i++){
if(value->data[i]==';'){
// 到第⼀个分号,然后修改了r->t_type_len
r->t_type_len = i;
types是什么意思break;
}
}
#endif
r->t_type =*value;
r->t_type_hash = hv->hash;
r->t_type_lowcase =NULL;
value->len =0;
return ngx_http_set_header_helper(r, hv, value,NULL,1);
}
可以看出,nginx只使⽤了Content-Type响应头中第⼀个分号前的内容进⾏匹配。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。