Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_gzip_filter.c @ 134:d57c6835225c
nginx-0.0.1-2003-09-26-09:45:21 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 26 Sep 2003 05:45:21 +0000 |
parents | b27548f540ad |
children | e29909bd9b8a |
comparison
equal
deleted
inserted
replaced
133:b27548f540ad | 134:d57c6835225c |
---|---|
5 | 5 |
6 #include <zlib.h> | 6 #include <zlib.h> |
7 | 7 |
8 | 8 |
9 typedef struct { | 9 typedef struct { |
10 int enable; | |
10 int hunk_size; | 11 int hunk_size; |
11 int max_hunks; | 12 int hunks; |
12 int no_buffer; | 13 int no_buffer; |
13 } ngx_http_gzip_conf_t; | 14 } ngx_http_gzip_conf_t; |
14 | 15 |
15 | 16 |
16 typedef struct { | 17 typedef struct { |
19 ngx_chain_t *busy; | 20 ngx_chain_t *busy; |
20 ngx_chain_t *out; | 21 ngx_chain_t *out; |
21 ngx_chain_t **last_out; | 22 ngx_chain_t **last_out; |
22 ngx_hunk_t *in_hunk; | 23 ngx_hunk_t *in_hunk; |
23 ngx_hunk_t *out_hunk; | 24 ngx_hunk_t *out_hunk; |
25 int hunks; | |
26 | |
27 int length; | |
24 void *alloc; | 28 void *alloc; |
25 | 29 |
30 int flush; | |
31 u_int crc32; | |
26 z_stream zstream; | 32 z_stream zstream; |
27 } ngx_http_gzip_ctx_t; | 33 } ngx_http_gzip_ctx_t; |
28 | 34 |
29 | 35 |
36 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); | |
30 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle); | 37 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle); |
38 static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); | |
39 static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, | |
40 void *parent, void *child); | |
41 | |
42 | |
43 static ngx_command_t ngx_http_gzip_filter_commands[] = { | |
44 | |
45 {ngx_string("gzip"), | |
46 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
47 ngx_conf_set_flag_slot, | |
48 NGX_HTTP_LOC_CONF_OFFSET, | |
49 offsetof(ngx_http_gzip_conf_t, enable), | |
50 NULL}, | |
51 | |
52 {ngx_string("gzip_hunk_size"), | |
53 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
54 ngx_conf_set_size_slot, | |
55 NGX_HTTP_LOC_CONF_OFFSET, | |
56 offsetof(ngx_http_gzip_conf_t, hunk_size), | |
57 NULL}, | |
58 | |
59 {ngx_string("gzip_hunks"), | |
60 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
61 ngx_conf_set_num_slot, | |
62 NGX_HTTP_LOC_CONF_OFFSET, | |
63 offsetof(ngx_http_gzip_conf_t, hunks), | |
64 NULL}, | |
65 | |
66 {ngx_string("gzip_no_buffer"), | |
67 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
68 ngx_conf_set_flag_slot, | |
69 NGX_HTTP_LOC_CONF_OFFSET, | |
70 offsetof(ngx_http_gzip_conf_t, no_buffer), | |
71 NULL}, | |
72 | |
73 ngx_null_command | |
74 }; | |
31 | 75 |
32 | 76 |
33 static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { | 77 static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { |
34 NULL, /* create main configuration */ | 78 NULL, /* create main configuration */ |
35 NULL, /* init main configuration */ | 79 NULL, /* init main configuration */ |
36 | 80 |
37 NULL, /* create server configuration */ | 81 NULL, /* create server configuration */ |
38 NULL, /* merge server configuration */ | 82 NULL, /* merge server configuration */ |
39 | 83 |
40 NULL, /* create location configuration */ | 84 ngx_http_gzip_create_conf, /* create location configuration */ |
41 NULL, /* merge location configuration */ | 85 ngx_http_gzip_merge_conf, /* merge location configuration */ |
42 }; | 86 }; |
43 | 87 |
44 | 88 |
45 ngx_module_t ngx_http_gzip_filter_module = { | 89 ngx_module_t ngx_http_gzip_filter_module = { |
46 NGX_MODULE, | 90 NGX_MODULE, |
47 &ngx_http_gzip_filter_module_ctx, /* module context */ | 91 &ngx_http_gzip_filter_module_ctx, /* module context */ |
48 NULL, /* module directives */ | 92 ngx_http_gzip_filter_commands, /* module directives */ |
49 NGX_HTTP_MODULE, /* module type */ | 93 NGX_HTTP_MODULE, /* module type */ |
50 ngx_http_gzip_filter_init, /* init module */ | 94 ngx_http_gzip_filter_init, /* init module */ |
51 NULL /* init child */ | 95 NULL /* init child */ |
52 }; | 96 }; |
53 | 97 |
54 | 98 |
55 static const char gzheader[10] = | 99 static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; |
56 { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; | 100 |
101 #if (HAVE_LITTLE_ENDIAN) | |
102 | |
103 struct gztrailer { | |
104 u_int crc32; | |
105 u_int zlen; | |
106 }; | |
107 | |
108 #else /* HAVE_BIG_ENDIAN */ | |
109 | |
110 struct gztrailer { | |
111 unsigned char crc32[4]; | |
112 unsigned char zlen[4]; | |
113 }; | |
114 | |
115 #endif | |
116 | |
57 | 117 |
58 | 118 |
59 static int (*next_header_filter) (ngx_http_request_t *r); | 119 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); | 120 static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch); |
61 | 121 |
62 | 122 |
63 static int ngx_http_gzip_header_filter(ngx_http_request_t *r) | 123 static int ngx_http_gzip_header_filter(ngx_http_request_t *r) |
64 { | 124 { |
125 ngx_http_gzip_ctx_t *ctx; | |
126 ngx_http_gzip_conf_t *conf; | |
127 | |
65 if (r->headers_out.status != NGX_HTTP_OK | 128 if (r->headers_out.status != NGX_HTTP_OK |
66 || (ngx_strncasecmp(r->headers_out.content_type->value.data, | 129 || r->header_only |
130 /* || r->content_encoding */ | |
131 /* || r->accept_encoding == NULL */ | |
132 || r->main) | |
133 { | |
134 return next_header_filter(r); | |
135 } | |
136 | |
137 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); | |
138 | |
139 if (!conf->enable | |
140 /* TODO: conf->version */ | |
141 /* TODO: "text/" -> custom types */ | |
142 || ngx_strncasecmp(r->headers_out.content_type->value.data, | |
67 "text/", 5) != 0) | 143 "text/", 5) != 0) |
68 { | 144 { |
69 return next_header_filter(r); | 145 return next_header_filter(r); |
70 } | 146 } |
71 | 147 |
72 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, | 148 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, |
73 sizeof(ngx_http_gzip_filter_ctx_t), NGX_ERROR); | 149 sizeof(ngx_http_gzip_ctx_t), NGX_ERROR); |
74 | 150 |
75 ctx->length = r->headers_out.content_length; | 151 ctx->length = r->headers_out.content_length; |
76 r->headers_out.content_length = -1; | 152 r->headers_out.content_length = -1; |
153 r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY; | |
77 | 154 |
78 return next_header_filter(r); | 155 return next_header_filter(r); |
79 } | 156 } |
80 | 157 |
81 | 158 |
82 static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | 159 static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) |
83 { | 160 { |
161 int rc, zin, zout; | |
162 struct gztrailer *trailer; | |
163 ngx_hunk_t *h; | |
164 ngx_chain_t *ce; | |
84 ngx_http_gzip_ctx_t *ctx; | 165 ngx_http_gzip_ctx_t *ctx; |
85 ngx_http_gzip_conf_t *conf; | 166 ngx_http_gzip_conf_t *conf; |
86 | 167 |
87 ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); | 168 ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); |
88 | 169 |
89 if (ctx == NULL) { | 170 if (ctx == NULL) { |
90 next_body_filter(r, in); | 171 return next_body_filter(r, in); |
91 } | 172 } |
92 | 173 |
93 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); | 174 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); |
94 | 175 |
95 if (ctx->alloc == NULL) { | 176 if (ctx->alloc == NULL) { |
96 #if 0 | 177 #if 0 |
97 ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR); | 178 ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR); |
98 #else | 179 #else |
99 ctx->alloc = ~NULL; | 180 ctx->alloc = (void *) ~NULL; |
100 #endif | 181 #endif |
101 rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED, | 182 rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED, |
102 /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1, | 183 /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1, |
103 Z_DEFAULT_STRATEGY); | 184 Z_DEFAULT_STRATEGY); |
104 | 185 |
105 if (rc != Z_OK) { | 186 if (rc != Z_OK) { |
106 ngx_log_error(NGX_LOG_ALERT, r->log, 0, | 187 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
107 "deflateInit2() failed: %d", rc); | 188 "deflateInit2() failed: %d", rc); |
108 return ngx_http_gzip_error(ctx); | 189 return ngx_http_gzip_error(ctx); |
109 } | 190 } |
110 | 191 |
111 ngx_test_null(h, ngx_calloc_hunk(r->pool), ngx_http_gzip_error(ctx)); | 192 ngx_test_null(h, ngx_calloc_hunk(r->pool), ngx_http_gzip_error(ctx)); |
124 ctx->crc32 = crc32(0L, Z_NULL, 0); | 205 ctx->crc32 = crc32(0L, Z_NULL, 0); |
125 ctx->flush = Z_NO_FLUSH; | 206 ctx->flush = Z_NO_FLUSH; |
126 } | 207 } |
127 | 208 |
128 if (in) { | 209 if (in) { |
129 add_to_chain(ctx->in, in) | 210 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { |
130 } | 211 return ngx_http_gzip_error(ctx); |
131 | 212 } |
132 for ( ;; ) { | 213 } |
133 | 214 |
215 while (ctx->in || ctx->out | |
216 || ctx->zstream.avail_in || ctx->zstream.avail_out | |
217 || ctx->flush != Z_NO_FLUSH) | |
218 { | |
134 for ( ;; ) { | 219 for ( ;; ) { |
135 | 220 |
136 if (ctx->flush == Z_NO_FLUSH | 221 if (ctx->in |
137 && ctx->zstream->avail_in == 0 | 222 && ctx->zstream.avail_in == 0 |
138 && ctx->in) | 223 && ctx->flush == Z_NO_FLUSH) |
139 { | 224 { |
140 ctx->in_hunk = ctx->in->hunk; | 225 ctx->in_hunk = ctx->in->hunk; |
141 ctx->in = ctx->in->next; | 226 ctx->in = ctx->in->next; |
142 | 227 |
143 ctx->zstream->next_in = ctx->in_hunk->pos; | 228 ctx->zstream.avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; |
144 ctx->zstream->avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; | 229 |
230 if (ctx->zstream.avail_in == 0) { | |
231 continue; | |
232 } | |
233 | |
234 ctx->zstream.next_in = ctx->in_hunk->pos; | |
235 | |
236 ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, | |
237 ctx->zstream.avail_in); | |
145 | 238 |
146 if (ctx->in_hunk->type & NGX_HUNK_LAST) { | 239 if (ctx->in_hunk->type & NGX_HUNK_LAST) { |
147 ctx->flush = Z_FINISH; | 240 ctx->flush = Z_FINISH; |
148 | 241 |
149 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { | 242 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { |
150 ctx->flush = Z_SYNC_FINISH; | 243 ctx->flush = Z_SYNC_FLUSH; |
151 } | 244 } |
152 } | 245 } |
153 | 246 |
154 if (ctx->zstream->avail_out == 0) { | 247 if (ctx->zstream.avail_out == 0) { |
155 if (ctx->free) { | 248 if (ctx->free) { |
156 ctx->out_hunk = ctx->free->hunk; | 249 ctx->out_hunk = ctx->free->hunk; |
157 ctx->free = ctx->free->next; | 250 ctx->free = ctx->free->next; |
158 | 251 |
159 } else if (ctx->max_hunks < ctx->cur_hunks) { | 252 } else if (ctx->hunks < conf->hunks) { |
160 ngx_test_null(ctx->out_hunk, | 253 ngx_test_null(ctx->out_hunk, |
161 ngx_create_temp_hunk(r->pool, conf->size, | 254 ngx_create_temp_hunk(r->pool, conf->hunk_size, |
162 0, 0), | 255 0, 0), |
163 ngx_http_gzip_error(ctx)); | 256 ngx_http_gzip_error(ctx)); |
164 ctx->cur_hunks++; | 257 ctx->hunks++; |
165 | 258 |
166 } else { | 259 } else { |
167 break; | 260 break; |
168 } | 261 } |
169 | 262 |
170 ctx->zstream->next_out = ctx->out_hunk->pos; | 263 ctx->zstream.next_out = ctx->out_hunk->pos; |
171 ctx->zstream->avail_out = conf->size; | 264 ctx->zstream.avail_out = conf->hunk_size; |
172 } | 265 } |
173 | 266 |
174 rc = deflate(ctx->zstream, ctx->flush); | 267 rc = deflate(&ctx->zstream, ctx->flush); |
175 if (rc != Z_OK && rc != Z_STREAM_END) { | 268 if (rc != Z_OK && rc != Z_STREAM_END) { |
176 ngx_log_error(NGX_LOG_ALERT, r->log, 0, | 269 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
177 "deflate() failed: %d, %d", ctx->flush, rc); | 270 "deflate() failed: %d, %d", ctx->flush, rc); |
178 return ngx_http_gzip_error(ctx); | 271 return ngx_http_gzip_error(ctx); |
179 } | 272 } |
180 | 273 |
181 ctx->in_hunk->pos = ctx->zstream->next_in; | 274 ngx_log_debug(r->connection->log, "deflate(): %d %d" _ ctx->flush _ rc); |
182 | 275 |
183 if (rc == Z_STREAM_END) { | 276 ctx->in_hunk->pos = ctx->zstream.next_in; |
184 deflateEnd(ctx->zstream); | 277 |
185 ngx_free(); | 278 if (ctx->zstream.avail_out == 0) { |
186 } | 279 ctx->out_hunk->last += conf->hunk_size; |
187 | 280 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, |
188 if (ctx->zstream->avail_out == 0) { | 281 ngx_http_gzip_error(ctx)); |
189 ctx->out_hunk->last += conf->size; | 282 *ctx->last_out = ce; |
190 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | 283 ctx->last_out = &ce->next; |
191 r->pool, ngx_http_gzip_error(ctx)); | |
192 | 284 |
193 } else { | 285 } else { |
194 ctx->out_hunk->last = ctx->zstream->next_out; | 286 ctx->out_hunk->last = ctx->zstream.next_out; |
195 | 287 |
196 if (ctx->flush == Z_SYNC_FLUSH) { | 288 if (ctx->flush == Z_SYNC_FLUSH) { |
197 ctx->out_hunk->type |= NGX_HUNK_FLUSH; | 289 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; | 290 ctx->flush = Z_NO_FLUSH; |
291 | |
292 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, | |
293 ngx_http_gzip_error(ctx)); | |
294 *ctx->last_out = ce; | |
295 ctx->last_out = &ce->next; | |
296 | |
201 break; | 297 break; |
202 | 298 |
203 } else if (ctx->flush == Z_FINISH) { | 299 } else if (ctx->flush == Z_FINISH) { |
204 ctx->out_hunk->type |= NGX_HUNK_LAST; | 300 /* rc == Z_STREAM_END */ |
205 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | 301 |
206 r->pool, ngx_http_gzip_error(ctx)); | 302 zin = ctx->zstream.total_in; |
303 zout = 10 + ctx->zstream.total_out + 8; | |
304 | |
305 ctx->flush = Z_NO_FLUSH; | |
306 | |
307 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, | |
308 ngx_http_gzip_error(ctx)); | |
309 *ctx->last_out = ce; | |
310 ctx->last_out = &ce->next; | |
311 | |
312 if (ctx->zstream.avail_out >= 8) { | |
313 trailer = (struct gztrailer *) &ctx->zstream.avail_in; | |
314 ctx->out_hunk->type |= NGX_HUNK_LAST; | |
315 ctx->out_hunk->last += 8; | |
316 | |
317 } else { | |
318 /* STUB */ trailer = NULL; | |
319 } | |
320 | |
321 #if (HAVE_LITTLE_ENDIAN) | |
322 trailer->crc32 = ctx->crc32; | |
323 trailer->zlen = zin; | |
324 #else | |
325 /* STUB */ | |
326 #endif | |
327 | |
328 deflateEnd(&ctx->zstream); | |
329 #if 0 | |
330 ngx_free(); | |
331 set ctx = NULL; | |
332 #endif | |
207 break; | 333 break; |
208 | 334 |
209 } else if (conf->no_buffer && ctx->in == NULL) { | 335 } else if (conf->no_buffer && ctx->in == NULL) { |
210 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, | 336 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, |
211 r->pool, ngx_http_gzip_error(ctx)); | 337 ngx_http_gzip_error(ctx)); |
338 *ctx->last_out = ce; | |
339 ctx->last_out = &ce->next; | |
340 | |
212 break; | 341 break; |
213 } | 342 } |
214 } | 343 } |
215 } | 344 } |
216 | 345 |
217 if (next_body_filter(r, ctx->out) == NGX_ERROR) { | 346 rc = next_body_filter(r, ctx->out); |
347 if (rc == NGX_ERROR) { | |
218 return ngx_http_gzip_error(ctx); | 348 return ngx_http_gzip_error(ctx); |
219 } | 349 } |
220 | 350 |
221 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); | 351 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); |
222 } | 352 ctx->last_out = &ctx->out; |
353 } | |
354 | |
355 /* STUB */ | |
356 return next_body_filter(r, NULL); | |
223 } | 357 } |
224 | 358 |
225 | 359 |
226 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) | 360 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) |
227 { | 361 { |
241 next_body_filter = ngx_http_top_body_filter; | 375 next_body_filter = ngx_http_top_body_filter; |
242 ngx_http_top_body_filter = ngx_http_gzip_body_filter; | 376 ngx_http_top_body_filter = ngx_http_gzip_body_filter; |
243 | 377 |
244 return NGX_OK; | 378 return NGX_OK; |
245 } | 379 } |
380 | |
381 | |
382 static void *ngx_http_gzip_create_conf(ngx_conf_t *cf) | |
383 { | |
384 ngx_http_gzip_conf_t *conf; | |
385 | |
386 ngx_test_null(conf, | |
387 ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)), | |
388 NGX_CONF_ERROR); | |
389 | |
390 conf->enable = NGX_CONF_UNSET; | |
391 conf->hunk_size = NGX_CONF_UNSET; | |
392 conf->hunks = NGX_CONF_UNSET; | |
393 conf->no_buffer = NGX_CONF_UNSET; | |
394 | |
395 return conf; | |
396 } | |
397 | |
398 | |
399 static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, | |
400 void *parent, void *child) | |
401 { | |
402 ngx_http_gzip_conf_t *prev = parent; | |
403 ngx_http_gzip_conf_t *conf = child; | |
404 | |
405 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
406 ngx_conf_merge_size_value(conf->hunk_size, prev->hunk_size, | |
407 /* STUB: PAGE_SIZE */ 4096); | |
408 ngx_conf_merge_value(conf->hunks, prev->hunks, 4); | |
409 ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); | |
410 | |
411 return NGX_CONF_OK; | |
412 } |