Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_gunzip_filter_module.c @ 5324:8ef1722143dc
SPDY: do not reject headers with empty value (ticket #396).
A quote from SPDY draft 2 specification: "The length of each name and
value must be greater than zero. A receiver of a zero-length name or
value must send a RST_STREAM with code PROTOCOL error."
But it appears that Chrome browser allows sending requests over SPDY/2
connection using JavaScript that contain headers with empty values.
For better compatibility across SPDY clients and to be compliant with
HTTP, such headers are no longer rejected.
Also, it is worth noting that in SPDY draft 3 the statement has been
changed so that it permits empty values for headers.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Thu, 15 Aug 2013 19:16:09 +0400 |
parents | 41bf14321133 |
children | c52a761a2029 |
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 | |
202 if (ctx->nomem) { | |
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) { | |
425 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
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 | |
503 if (rc == Z_STREAM_END && ctx->flush == Z_FINISH | |
504 && ctx->zstream.avail_in == 0) | |
505 { | |
506 | |
507 if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) { | |
508 return NGX_ERROR; | |
509 } | |
510 | |
511 return NGX_OK; | |
512 } | |
513 | |
514 if (rc == Z_STREAM_END && ctx->zstream.avail_in > 0) { | |
515 | |
516 rc = inflateReset(&ctx->zstream); | |
517 | |
518 if (rc != Z_OK) { | |
519 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
520 "inflateReset() failed: %d", rc); | |
521 return NGX_ERROR; | |
522 } | |
523 | |
524 ctx->redo = 1; | |
525 | |
526 return NGX_AGAIN; | |
527 } | |
528 | |
529 if (ctx->in == NULL) { | |
530 | |
531 b = ctx->out_buf; | |
532 | |
533 if (ngx_buf_size(b) == 0) { | |
534 return NGX_OK; | |
535 } | |
536 | |
537 cl = ngx_alloc_chain_link(r->pool); | |
538 if (cl == NULL) { | |
539 return NGX_ERROR; | |
540 } | |
541 | |
542 ctx->zstream.avail_out = 0; | |
543 | |
544 cl->buf = b; | |
545 cl->next = NULL; | |
546 *ctx->last_out = cl; | |
547 ctx->last_out = &cl->next; | |
548 | |
549 return NGX_OK; | |
550 } | |
551 | |
552 return NGX_AGAIN; | |
553 } | |
554 | |
555 | |
556 static ngx_int_t | |
557 ngx_http_gunzip_filter_inflate_end(ngx_http_request_t *r, | |
558 ngx_http_gunzip_ctx_t *ctx) | |
559 { | |
560 int rc; | |
561 ngx_buf_t *b; | |
562 ngx_chain_t *cl; | |
563 | |
564 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
565 "gunzip inflate end"); | |
566 | |
567 rc = inflateEnd(&ctx->zstream); | |
568 | |
569 if (rc != Z_OK) { | |
570 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
571 "inflateEnd() failed: %d", rc); | |
572 return NGX_ERROR; | |
573 } | |
574 | |
575 b = ctx->out_buf; | |
576 | |
577 if (ngx_buf_size(b) == 0) { | |
578 | |
579 b = ngx_calloc_buf(ctx->request->pool); | |
580 if (b == NULL) { | |
581 return NGX_ERROR; | |
582 } | |
583 } | |
584 | |
585 cl = ngx_alloc_chain_link(r->pool); | |
586 if (cl == NULL) { | |
587 return NGX_ERROR; | |
588 } | |
589 | |
590 cl->buf = b; | |
591 cl->next = NULL; | |
592 *ctx->last_out = cl; | |
593 ctx->last_out = &cl->next; | |
594 | |
595 b->last_buf = (r == r->main) ? 1 : 0; | |
596 b->last_in_chain = 1; | |
597 b->sync = 1; | |
598 | |
599 ctx->done = 1; | |
600 | |
601 return NGX_OK; | |
602 } | |
603 | |
604 | |
605 static void * | |
606 ngx_http_gunzip_filter_alloc(void *opaque, u_int items, u_int size) | |
607 { | |
608 ngx_http_gunzip_ctx_t *ctx = opaque; | |
609 | |
610 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, | |
611 "gunzip alloc: n:%ud s:%ud", | |
612 items, size); | |
613 | |
614 return ngx_palloc(ctx->request->pool, items * size); | |
615 } | |
616 | |
617 | |
618 static void | |
619 ngx_http_gunzip_filter_free(void *opaque, void *address) | |
620 { | |
621 #if 0 | |
622 ngx_http_gunzip_ctx_t *ctx = opaque; | |
623 | |
624 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, | |
625 "gunzip free: %p", address); | |
626 #endif | |
627 } | |
628 | |
629 | |
630 static void * | |
631 ngx_http_gunzip_create_conf(ngx_conf_t *cf) | |
632 { | |
633 ngx_http_gunzip_conf_t *conf; | |
634 | |
635 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gunzip_conf_t)); | |
636 if (conf == NULL) { | |
637 return NULL; | |
638 } | |
639 | |
640 /* | |
641 * set by ngx_pcalloc(): | |
642 * | |
643 * conf->bufs.num = 0; | |
644 */ | |
645 | |
646 conf->enable = NGX_CONF_UNSET; | |
647 | |
648 return conf; | |
649 } | |
650 | |
651 | |
652 static char * | |
653 ngx_http_gunzip_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
654 { | |
655 ngx_http_gunzip_conf_t *prev = parent; | |
656 ngx_http_gunzip_conf_t *conf = child; | |
657 | |
658 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
659 | |
660 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, | |
661 (128 * 1024) / ngx_pagesize, ngx_pagesize); | |
662 | |
663 return NGX_CONF_OK; | |
664 } | |
665 | |
666 | |
667 static ngx_int_t | |
668 ngx_http_gunzip_filter_init(ngx_conf_t *cf) | |
669 { | |
670 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
671 ngx_http_top_header_filter = ngx_http_gunzip_header_filter; | |
672 | |
673 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
674 ngx_http_top_body_filter = ngx_http_gunzip_body_filter; | |
675 | |
676 return NGX_OK; | |
677 } |