Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_gzip_filter.c @ 133:b27548f540ad
nginx-0.0.1-2003-09-24-23:51:12 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Wed, 24 Sep 2003 19:51:12 +0000 |
parents | |
children | d57c6835225c |
comparison
equal
deleted
inserted
replaced
132:949f45d1589a | 133:b27548f540ad |
---|---|
1 | |
2 #include <ngx_config.h> | |
3 #include <ngx_core.h> | |
4 #include <ngx_http.h> | |
5 | |
6 #include <zlib.h> | |
7 | |
8 | |
9 typedef struct { | |
10 int hunk_size; | |
11 int max_hunks; | |
12 int no_buffer; | |
13 } ngx_http_gzip_conf_t; | |
14 | |
15 | |
16 typedef struct { | |
17 ngx_chain_t *in; | |
18 ngx_chain_t *free; | |
19 ngx_chain_t *busy; | |
20 ngx_chain_t *out; | |
21 ngx_chain_t **last_out; | |
22 ngx_hunk_t *in_hunk; | |
23 ngx_hunk_t *out_hunk; | |
24 void *alloc; | |
25 | |
26 z_stream zstream; | |
27 } ngx_http_gzip_ctx_t; | |
28 | |
29 | |
30 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle); | |
31 | |
32 | |
33 static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { | |
34 NULL, /* create main configuration */ | |
35 NULL, /* init main configuration */ | |
36 | |
37 NULL, /* create server configuration */ | |
38 NULL, /* merge server configuration */ | |
39 | |
40 NULL, /* create location configuration */ | |
41 NULL, /* merge location configuration */ | |
42 }; | |
43 | |
44 | |
45 ngx_module_t ngx_http_gzip_filter_module = { | |
46 NGX_MODULE, | |
47 &ngx_http_gzip_filter_module_ctx, /* module context */ | |
48 NULL, /* module directives */ | |
49 NGX_HTTP_MODULE, /* module type */ | |
50 ngx_http_gzip_filter_init, /* init module */ | |
51 NULL /* init child */ | |
52 }; | |
53 | |
54 | |
55 static const char gzheader[10] = | |
56 { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; | |
57 | |
58 | |
59 static int (*next_header_filter) (ngx_http_request_t *r); | |
60 static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch); | |
61 | |
62 | |
63 static int ngx_http_gzip_header_filter(ngx_http_request_t *r) | |
64 { | |
65 if (r->headers_out.status != NGX_HTTP_OK | |
66 || (ngx_strncasecmp(r->headers_out.content_type->value.data, | |
67 "text/", 5) != 0) | |
68 { | |
69 return next_header_filter(r); | |
70 } | |
71 | |
72 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, | |
73 sizeof(ngx_http_gzip_filter_ctx_t), NGX_ERROR); | |
74 | |
75 ctx->length = r->headers_out.content_length; | |
76 r->headers_out.content_length = -1; | |
77 | |
78 return next_header_filter(r); | |
79 } | |
80 | |
81 | |
82 static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
83 { | |
84 ngx_http_gzip_ctx_t *ctx; | |
85 ngx_http_gzip_conf_t *conf; | |
86 | |
87 ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); | |
88 | |
89 if (ctx == NULL) { | |
90 next_body_filter(r, in); | |
91 } | |
92 | |
93 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); | |
94 | |
95 if (ctx->alloc == NULL) { | |
96 #if 0 | |
97 ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR); | |
98 #else | |
99 ctx->alloc = ~NULL; | |
100 #endif | |
101 rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED, | |
102 /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1, | |
103 Z_DEFAULT_STRATEGY); | |
104 | |
105 if (rc != Z_OK) { | |
106 ngx_log_error(NGX_LOG_ALERT, r->log, 0, | |
107 "deflateInit2() failed: %d", rc); | |
108 return ngx_http_gzip_error(ctx); | |
109 } | |
110 | |
111 ngx_test_null(h, ngx_calloc_hunk(r->pool), ngx_http_gzip_error(ctx)); | |
112 | |
113 h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_MEMORY; | |
114 h->pos = gzheader; | |
115 h->last = h->pos + 10; | |
116 | |
117 ngx_test_null(ce, ngx_alloc_chain_entry(r->pool), | |
118 ngx_http_gzip_error(ctx)); | |
119 ce->hunk = h; | |
120 ce->next = NULL; | |
121 ctx->out = ce; | |
122 ctx->last_out = &ce->next; | |
123 | |
124 ctx->crc32 = crc32(0L, Z_NULL, 0); | |
125 ctx->flush = Z_NO_FLUSH; | |
126 } | |
127 | |
128 if (in) { | |
129 add_to_chain(ctx->in, in) | |
130 } | |
131 | |
132 for ( ;; ) { | |
133 | |
134 for ( ;; ) { | |
135 | |
136 if (ctx->flush == Z_NO_FLUSH | |
137 && ctx->zstream->avail_in == 0 | |
138 && ctx->in) | |
139 { | |
140 ctx->in_hunk = ctx->in->hunk; | |
141 ctx->in = ctx->in->next; | |
142 | |
143 ctx->zstream->next_in = ctx->in_hunk->pos; | |
144 ctx->zstream->avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; | |
145 | |
146 if (ctx->in_hunk->type & NGX_HUNK_LAST) { | |
147 ctx->flush = Z_FINISH; | |
148 | |
149 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { | |
150 ctx->flush = Z_SYNC_FINISH; | |
151 } | |
152 } | |
153 | |
154 if (ctx->zstream->avail_out == 0) { | |
155 if (ctx->free) { | |
156 ctx->out_hunk = ctx->free->hunk; | |
157 ctx->free = ctx->free->next; | |
158 | |
159 } else if (ctx->max_hunks < ctx->cur_hunks) { | |
160 ngx_test_null(ctx->out_hunk, | |
161 ngx_create_temp_hunk(r->pool, conf->size, | |
162 0, 0), | |
163 ngx_http_gzip_error(ctx)); | |
164 ctx->cur_hunks++; | |
165 | |
166 } else { | |
167 break; | |
168 } | |
169 | |
170 ctx->zstream->next_out = ctx->out_hunk->pos; | |
171 ctx->zstream->avail_out = conf->size; | |
172 } | |
173 | |
174 rc = deflate(ctx->zstream, ctx->flush); | |
175 if (rc != Z_OK && rc != Z_STREAM_END) { | |
176 ngx_log_error(NGX_LOG_ALERT, r->log, 0, | |
177 "deflate() failed: %d, %d", ctx->flush, rc); | |
178 return ngx_http_gzip_error(ctx); | |
179 } | |
180 | |
181 ctx->in_hunk->pos = ctx->zstream->next_in; | |
182 | |
183 if (rc == Z_STREAM_END) { | |
184 deflateEnd(ctx->zstream); | |
185 ngx_free(); | |
186 } | |
187 | |
188 if (ctx->zstream->avail_out == 0) { | |
189 ctx->out_hunk->last += conf->size; | |
190 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | |
191 r->pool, ngx_http_gzip_error(ctx)); | |
192 | |
193 } else { | |
194 ctx->out_hunk->last = ctx->zstream->next_out; | |
195 | |
196 if (ctx->flush == Z_SYNC_FLUSH) { | |
197 ctx->out_hunk->type |= NGX_HUNK_FLUSH; | |
198 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | |
199 r->pool, ngx_http_gzip_error(ctx)); | |
200 ctx->flush = Z_NO_FLUSH; | |
201 break; | |
202 | |
203 } else if (ctx->flush == Z_FINISH) { | |
204 ctx->out_hunk->type |= NGX_HUNK_LAST; | |
205 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | |
206 r->pool, ngx_http_gzip_error(ctx)); | |
207 break; | |
208 | |
209 } else if (conf->no_buffer && ctx->in == NULL) { | |
210 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | |
211 r->pool, ngx_http_gzip_error(ctx)); | |
212 break; | |
213 } | |
214 } | |
215 } | |
216 | |
217 if (next_body_filter(r, ctx->out) == NGX_ERROR) { | |
218 return ngx_http_gzip_error(ctx); | |
219 } | |
220 | |
221 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); | |
222 } | |
223 } | |
224 | |
225 | |
226 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) | |
227 { | |
228 #if 0 | |
229 ngx_free(ctx->alloc); | |
230 #endif | |
231 | |
232 return NGX_ERROR; | |
233 } | |
234 | |
235 | |
236 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle) | |
237 { | |
238 next_header_filter = ngx_http_top_header_filter; | |
239 ngx_http_top_header_filter = ngx_http_gzip_header_filter; | |
240 | |
241 next_body_filter = ngx_http_top_body_filter; | |
242 ngx_http_top_body_filter = ngx_http_gzip_body_filter; | |
243 | |
244 return NGX_OK; | |
245 } |