Mercurial > hg > nginx
comparison src/http/modules/ngx_http_gzip_filter.c @ 135:e29909bd9b8a
nginx-0.0.1-2003-09-28-23:29:06 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Sun, 28 Sep 2003 19:29:06 +0000 |
parents | d57c6835225c |
children | da00cde00e8a |
comparison
equal
deleted
inserted
replaced
134:d57c6835225c | 135:e29909bd9b8a |
---|---|
25 int hunks; | 25 int hunks; |
26 | 26 |
27 int length; | 27 int length; |
28 void *alloc; | 28 void *alloc; |
29 | 29 |
30 int flush; | 30 unsigned flush:4; |
31 unsigned redo:1; | |
32 | |
31 u_int crc32; | 33 u_int crc32; |
32 z_stream zstream; | 34 z_stream zstream; |
33 } ngx_http_gzip_ctx_t; | 35 } ngx_http_gzip_ctx_t; |
34 | 36 |
35 | 37 |
123 static int ngx_http_gzip_header_filter(ngx_http_request_t *r) | 125 static int ngx_http_gzip_header_filter(ngx_http_request_t *r) |
124 { | 126 { |
125 ngx_http_gzip_ctx_t *ctx; | 127 ngx_http_gzip_ctx_t *ctx; |
126 ngx_http_gzip_conf_t *conf; | 128 ngx_http_gzip_conf_t *conf; |
127 | 129 |
128 if (r->headers_out.status != NGX_HTTP_OK | 130 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); |
131 | |
132 if (!conf->enable | |
133 || r->headers_out.status != NGX_HTTP_OK | |
129 || r->header_only | 134 || r->header_only |
130 /* || r->content_encoding */ | 135 || r->main |
131 /* || r->accept_encoding == NULL */ | 136 /* TODO: conf->http_version */ |
132 || r->main) | 137 || (r->headers_out.content_encoding |
138 && r->headers_out.content_encoding->value.len) | |
139 || r->headers_in.accept_encoding == NULL | |
140 || ngx_strstr(r->headers_in.accept_encoding->value.data, "gzip") == NULL | |
141 ) | |
133 { | 142 { |
134 return next_header_filter(r); | 143 return next_header_filter(r); |
135 } | 144 } |
136 | 145 |
137 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); | 146 /* TODO: "text/html" -> custom types */ |
138 | 147 if (r->headers_out.content_type |
139 if (!conf->enable | 148 && ngx_strncasecmp(r->headers_out.content_type->value.data, |
140 /* TODO: conf->version */ | 149 "text/html", 5) != 0) |
141 /* TODO: "text/" -> custom types */ | |
142 || ngx_strncasecmp(r->headers_out.content_type->value.data, | |
143 "text/", 5) != 0) | |
144 { | 150 { |
145 return next_header_filter(r); | 151 return next_header_filter(r); |
146 } | 152 } |
147 | 153 |
148 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, | 154 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, |
149 sizeof(ngx_http_gzip_ctx_t), NGX_ERROR); | 155 sizeof(ngx_http_gzip_ctx_t), NGX_ERROR); |
156 | |
157 ngx_test_null(r->headers_out.content_encoding, | |
158 ngx_push_table(r->headers_out.headers), | |
159 NGX_ERROR); | |
160 | |
161 r->headers_out.content_encoding->key.len = 0; | |
162 r->headers_out.content_encoding->key.data = NULL; | |
163 r->headers_out.content_encoding->value.len = 4; | |
164 r->headers_out.content_encoding->value.data = "gzip"; | |
150 | 165 |
151 ctx->length = r->headers_out.content_length; | 166 ctx->length = r->headers_out.content_length; |
152 r->headers_out.content_length = -1; | 167 r->headers_out.content_length = -1; |
153 r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY; | 168 r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY; |
154 | 169 |
210 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { | 225 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { |
211 return ngx_http_gzip_error(ctx); | 226 return ngx_http_gzip_error(ctx); |
212 } | 227 } |
213 } | 228 } |
214 | 229 |
215 while (ctx->in || ctx->out | 230 for ( ;; ) { |
216 || ctx->zstream.avail_in || ctx->zstream.avail_out | 231 |
217 || ctx->flush != Z_NO_FLUSH) | |
218 { | |
219 for ( ;; ) { | 232 for ( ;; ) { |
220 | 233 |
221 if (ctx->in | 234 /* is there a data to gzip ? */ |
222 && ctx->zstream.avail_in == 0 | 235 |
223 && ctx->flush == Z_NO_FLUSH) | 236 if (ctx->zstream.avail_in == 0 |
224 { | 237 && ctx->flush == Z_NO_FLUSH |
238 && !ctx->redo) { | |
239 | |
240 if (ctx->in == NULL) { | |
241 break; | |
242 } | |
243 | |
225 ctx->in_hunk = ctx->in->hunk; | 244 ctx->in_hunk = ctx->in->hunk; |
226 ctx->in = ctx->in->next; | 245 ctx->in = ctx->in->next; |
227 | 246 |
247 ctx->zstream.next_in = ctx->in_hunk->pos; | |
228 ctx->zstream.avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; | 248 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); | |
238 | 249 |
239 if (ctx->in_hunk->type & NGX_HUNK_LAST) { | 250 if (ctx->in_hunk->type & NGX_HUNK_LAST) { |
240 ctx->flush = Z_FINISH; | 251 ctx->flush = Z_FINISH; |
241 | 252 |
242 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { | 253 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { |
243 ctx->flush = Z_SYNC_FLUSH; | 254 ctx->flush = Z_SYNC_FLUSH; |
244 } | 255 } |
256 | |
257 if (ctx->zstream.avail_in == 0) { | |
258 if (ctx->flush == Z_NO_FLUSH) { | |
259 continue; | |
260 } | |
261 | |
262 } else { | |
263 ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, | |
264 ctx->zstream.avail_in); | |
265 } | |
245 } | 266 } |
267 | |
268 /* is there a space for the gzipped data ? */ | |
246 | 269 |
247 if (ctx->zstream.avail_out == 0) { | 270 if (ctx->zstream.avail_out == 0) { |
248 if (ctx->free) { | 271 if (ctx->free) { |
249 ctx->out_hunk = ctx->free->hunk; | 272 ctx->out_hunk = ctx->free->hunk; |
250 ctx->free = ctx->free->next; | 273 ctx->free = ctx->free->next; |
255 0, 0), | 278 0, 0), |
256 ngx_http_gzip_error(ctx)); | 279 ngx_http_gzip_error(ctx)); |
257 ctx->hunks++; | 280 ctx->hunks++; |
258 | 281 |
259 } else { | 282 } else { |
260 break; | 283 break; |
261 } | 284 } |
262 | 285 |
263 ctx->zstream.next_out = ctx->out_hunk->pos; | 286 ctx->zstream.next_out = ctx->out_hunk->pos; |
264 ctx->zstream.avail_out = conf->hunk_size; | 287 ctx->zstream.avail_out = conf->hunk_size; |
265 } | 288 } |
289 | |
290 ngx_log_debug(r->connection->log, "deflate(): %08x %08x %d %d %d" _ | |
291 ctx->zstream.next_in _ ctx->zstream.next_out _ | |
292 ctx->zstream.avail_in _ ctx->zstream.avail_out _ ctx->flush); | |
266 | 293 |
267 rc = deflate(&ctx->zstream, ctx->flush); | 294 rc = deflate(&ctx->zstream, ctx->flush); |
268 if (rc != Z_OK && rc != Z_STREAM_END) { | 295 if (rc != Z_OK && rc != Z_STREAM_END) { |
269 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | 296 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
270 "deflate() failed: %d, %d", ctx->flush, rc); | 297 "deflate() failed: %d, %d", ctx->flush, rc); |
271 return ngx_http_gzip_error(ctx); | 298 return ngx_http_gzip_error(ctx); |
272 } | 299 } |
273 | 300 |
274 ngx_log_debug(r->connection->log, "deflate(): %d %d" _ ctx->flush _ rc); | 301 ngx_log_debug(r->connection->log, "DEFLATE(): %08x %08x %d %d %d" _ |
302 ctx->zstream.next_in _ ctx->zstream.next_out _ | |
303 ctx->zstream.avail_in _ ctx->zstream.avail_out _ rc); | |
275 | 304 |
276 ctx->in_hunk->pos = ctx->zstream.next_in; | 305 ctx->in_hunk->pos = ctx->zstream.next_in; |
277 | 306 |
278 if (ctx->zstream.avail_out == 0) { | 307 if (ctx->zstream.avail_out == 0) { |
279 ctx->out_hunk->last += conf->hunk_size; | 308 ctx->out_hunk->last += conf->hunk_size; |
280 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, | 309 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, |
281 ngx_http_gzip_error(ctx)); | 310 ngx_http_gzip_error(ctx)); |
282 *ctx->last_out = ce; | 311 *ctx->last_out = ce; |
283 ctx->last_out = &ce->next; | 312 ctx->last_out = &ce->next; |
313 ctx->redo = 1; | |
284 | 314 |
285 } else { | 315 } else { |
286 ctx->out_hunk->last = ctx->zstream.next_out; | 316 ctx->out_hunk->last = ctx->zstream.next_out; |
317 ctx->redo = 0; | |
287 | 318 |
288 if (ctx->flush == Z_SYNC_FLUSH) { | 319 if (ctx->flush == Z_SYNC_FLUSH) { |
289 ctx->out_hunk->type |= NGX_HUNK_FLUSH; | 320 ctx->out_hunk->type |= NGX_HUNK_FLUSH; |
290 ctx->flush = Z_NO_FLUSH; | 321 ctx->flush = Z_NO_FLUSH; |
291 | 322 |
300 /* rc == Z_STREAM_END */ | 331 /* rc == Z_STREAM_END */ |
301 | 332 |
302 zin = ctx->zstream.total_in; | 333 zin = ctx->zstream.total_in; |
303 zout = 10 + ctx->zstream.total_out + 8; | 334 zout = 10 + ctx->zstream.total_out + 8; |
304 | 335 |
336 rc = deflateEnd(&ctx->zstream); | |
337 if (rc != Z_OK) { | |
338 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
339 "deflateEnd() failed: %d", rc); | |
340 return ngx_http_gzip_error(ctx); | |
341 } | |
342 | |
305 ctx->flush = Z_NO_FLUSH; | 343 ctx->flush = Z_NO_FLUSH; |
306 | 344 |
307 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, | 345 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, |
308 ngx_http_gzip_error(ctx)); | 346 ngx_http_gzip_error(ctx)); |
309 *ctx->last_out = ce; | 347 *ctx->last_out = ce; |
310 ctx->last_out = &ce->next; | 348 ctx->last_out = &ce->next; |
311 | 349 |
312 if (ctx->zstream.avail_out >= 8) { | 350 if (ctx->zstream.avail_out >= 8) { |
313 trailer = (struct gztrailer *) &ctx->zstream.avail_in; | 351 trailer = (struct gztrailer *) ctx->out_hunk->last; |
314 ctx->out_hunk->type |= NGX_HUNK_LAST; | 352 ctx->out_hunk->type |= NGX_HUNK_LAST; |
315 ctx->out_hunk->last += 8; | 353 ctx->out_hunk->last += 8; |
316 | 354 |
317 } else { | 355 } else { |
318 /* STUB */ trailer = NULL; | 356 ngx_test_null(h, |
357 ngx_create_temp_hunk(r->pool, 8, 0, 0), | |
358 ngx_http_gzip_error(ctx)); | |
359 | |
360 h->type |= NGX_HUNK_LAST; | |
361 | |
362 ngx_test_null(ce, ngx_alloc_chain_entry(r->pool), | |
363 ngx_http_gzip_error(ctx)); | |
364 ce->hunk = h; | |
365 ce->next = NULL; | |
366 *ctx->last_out = ce; | |
367 ctx->last_out = &ce->next; | |
368 trailer = (struct gztrailer *) h->pos; | |
369 h->last += 8; | |
319 } | 370 } |
320 | 371 |
321 #if (HAVE_LITTLE_ENDIAN) | 372 #if (HAVE_LITTLE_ENDIAN) |
322 trailer->crc32 = ctx->crc32; | 373 trailer->crc32 = ctx->crc32; |
323 trailer->zlen = zin; | 374 trailer->zlen = zin; |
324 #else | 375 #else |
325 /* STUB */ | 376 /* STUB */ |
326 #endif | 377 #endif |
327 | 378 |
328 deflateEnd(&ctx->zstream); | 379 ctx->zstream.avail_in = 0; |
380 ctx->zstream.avail_out = 0; | |
381 ngx_http_delete_ctx(r, ngx_http_gzip_filter_module); | |
329 #if 0 | 382 #if 0 |
330 ngx_free(); | 383 ngx_free(); |
331 set ctx = NULL; | |
332 #endif | 384 #endif |
333 break; | 385 break; |
334 | 386 |
335 } else if (conf->no_buffer && ctx->in == NULL) { | 387 } else if (conf->no_buffer && ctx->in == NULL) { |
336 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, | 388 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, |
341 break; | 393 break; |
342 } | 394 } |
343 } | 395 } |
344 } | 396 } |
345 | 397 |
346 rc = next_body_filter(r, ctx->out); | 398 if (ctx->out == NULL) { |
347 if (rc == NGX_ERROR) { | 399 if (ctx->in || ctx->zstream.avail_in) { |
400 return NGX_AGAIN; | |
401 } else { | |
402 return NGX_OK; | |
403 } | |
404 } | |
405 | |
406 if (next_body_filter(r, ctx->out) == NGX_ERROR) { | |
348 return ngx_http_gzip_error(ctx); | 407 return ngx_http_gzip_error(ctx); |
349 } | 408 } |
350 | 409 |
351 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); | 410 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); |
352 ctx->last_out = &ctx->out; | 411 ctx->last_out = &ctx->out; |
353 } | 412 } |
354 | |
355 /* STUB */ | |
356 return next_body_filter(r, NULL); | |
357 } | 413 } |
358 | 414 |
359 | 415 |
360 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) | 416 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) |
361 { | 417 { |
362 #if 0 | 418 #if 0 |
363 ngx_free(ctx->alloc); | 419 ngx_free(ctx->alloc); |
420 #else | |
421 deflateEnd(&ctx->zstream); | |
364 #endif | 422 #endif |
423 | |
424 ctx->zstream.avail_in = 0; | |
425 ctx->zstream.avail_out = 0; | |
365 | 426 |
366 return NGX_ERROR; | 427 return NGX_ERROR; |
367 } | 428 } |
368 | 429 |
369 | 430 |