Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_gunzip_filter_module.c @ 5503:d049b0ea00a3
SSL: ssl_session_tickets directive.
This adds support so it's possible to explicitly disable SSL Session
Tickets. In order to have good Forward Secrecy support either the
session ticket key has to be reloaded by using nginx' binary upgrade
process or using an external key file and reloading the configuration.
This directive adds another possibility to have good support by
disabling session tickets altogether.
If session tickets are enabled and the process lives for a long a time,
an attacker can grab the session ticket from the process and use that to
decrypt any traffic that occured during the entire lifetime of the
process.
author | Dirkjan Bussink <d.bussink@gmail.com> |
---|---|
date | Fri, 10 Jan 2014 16:12:40 +0100 |
parents | 6aa75f4982ce |
children | e491b26fa5a1 |
rev | line source |
---|---|
4837 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 * Copyright (C) Maxim Dounin | |
5 * Copyright (C) Nginx, Inc. | |
6 */ | |
7 | |
8 | |
9 #include <ngx_config.h> | |
10 #include <ngx_core.h> | |
11 #include <ngx_http.h> | |
12 | |
13 #include <zlib.h> | |
14 | |
15 | |
16 typedef struct { | |
17 ngx_flag_t enable; | |
18 ngx_bufs_t bufs; | |
19 } ngx_http_gunzip_conf_t; | |
20 | |
21 | |
22 typedef struct { | |
23 ngx_chain_t *in; | |
24 ngx_chain_t *free; | |
25 ngx_chain_t *busy; | |
26 ngx_chain_t *out; | |
27 ngx_chain_t **last_out; | |
28 | |
29 ngx_buf_t *in_buf; | |
30 ngx_buf_t *out_buf; | |
31 ngx_int_t bufs; | |
32 | |
33 unsigned started:1; | |
34 unsigned flush:4; | |
35 unsigned redo:1; | |
36 unsigned done:1; | |
37 unsigned nomem:1; | |
38 | |
39 z_stream zstream; | |
40 ngx_http_request_t *request; | |
41 } ngx_http_gunzip_ctx_t; | |
42 | |
43 | |
44 static ngx_int_t ngx_http_gunzip_filter_inflate_start(ngx_http_request_t *r, | |
45 ngx_http_gunzip_ctx_t *ctx); | |
46 static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, | |
47 ngx_http_gunzip_ctx_t *ctx); | |
48 static ngx_int_t ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, | |
49 ngx_http_gunzip_ctx_t *ctx); | |
50 static ngx_int_t ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, | |
51 ngx_http_gunzip_ctx_t *ctx); | |
52 static ngx_int_t ngx_http_gunzip_filter_inflate_end(ngx_http_request_t *r, | |
53 ngx_http_gunzip_ctx_t *ctx); | |
54 | |
55 static void *ngx_http_gunzip_filter_alloc(void *opaque, u_int items, | |
56 u_int size); | |
57 static void ngx_http_gunzip_filter_free(void *opaque, void *address); | |
58 | |
59 static ngx_int_t ngx_http_gunzip_filter_init(ngx_conf_t *cf); | |
60 static void *ngx_http_gunzip_create_conf(ngx_conf_t *cf); | |
61 static char *ngx_http_gunzip_merge_conf(ngx_conf_t *cf, | |
62 void *parent, void *child); | |
63 | |
64 | |
65 static ngx_command_t ngx_http_gunzip_filter_commands[] = { | |
66 | |
67 { ngx_string("gunzip"), | |
68 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
69 ngx_conf_set_flag_slot, | |
70 NGX_HTTP_LOC_CONF_OFFSET, | |
71 offsetof(ngx_http_gunzip_conf_t, enable), | |
72 NULL }, | |
73 | |
74 { ngx_string("gunzip_buffers"), | |
75 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
76 ngx_conf_set_bufs_slot, | |
77 NGX_HTTP_LOC_CONF_OFFSET, | |
78 offsetof(ngx_http_gunzip_conf_t, bufs), | |
79 NULL }, | |
80 | |
81 ngx_null_command | |
82 }; | |
83 | |
84 | |
85 static ngx_http_module_t ngx_http_gunzip_filter_module_ctx = { | |
86 NULL, /* preconfiguration */ | |
87 ngx_http_gunzip_filter_init, /* postconfiguration */ | |
88 | |
89 NULL, /* create main configuration */ | |
90 NULL, /* init main configuration */ | |
91 | |
92 NULL, /* create server configuration */ | |
93 NULL, /* merge server configuration */ | |
94 | |
95 ngx_http_gunzip_create_conf, /* create location configuration */ | |
96 ngx_http_gunzip_merge_conf /* merge location configuration */ | |
97 }; | |
98 | |
99 | |
100 ngx_module_t ngx_http_gunzip_filter_module = { | |
101 NGX_MODULE_V1, | |
102 &ngx_http_gunzip_filter_module_ctx, /* module context */ | |
103 ngx_http_gunzip_filter_commands, /* module directives */ | |
104 NGX_HTTP_MODULE, /* module type */ | |
105 NULL, /* init master */ | |
106 NULL, /* init module */ | |
107 NULL, /* init process */ | |
108 NULL, /* init thread */ | |
109 NULL, /* exit thread */ | |
110 NULL, /* exit process */ | |
111 NULL, /* exit master */ | |
112 NGX_MODULE_V1_PADDING | |
113 }; | |
114 | |
115 | |
116 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; | |
117 static ngx_http_output_body_filter_pt ngx_http_next_body_filter; | |
118 | |
119 | |
120 static ngx_int_t | |
121 ngx_http_gunzip_header_filter(ngx_http_request_t *r) | |
122 { | |
123 ngx_http_gunzip_ctx_t *ctx; | |
124 ngx_http_gunzip_conf_t *conf; | |
125 | |
126 conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); | |
127 | |
128 /* TODO support multiple content-codings */ | |
129 /* TODO always gunzip - due to configuration or module request */ | |
130 /* TODO ignore content encoding? */ | |
131 | |
132 if (!conf->enable | |
133 || r->headers_out.content_encoding == NULL | |
134 || r->headers_out.content_encoding->value.len != 4 | |
135 || ngx_strncasecmp(r->headers_out.content_encoding->value.data, | |
136 (u_char *) "gzip", 4) != 0) | |
137 { | |
138 return ngx_http_next_header_filter(r); | |
139 } | |
140 | |
141 r->gzip_vary = 1; | |
142 | |
143 if (!r->gzip_tested) { | |
144 if (ngx_http_gzip_ok(r) == NGX_OK) { | |
145 return ngx_http_next_header_filter(r); | |
146 } | |
147 | |
4888
3abac956f6c8
Gunzip: fixed r->gzip_ok check.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4838
diff
changeset
|
148 } else if (r->gzip_ok) { |
4837 | 149 return ngx_http_next_header_filter(r); |
150 } | |
151 | |
152 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gunzip_ctx_t)); | |
153 if (ctx == NULL) { | |
154 return NGX_ERROR; | |
155 } | |
156 | |
157 ngx_http_set_ctx(r, ctx, ngx_http_gunzip_filter_module); | |
158 | |
159 ctx->request = r; | |
160 | |
161 r->filter_need_in_memory = 1; | |
162 | |
163 r->headers_out.content_encoding->hash = 0; | |
164 r->headers_out.content_encoding = NULL; | |
165 | |
166 ngx_http_clear_content_length(r); | |
167 ngx_http_clear_accept_ranges(r); | |
4939
41bf14321133
Gunzip: added missing ngx_http_clear_etag().
Maxim Dounin <mdounin@mdounin.ru>
parents:
4888
diff
changeset
|
168 ngx_http_clear_etag(r); |
4837 | 169 |
170 return ngx_http_next_header_filter(r); | |
171 } | |
172 | |
173 | |
174 static ngx_int_t | |
175 ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
176 { | |
177 int rc; | |
178 ngx_chain_t *cl; | |
179 ngx_http_gunzip_ctx_t *ctx; | |
180 | |
181 ctx = ngx_http_get_module_ctx(r, ngx_http_gunzip_filter_module); | |
182 | |
183 if (ctx == NULL || ctx->done) { | |
184 return ngx_http_next_body_filter(r, in); | |
185 } | |
186 | |
187 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
188 "http gunzip filter"); | |
189 | |
190 if (!ctx->started) { | |
191 if (ngx_http_gunzip_filter_inflate_start(r, ctx) != NGX_OK) { | |
192 goto failed; | |
193 } | |
194 } | |
195 | |
196 if (in) { | |
197 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { | |
198 goto failed; | |
199 } | |
200 } | |
201 | |
5432
c52a761a2029
Gzip, gunzip: flush pending data when incoming chain is NULL.
Yichun Zhang <agentzh@gmail.com>
parents:
4939
diff
changeset
|
202 if (ctx->nomem || in == NULL) { |
4837 | 203 |
204 /* flush busy buffers */ | |
205 | |
206 if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) { | |
207 goto failed; | |
208 } | |
209 | |
210 cl = NULL; | |
211 | |
212 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, | |
213 (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); | |
214 ctx->nomem = 0; | |
215 } | |
216 | |
217 for ( ;; ) { | |
218 | |
219 /* cycle while we can write to a client */ | |
220 | |
221 for ( ;; ) { | |
222 | |
223 /* cycle while there is data to feed zlib and ... */ | |
224 | |
225 rc = ngx_http_gunzip_filter_add_data(r, ctx); | |
226 | |
227 if (rc == NGX_DECLINED) { | |
228 break; | |
229 } | |
230 | |
231 if (rc == NGX_AGAIN) { | |
232 continue; | |
233 } | |
234 | |
235 | |
236 /* ... there are buffers to write zlib output */ | |
237 | |
238 rc = ngx_http_gunzip_filter_get_buf(r, ctx); | |
239 | |
240 if (rc == NGX_DECLINED) { | |
241 break; | |
242 } | |
243 | |
244 if (rc == NGX_ERROR) { | |
245 goto failed; | |
246 } | |
247 | |
248 rc = ngx_http_gunzip_filter_inflate(r, ctx); | |
249 | |
250 if (rc == NGX_OK) { | |
251 break; | |
252 } | |
253 | |
254 if (rc == NGX_ERROR) { | |
255 goto failed; | |
256 } | |
257 | |
258 /* rc == NGX_AGAIN */ | |
259 } | |
260 | |
261 if (ctx->out == NULL) { | |
262 return ctx->busy ? NGX_AGAIN : NGX_OK; | |
263 } | |
264 | |
265 rc = ngx_http_next_body_filter(r, ctx->out); | |
266 | |
267 if (rc == NGX_ERROR) { | |
268 goto failed; | |
269 } | |
270 | |
271 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out, | |
272 (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); | |
273 ctx->last_out = &ctx->out; | |
274 | |
275 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
276 "gunzip out: %p", ctx->out); | |
277 | |
278 ctx->nomem = 0; | |
279 | |
280 if (ctx->done) { | |
281 return rc; | |
282 } | |
283 } | |
284 | |
285 /* unreachable */ | |
286 | |
287 failed: | |
288 | |
289 ctx->done = 1; | |
290 | |
291 return NGX_ERROR; | |
292 } | |
293 | |
294 | |
295 static ngx_int_t | |
296 ngx_http_gunzip_filter_inflate_start(ngx_http_request_t *r, | |
297 ngx_http_gunzip_ctx_t *ctx) | |
298 { | |
299 int rc; | |
300 | |
301 ctx->zstream.next_in = Z_NULL; | |
302 ctx->zstream.avail_in = 0; | |
303 | |
304 ctx->zstream.zalloc = ngx_http_gunzip_filter_alloc; | |
305 ctx->zstream.zfree = ngx_http_gunzip_filter_free; | |
306 ctx->zstream.opaque = ctx; | |
307 | |
308 /* windowBits +16 to decode gzip, zlib 1.2.0.4+ */ | |
309 rc = inflateInit2(&ctx->zstream, MAX_WBITS + 16); | |
310 | |
311 if (rc != Z_OK) { | |
312 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
313 "inflateInit2() failed: %d", rc); | |
314 return NGX_ERROR; | |
315 } | |
316 | |
317 ctx->started = 1; | |
318 | |
319 ctx->last_out = &ctx->out; | |
320 ctx->flush = Z_NO_FLUSH; | |
321 | |
322 return NGX_OK; | |
323 } | |
324 | |
325 | |
326 static ngx_int_t | |
327 ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, | |
328 ngx_http_gunzip_ctx_t *ctx) | |
329 { | |
330 if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { | |
331 return NGX_OK; | |
332 } | |
333 | |
334 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
335 "gunzip in: %p", ctx->in); | |
336 | |
337 if (ctx->in == NULL) { | |
338 return NGX_DECLINED; | |
339 } | |
340 | |
341 ctx->in_buf = ctx->in->buf; | |
342 ctx->in = ctx->in->next; | |
343 | |
344 ctx->zstream.next_in = ctx->in_buf->pos; | |
345 ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; | |
346 | |
347 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
348 "gunzip in_buf:%p ni:%p ai:%ud", | |
349 ctx->in_buf, | |
350 ctx->zstream.next_in, ctx->zstream.avail_in); | |
351 | |
352 if (ctx->in_buf->last_buf || ctx->in_buf->last_in_chain) { | |
353 ctx->flush = Z_FINISH; | |
354 | |
355 } else if (ctx->in_buf->flush) { | |
356 ctx->flush = Z_SYNC_FLUSH; | |
357 | |
358 } else if (ctx->zstream.avail_in == 0) { | |
359 /* ctx->flush == Z_NO_FLUSH */ | |
360 return NGX_AGAIN; | |
361 } | |
362 | |
363 return NGX_OK; | |
364 } | |
365 | |
366 | |
367 static ngx_int_t | |
368 ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, | |
369 ngx_http_gunzip_ctx_t *ctx) | |
370 { | |
371 ngx_http_gunzip_conf_t *conf; | |
372 | |
373 if (ctx->zstream.avail_out) { | |
374 return NGX_OK; | |
375 } | |
376 | |
377 conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); | |
378 | |
379 if (ctx->free) { | |
380 ctx->out_buf = ctx->free->buf; | |
381 ctx->free = ctx->free->next; | |
382 | |
383 ctx->out_buf->flush = 0; | |
384 | |
385 } else if (ctx->bufs < conf->bufs.num) { | |
386 | |
387 ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size); | |
388 if (ctx->out_buf == NULL) { | |
389 return NGX_ERROR; | |
390 } | |
391 | |
392 ctx->out_buf->tag = (ngx_buf_tag_t) &ngx_http_gunzip_filter_module; | |
393 ctx->out_buf->recycled = 1; | |
394 ctx->bufs++; | |
395 | |
396 } else { | |
397 ctx->nomem = 1; | |
398 return NGX_DECLINED; | |
399 } | |
400 | |
401 ctx->zstream.next_out = ctx->out_buf->pos; | |
402 ctx->zstream.avail_out = conf->bufs.size; | |
403 | |
404 return NGX_OK; | |
405 } | |
406 | |
407 | |
408 static ngx_int_t | |
409 ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, | |
410 ngx_http_gunzip_ctx_t *ctx) | |
411 { | |
412 int rc; | |
413 ngx_buf_t *b; | |
414 ngx_chain_t *cl; | |
415 | |
416 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
417 "inflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d", | |
418 ctx->zstream.next_in, ctx->zstream.next_out, | |
419 ctx->zstream.avail_in, ctx->zstream.avail_out, | |
420 ctx->flush, ctx->redo); | |
421 | |
422 rc = inflate(&ctx->zstream, ctx->flush); | |
423 | |
424 if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) { | |
5435
2bb2571d6e34
Gunzip: "error" logging level on inflate() errors.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5432
diff
changeset
|
425 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
4837 | 426 "inflate() failed: %d, %d", ctx->flush, rc); |
427 return NGX_ERROR; | |
428 } | |
429 | |
430 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
431 "inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", | |
432 ctx->zstream.next_in, ctx->zstream.next_out, | |
433 ctx->zstream.avail_in, ctx->zstream.avail_out, | |
434 rc); | |
435 | |
436 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
437 "gunzip in_buf:%p pos:%p", | |
438 ctx->in_buf, ctx->in_buf->pos); | |
439 | |
440 if (ctx->zstream.next_in) { | |
441 ctx->in_buf->pos = ctx->zstream.next_in; | |
442 | |
443 if (ctx->zstream.avail_in == 0) { | |
444 ctx->zstream.next_in = NULL; | |
445 } | |
446 } | |
447 | |
448 ctx->out_buf->last = ctx->zstream.next_out; | |
449 | |
450 if (ctx->zstream.avail_out == 0) { | |
451 | |
452 /* zlib wants to output some more data */ | |
453 | |
454 cl = ngx_alloc_chain_link(r->pool); | |
455 if (cl == NULL) { | |
456 return NGX_ERROR; | |
457 } | |
458 | |
459 cl->buf = ctx->out_buf; | |
460 cl->next = NULL; | |
461 *ctx->last_out = cl; | |
462 ctx->last_out = &cl->next; | |
463 | |
464 ctx->redo = 1; | |
465 | |
466 return NGX_AGAIN; | |
467 } | |
468 | |
469 ctx->redo = 0; | |
470 | |
471 if (ctx->flush == Z_SYNC_FLUSH) { | |
472 | |
473 ctx->flush = Z_NO_FLUSH; | |
474 | |
475 cl = ngx_alloc_chain_link(r->pool); | |
476 if (cl == NULL) { | |
477 return NGX_ERROR; | |
478 } | |
479 | |
480 b = ctx->out_buf; | |
481 | |
482 if (ngx_buf_size(b) == 0) { | |
483 | |
484 b = ngx_calloc_buf(ctx->request->pool); | |
485 if (b == NULL) { | |
486 return NGX_ERROR; | |
487 } | |
488 | |
489 } else { | |
490 ctx->zstream.avail_out = 0; | |
491 } | |
492 | |
493 b->flush = 1; | |
494 | |
495 cl->buf = b; | |
496 cl->next = NULL; | |
497 *ctx->last_out = cl; | |
498 ctx->last_out = &cl->next; | |
499 | |
500 return NGX_OK; | |
501 } | |
502 | |
5436
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
503 if (ctx->flush == Z_FINISH && ctx->zstream.avail_in == 0) { |
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
504 |
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
505 if (rc != Z_STREAM_END) { |
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
506 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
507 "inflate() returned %d on response end", rc); |
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
508 return NGX_ERROR; |
6aa75f4982ce
Gunzip: proper error handling on gunzipping an empty response.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5435
diff
changeset
|
509 } |
4837 | 510 |
511 if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) { | |
512 return NGX_ERROR; | |
513 } | |
514 | |
515 return NGX_OK; | |
516 } | |
517 | |
518 if (rc == Z_STREAM_END && ctx->zstream.avail_in > 0) { | |
519 | |
520 rc = inflateReset(&ctx->zstream); | |
521 | |
522 if (rc != Z_OK) { | |
523 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
524 "inflateReset() failed: %d", rc); | |
525 return NGX_ERROR; | |
526 } | |
527 | |
528 ctx->redo = 1; | |
529 | |
530 return NGX_AGAIN; | |
531 } | |
532 | |
533 if (ctx->in == NULL) { | |
534 | |
535 b = ctx->out_buf; | |
536 | |
537 if (ngx_buf_size(b) == 0) { | |
538 return NGX_OK; | |
539 } | |
540 | |
541 cl = ngx_alloc_chain_link(r->pool); | |
542 if (cl == NULL) { | |
543 return NGX_ERROR; | |
544 } | |
545 | |
546 ctx->zstream.avail_out = 0; | |
547 | |
548 cl->buf = b; | |
549 cl->next = NULL; | |
550 *ctx->last_out = cl; | |
551 ctx->last_out = &cl->next; | |
552 | |
553 return NGX_OK; | |
554 } | |
555 | |
556 return NGX_AGAIN; | |
557 } | |
558 | |
559 | |
560 static ngx_int_t | |
561 ngx_http_gunzip_filter_inflate_end(ngx_http_request_t *r, | |
562 ngx_http_gunzip_ctx_t *ctx) | |
563 { | |
564 int rc; | |
565 ngx_buf_t *b; | |
566 ngx_chain_t *cl; | |
567 | |
568 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
569 "gunzip inflate end"); | |
570 | |
571 rc = inflateEnd(&ctx->zstream); | |
572 | |
573 if (rc != Z_OK) { | |
574 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
575 "inflateEnd() failed: %d", rc); | |
576 return NGX_ERROR; | |
577 } | |
578 | |
579 b = ctx->out_buf; | |
580 | |
581 if (ngx_buf_size(b) == 0) { | |
582 | |
583 b = ngx_calloc_buf(ctx->request->pool); | |
584 if (b == NULL) { | |
585 return NGX_ERROR; | |
586 } | |
587 } | |
588 | |
589 cl = ngx_alloc_chain_link(r->pool); | |
590 if (cl == NULL) { | |
591 return NGX_ERROR; | |
592 } | |
593 | |
594 cl->buf = b; | |
595 cl->next = NULL; | |
596 *ctx->last_out = cl; | |
597 ctx->last_out = &cl->next; | |
598 | |
599 b->last_buf = (r == r->main) ? 1 : 0; | |
600 b->last_in_chain = 1; | |
601 b->sync = 1; | |
602 | |
603 ctx->done = 1; | |
604 | |
605 return NGX_OK; | |
606 } | |
607 | |
608 | |
609 static void * | |
610 ngx_http_gunzip_filter_alloc(void *opaque, u_int items, u_int size) | |
611 { | |
612 ngx_http_gunzip_ctx_t *ctx = opaque; | |
613 | |
614 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, | |
615 "gunzip alloc: n:%ud s:%ud", | |
616 items, size); | |
617 | |
618 return ngx_palloc(ctx->request->pool, items * size); | |
619 } | |
620 | |
621 | |
622 static void | |
623 ngx_http_gunzip_filter_free(void *opaque, void *address) | |
624 { | |
625 #if 0 | |
626 ngx_http_gunzip_ctx_t *ctx = opaque; | |
627 | |
628 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, | |
629 "gunzip free: %p", address); | |
630 #endif | |
631 } | |
632 | |
633 | |
634 static void * | |
635 ngx_http_gunzip_create_conf(ngx_conf_t *cf) | |
636 { | |
637 ngx_http_gunzip_conf_t *conf; | |
638 | |
639 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gunzip_conf_t)); | |
640 if (conf == NULL) { | |
641 return NULL; | |
642 } | |
643 | |
644 /* | |
645 * set by ngx_pcalloc(): | |
646 * | |
647 * conf->bufs.num = 0; | |
648 */ | |
649 | |
650 conf->enable = NGX_CONF_UNSET; | |
651 | |
652 return conf; | |
653 } | |
654 | |
655 | |
656 static char * | |
657 ngx_http_gunzip_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
658 { | |
659 ngx_http_gunzip_conf_t *prev = parent; | |
660 ngx_http_gunzip_conf_t *conf = child; | |
661 | |
662 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
663 | |
664 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, | |
665 (128 * 1024) / ngx_pagesize, ngx_pagesize); | |
666 | |
667 return NGX_CONF_OK; | |
668 } | |
669 | |
670 | |
671 static ngx_int_t | |
672 ngx_http_gunzip_filter_init(ngx_conf_t *cf) | |
673 { | |
674 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
675 ngx_http_top_header_filter = ngx_http_gunzip_header_filter; | |
676 | |
677 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
678 ngx_http_top_body_filter = ngx_http_gunzip_body_filter; | |
679 | |
680 return NGX_OK; | |
681 } |