📄 ngx_http_gzip_filter_module.c
字号:
/* * Copyright (C) Igor Sysoev */#include <ngx_config.h>#include <ngx_core.h>#include <ngx_http.h>#include <zlib.h>typedef struct { ngx_flag_t enable; ngx_flag_t no_buffer; ngx_flag_t vary; ngx_array_t *types; /* array of ngx_str_t */ ngx_bufs_t bufs; ngx_uint_t http_version; ngx_uint_t proxied; ngx_int_t level; size_t wbits; size_t memlevel; ssize_t min_length;} ngx_http_gzip_conf_t;#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200typedef struct { ngx_chain_t *in; ngx_chain_t *free; ngx_chain_t *busy; ngx_chain_t *out; ngx_chain_t **last_out; ngx_buf_t *in_buf; ngx_buf_t *out_buf; ngx_int_t bufs; off_t length; void *preallocated; char *free_mem; ngx_uint_t allocated; unsigned flush:4; unsigned redo:1; unsigned done:1; size_t zin; size_t zout; uint32_t crc32; z_stream zstream; ngx_http_request_t *request;} ngx_http_gzip_ctx_t;static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf);static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size);static void ngx_http_gzip_filter_free(void *opaque, void *address);static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf);static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);static ngx_int_t ngx_http_gzip_filter_init(ngx_conf_t *cf);static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child);static char *ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);static ngx_conf_num_bounds_t ngx_http_gzip_comp_level_bounds = { ngx_conf_check_num_bounds, 1, 9};static ngx_conf_post_handler_pt ngx_http_gzip_window_p = ngx_http_gzip_window;static ngx_conf_post_handler_pt ngx_http_gzip_hash_p = ngx_http_gzip_hash;static ngx_conf_enum_t ngx_http_gzip_http_version[] = { { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, { ngx_null_string, 0 }};static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, { ngx_null_string, 0 }};static ngx_command_t ngx_http_gzip_filter_commands[] = { { ngx_string("gzip"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, enable), NULL }, { ngx_string("gzip_buffers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_bufs_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, bufs), NULL }, { ngx_string("gzip_types"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_http_gzip_types, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, { ngx_string("gzip_comp_level"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, level), &ngx_http_gzip_comp_level_bounds }, { ngx_string("gzip_window"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, wbits), &ngx_http_gzip_window_p }, { ngx_string("gzip_hash"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, memlevel), &ngx_http_gzip_hash_p }, { ngx_string("gzip_no_buffer"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, no_buffer), NULL }, { ngx_string("gzip_http_version"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, http_version), &ngx_http_gzip_http_version }, { ngx_string("gzip_proxied"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, proxied), &ngx_http_gzip_proxied_mask }, { ngx_string("gzip_min_length"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, min_length), NULL }, { ngx_string("gzip_vary"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, vary), NULL }, ngx_null_command};static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { ngx_http_gzip_add_variables, /* preconfiguration */ ngx_http_gzip_filter_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_gzip_create_conf, /* create location configuration */ ngx_http_gzip_merge_conf /* merge location configuration */};ngx_module_t ngx_http_gzip_filter_module = { NGX_MODULE_V1, &ngx_http_gzip_filter_module_ctx, /* module context */ ngx_http_gzip_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING};static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)struct gztrailer { uint32_t crc32; uint32_t zlen;};#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */struct gztrailer { u_char crc32[4]; u_char zlen[4];};#endifstatic ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio");static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache");static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store");static ngx_str_t ngx_http_gzip_private = ngx_string("private");static ngx_http_output_header_filter_pt ngx_http_next_header_filter;static ngx_http_output_body_filter_pt ngx_http_next_body_filter;static ngx_int_tngx_http_gzip_header_filter(ngx_http_request_t *r){ ngx_str_t *type; ngx_uint_t i; ngx_table_elt_t *header; 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->header_only || r != r->main || r->http_version < conf->http_version || r->headers_out.content_type.len == 0 || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) || r->headers_in.accept_encoding == NULL || (r->headers_out.content_length_n != -1 && r->headers_out.content_length_n < conf->min_length) || ngx_strcasestrn(r->headers_in.accept_encoding->value.data, "gzip", 4 - 1) == NULL ) { return ngx_http_next_header_filter(r); } type = conf->types->elts; for (i = 0; i < conf->types->nelts; i++) { if (r->headers_out.content_type.len >= type[i].len && ngx_strncasecmp(r->headers_out.content_type.data, type[i].data, type[i].len) == 0) { goto found; } } return ngx_http_next_header_filter(r);found: if (r->headers_in.via) { if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) { return ngx_http_next_header_filter(r); } if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_ANY) && ngx_http_gzip_proxied(r, conf) == NGX_DECLINED) { return ngx_http_next_header_filter(r); } } /* * if the URL (without the "http://" prefix) is longer than 253 bytes * then MSIE 4.x can not handle the compressed stream - it waits too long, * hangs up or crashes */ if (r->headers_in.msie4 && r->unparsed_uri.len > 200) { 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; header = ngx_list_push(&r->headers_out.headers); if (header == NULL) { return NGX_ERROR; } header->hash = 1; header->key.len = sizeof("Content-Encoding") - 1; header->key.data = (u_char *) "Content-Encoding"; header->value.len = sizeof("gzip") - 1; header->value.data = (u_char *) "gzip"; r->headers_out.content_encoding = header; if (conf->vary) { header = ngx_list_push(&r->headers_out.headers); if (header == NULL) { return NGX_ERROR; } header->hash = 1; header->key.len = sizeof("Vary") - 1; header->key.data = (u_char *) "Vary"; header->value.len = sizeof("Accept-Encoding") - 1; header->value.data = (u_char *) "Accept-Encoding"; } ctx->length = r->headers_out.content_length_n; r->main_filter_need_in_memory = 1; ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); return ngx_http_next_header_filter(r);}static ngx_int_tngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf){ time_t date, expires; if (r->headers_in.authorization && (conf->proxied & NGX_HTTP_GZIP_PROXIED_AUTH)) { return NGX_OK; } if (r->headers_out.expires) { if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { return NGX_DECLINED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -