1 diff -Naur lighttpd-1.4.19/configure.in lighttpd-1.4.19.mod_deflate.jz/configure.in
2 --- lighttpd-1.4.19/configure.in
3 +++ lighttpd-1.4.19.mod_deflate.jz/configure.in
8 -do_build="mod_cgi mod_fastcgi mod_extforward mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming"
9 +do_build="mod_cgi mod_fastcgi mod_extforward mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming mod_deflate"
11 plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
12 features="regex-conditionals"
13 diff -Naur lighttpd-1.4.19/src/base.h lighttpd-1.4.19.mod_deflate.jz/src/base.h
14 --- lighttpd-1.4.19/src/base.h
15 +++ lighttpd-1.4.19.mod_deflate.jz/src/base.h
18 http_method_t http_method;
19 http_version_t http_version;
20 + int true_http_10_client;
28 + int end_chunk; /* used for chunked transfer encoding. */
30 - chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
31 + chunkqueue *write_queue; /* a large queue for HTTP response content [ file, mem ] */
32 + chunkqueue *output_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
33 chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
34 chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
40 + connections *joblist_prev;
41 connections *fdwaitqueue;
43 stat_cache *stat_cache;
44 diff -Naur lighttpd-1.4.19/src/chunk.c lighttpd-1.4.19.mod_deflate.jz/src/chunk.c
45 --- lighttpd-1.4.19/src/chunk.c
46 +++ lighttpd-1.4.19.mod_deflate.jz/src/chunk.c
55 chunkqueue *chunkqueue_init(void) {
61 +int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src) {
62 + if(src == NULL) return 0;
63 + chunkqueue_append_chunk(cq, src->first);
64 + cq->last = src->last;
71 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
80 + * the HTTP chunk-API
85 +static int chunk_encode_append_len(chunkqueue *cq, size_t len) {
86 + size_t i, olen = len, j;
89 + /*b = srv->tmp_chunk_len;*/
90 + /*b = buffer_init();*/
91 + b = chunkqueue_get_append_buffer(cq);
94 + buffer_copy_string(b, "0");
96 + for (i = 0; i < 8 && len; i++) {
100 + /* i is the number of hex digits we have */
101 + buffer_prepare_copy(b, i + 1);
103 + for (j = i-1, len = olen; j+1 > 0; j--) {
104 + b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
108 + b->ptr[b->used++] = '\0';
111 + buffer_append_string(b, "\r\n");
113 + chunkqueue_append_buffer(cq, b);
121 +int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
122 + if (!cq) return -1;
123 + if (len == 0) return 0;
125 + chunk_encode_append_len(cq, len);
127 + chunkqueue_append_file(cq, fn, offset, len);
129 + chunkqueue_append_mem(cq, "\r\n", 2 + 1);
134 +int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem) {
135 + if (!cq) return -1;
136 + if (mem->used <= 1) return 0;
138 + chunk_encode_append_len(cq, mem->used - 1);
140 + chunkqueue_append_buffer(cq, mem);
142 + chunkqueue_append_mem(cq, "\r\n", 2 + 1);
147 +int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len) {
148 + if (!cq) return -1;
149 + if (len <= 1) return 0;
151 + chunk_encode_append_len(cq, len - 1);
153 + chunkqueue_append_mem(cq, mem, len);
155 + chunkqueue_append_mem(cq, "\r\n", 2 + 1);
160 +int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src) {
161 + int len = chunkqueue_length(src);
162 + if (!cq) return -1;
163 + if (len == 0) return 0;
165 + chunk_encode_append_len(cq, len);
167 + chunkqueue_append_chunkqueue(cq, src);
169 + chunkqueue_append_mem(cq, "\r\n", 2 + 1);
174 +int chunk_encode_end(chunkqueue *cq) {
175 + chunk_encode_append_len(cq, 0);
176 + chunkqueue_append_mem(cq, "\r\n", 2 + 1);
180 diff -Naur lighttpd-1.4.19/src/chunk.h lighttpd-1.4.19.mod_deflate.jz/src/chunk.h
181 --- lighttpd-1.4.19/src/chunk.h
182 +++ lighttpd-1.4.19.mod_deflate.jz/src/chunk.h
184 int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len);
185 int chunkqueue_append_buffer(chunkqueue *c, buffer *mem);
186 int chunkqueue_append_buffer_weak(chunkqueue *c, buffer *mem);
187 +int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src);
188 int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem);
190 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
193 int chunkqueue_is_empty(chunkqueue *c);
195 +int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len);
196 +int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem);
197 +int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len);
198 +int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src);
199 +int chunk_encode_end(chunkqueue *cq);
202 diff -Naur lighttpd-1.4.19/src/connections.c lighttpd-1.4.19.mod_deflate.jz/src/connections.c
203 --- lighttpd-1.4.19/src/connections.c
204 +++ lighttpd-1.4.19.mod_deflate.jz/src/connections.c
206 #include "response.h"
208 #include "http_chunk.h"
210 #include "stat_cache.h"
217 +int connection_queue_is_empty(connection *con) {
218 + if(!chunkqueue_is_empty(con->write_queue)) return 0;
219 + if(!chunkqueue_is_empty(con->output_queue)) return 0;
224 static void dump_packet(const unsigned char *data, size_t len) {
227 con->file_finished = 1;
229 chunkqueue_reset(con->write_queue);
230 + chunkqueue_reset(con->output_queue);
234 @@ -517,12 +525,27 @@
235 /* disable chunked encoding again as we have no body */
236 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
237 con->parsed_response &= ~HTTP_CONTENT_LENGTH;
238 chunkqueue_reset(con->write_queue);
239 + chunkqueue_reset(con->output_queue);
241 con->file_finished = 1;
245 + /* Allow filter plugins to change response headers before they are written. */
246 + switch(plugins_call_handle_response_start(srv, con)) {
247 + case HANDLER_GO_ON:
248 + case HANDLER_FINISHED:
249 + /* response start is finished */
252 + /* something strange happend */
253 + log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed.");
254 + connection_set_state(srv, con, CON_STATE_ERROR);
255 + joblist_append(srv, con);
259 if (con->file_finished) {
260 /* we have all the content and chunked encoding is not used, set a content-length */
263 * without the content
265 con->file_finished = 1;
267 chunkqueue_reset(con->write_queue);
268 + chunkqueue_reset(con->output_queue);
269 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
272 @@ -603,11 +627,57 @@
275 static int connection_handle_write(server *srv, connection *con) {
276 - switch(network_write_chunkqueue(srv, con, con->write_queue)) {
280 + /* Allow filter plugins to modify response conent */
281 + switch(plugins_call_handle_response_filter(srv, con)) {
282 + case HANDLER_GO_ON:
283 + finished = con->file_finished;
284 + /* response content not changed */
286 + case HANDLER_COMEBACK:
287 + /* response filter has more work */
290 + case HANDLER_FINISHED:
291 + /* response filter is finished */
295 + /* something strange happend */
296 + log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed.");
297 + connection_set_state(srv, con, CON_STATE_ERROR);
298 + joblist_append(srv, con);
303 + /* move chunks from write_queue to output_queue. */
304 + if (con->request.http_method == HTTP_METHOD_HEAD) {
305 + chunkqueue_reset(con->write_queue);
307 + len = chunkqueue_length(con->write_queue);
308 + if(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
309 + chunk_encode_append_queue(con->output_queue, con->write_queue);
310 + if(finished && !con->end_chunk) {
311 + con->end_chunk = 1;
312 + chunk_encode_end(con->output_queue);
315 + chunkqueue_append_chunkqueue(con->output_queue, con->write_queue);
317 + con->write_queue->bytes_out += len;
319 + /* write chunks from output_queue to network */
320 + switch(network_write_chunkqueue(srv, con, con->output_queue)) {
322 - if (con->file_finished) {
324 connection_set_state(srv, con, CON_STATE_RESPONSE_END);
325 joblist_append(srv, con);
327 + /* not finished yet -> WRITE */
328 + con->is_writable = 1;
331 case -1: /* error on our side */
335 con->write_queue = chunkqueue_init();
336 + con->output_queue = chunkqueue_init();
337 con->read_queue = chunkqueue_init();
338 con->request_content_queue = chunkqueue_init();
339 chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs);
341 connection_reset(srv, con);
343 chunkqueue_free(con->write_queue);
344 + chunkqueue_free(con->output_queue);
345 chunkqueue_free(con->read_queue);
346 chunkqueue_free(con->request_content_queue);
347 array_free(con->request.headers);
349 con->http_status = 0;
350 con->file_finished = 0;
351 con->file_started = 0;
352 + con->end_chunk = 0;
353 con->got_response = 0;
354 +// con->use_cache_file = 0;
355 +// con->write_cache_file = 0;
357 con->parsed_response = 0;
360 array_reset(con->environment);
362 chunkqueue_reset(con->write_queue);
363 + chunkqueue_reset(con->output_queue);
364 chunkqueue_reset(con->request_content_queue);
366 /* the plugins should cleanup themself */
367 @@ -1223,7 +1299,6 @@
370 if (con->state == CON_STATE_WRITE &&
371 - !chunkqueue_is_empty(con->write_queue) &&
374 if (-1 == connection_handle_write(srv, con)) {
375 @@ -1640,15 +1715,15 @@
378 /* only try to write if we have something in the queue */
379 - if (!chunkqueue_is_empty(con->write_queue)) {
381 + if (!connection_queue_is_empty(con)) {
382 log_error_write(srv, __FILE__, __LINE__, "dsd",
385 - con->write_queue->used);
387 + con->output_queue->used);
389 - if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
391 + if (con->is_writable) {
392 if (-1 == connection_handle_write(srv, con)) {
393 log_error_write(srv, __FILE__, __LINE__, "ds",
395 @@ -1758,9 +1833,9 @@
396 * - if we have data to write
397 * - if the socket is not writable yet
399 - if (!chunkqueue_is_empty(con->write_queue) &&
400 - (con->is_writable == 0) &&
401 - (con->traffic_limit_reached == 0)) {
402 + if ((con->is_writable == 0) &&
403 + (con->traffic_limit_reached == 0) &&
404 + !connection_queue_is_empty(con)) {
405 fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
407 fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
408 diff -Naur lighttpd-1.4.19/src/http_chunk.c lighttpd-1.4.19.mod_deflate.jz/src/http_chunk.c
409 --- lighttpd-1.4.19/src/http_chunk.c
410 +++ lighttpd-1.4.19.mod_deflate.jz/src/http_chunk.c
413 cq = con->write_queue;
415 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
416 - http_chunk_append_len(srv, con, len);
419 chunkqueue_append_file(cq, fn, offset, len);
421 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
422 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
430 cq = con->write_queue;
432 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
433 - http_chunk_append_len(srv, con, mem->used - 1);
436 chunkqueue_append_buffer(cq, mem);
438 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
439 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
446 cq = con->write_queue;
449 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
450 - chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1);
452 - chunkqueue_append_mem(cq, "", 1);
457 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
458 - http_chunk_append_len(srv, con, len - 1);
461 chunkqueue_append_mem(cq, mem, len);
463 - if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
464 - chunkqueue_append_mem(cq, "\r\n", 2 + 1);
470 diff -Naur lighttpd-1.4.19/src/joblist.c lighttpd-1.4.19.mod_deflate.jz/src/joblist.c
471 --- lighttpd-1.4.19/src/joblist.c
472 +++ lighttpd-1.4.19.mod_deflate.jz/src/joblist.c
475 int joblist_append(server *srv, connection *con) {
476 if (con->in_joblist) return 0;
477 + con->in_joblist = 1;
479 if (srv->joblist->size == 0) {
480 srv->joblist->size = 16;
481 diff -Naur lighttpd-1.4.19/src/Makefile.am lighttpd-1.4.19.mod_deflate.jz/src/Makefile.am
482 --- lighttpd-1.4.19/src/Makefile.am
483 +++ lighttpd-1.4.19.mod_deflate.jz/src/Makefile.am
485 mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
486 mod_accesslog_la_LIBADD = $(common_libadd)
488 +lib_LTLIBRARIES += mod_deflate.la
489 +mod_deflate_la_SOURCES = mod_deflate.c
490 +mod_deflate_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
491 +mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
494 hdr = server.h buffer.h network.h log.h keyvalue.h \
495 response.h request.h fastcgi.h chunk.h \
496 diff -Naur lighttpd-1.4.19/src/Makefile.in lighttpd-1.4.19.mod_deflate.jz/src/Makefile.in
497 --- lighttpd-1.4.19/src/Makefile.in
498 +++ lighttpd-1.4.19.mod_deflate.jz/src/Makefile.in
500 am_mod_compress_la_OBJECTS = mod_compress.lo
501 mod_compress_la_OBJECTS = $(am_mod_compress_la_OBJECTS)
502 mod_compress_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
503 $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
504 $(mod_compress_la_LDFLAGS) $(LDFLAGS) -o $@
505 +mod_deflate_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
506 + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
507 +am_mod_deflate_la_OBJECTS = mod_deflate.lo
508 +mod_deflate_la_OBJECTS = $(am_mod_deflate_la_OBJECTS)
509 +mod_deflate_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
510 + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
511 + $(mod_deflate_la_LDFLAGS) $(LDFLAGS) -o $@
512 mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
513 $(am__DEPENDENCIES_1)
514 am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo
516 $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) \
517 $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) \
518 $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \
519 + $(mod_deflate_la_SOURCES) \
520 $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \
521 $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \
522 $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) \
524 mod_ssi.la mod_secdownload.la mod_expire.la mod_evhost.la \
525 mod_simple_vhost.la mod_fastcgi.la mod_extforward.la \
526 mod_access.la mod_compress.la mod_auth.la mod_rewrite.la \
527 - mod_redirect.la mod_status.la mod_accesslog.la
528 + mod_redirect.la mod_status.la mod_accesslog.la mod_deflate.la
529 @NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src)
530 @NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS)
531 @NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
533 mod_accesslog_la_SOURCES = mod_accesslog.c
534 mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
535 mod_accesslog_la_LIBADD = $(common_libadd)
536 +mod_deflate_la_SOURCES = mod_deflate.c
537 +mod_deflate_la_LDFLAGS = -module -export-dynamic -no-undefined
538 +mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
539 hdr = server.h buffer.h network.h log.h keyvalue.h \
540 response.h request.h fastcgi.h chunk.h \
541 settings.h http_chunk.h http_auth_digest.h \
543 $(mod_cml_la_LINK) -rpath $(libdir) $(mod_cml_la_OBJECTS) $(mod_cml_la_LIBADD) $(LIBS)
544 mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES)
545 $(mod_compress_la_LINK) -rpath $(libdir) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
546 +mod_deflate.la: $(mod_deflate_la_OBJECTS) $(mod_deflate_la_DEPENDENCIES)
547 + $(mod_deflate_la_LINK) -rpath $(libdir) $(mod_deflate_la_LDFLAGS) $(mod_deflate_la_OBJECTS) $(mod_deflate_la_LIBADD) $(LIBS)
548 mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES)
549 $(mod_dirlisting_la_LINK) -rpath $(libdir) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
550 mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES)
551 @@ -1050,6 +1060,7 @@
552 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo@am__quote@
553 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo@am__quote@
554 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_compress.Plo@am__quote@
555 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_deflate.Plo@am__quote@
556 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_dirlisting.Plo@am__quote@
557 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@
558 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@
559 diff -Naur lighttpd-1.4.19/src/mod_deflate.c lighttpd-1.4.19.mod_deflate.jz/src/mod_deflate.c
560 --- lighttpd-1.4.19/src/mod_deflate.c
561 +++ lighttpd-1.4.19.mod_deflate.jz/src/mod_deflate.c
563 +/* bug fix on Robert Jakabosky from alphatrade.com's lighttp 1.4.10 mod_deflate patch
565 + * new module option:
566 + * deflate.nocompress-url = "^/nocompressurl/" # pcre regex which don't compress
568 + * Bug fix and new features:
569 + * 1) fix loop bug when content-length is bigger than work-block-size*k
570 + * 2) prevent compress on buggy http 1.0 client with Accept Encoding: gzip, deflate
571 + * 3) fix bug with chunk transfer encoding (under mod_fastcgi+php environment)
573 + * deflate.sync-flush = "enable" is buggy on chunk encoding transfer. Use it carefully,
575 +#include <sys/types.h>
576 +#include <sys/stat.h>
587 +#if defined(HAVE_PCRE_H)
594 +#include "response.h"
595 +#include "joblist.h"
596 +#include "stat_cache.h"
602 +#include "inet_ntop_cache.h"
604 +#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
608 +# define Z_DEFAULT_COMPRESSION 1
611 +#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
613 +/* we don't need stdio interface */
614 +# define BZ_NO_STDIO
618 +#include "sys-mmap.h"
620 +/* request: accept-encoding */
621 +#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
622 +#define HTTP_ACCEPT_ENCODING_GZIP BV(1)
623 +#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2)
624 +#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3)
625 +#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4)
627 +#define KByte * 1024
628 +#define MByte * 1024 KByte
629 +#define GByte * 1024 MByte
632 + unsigned short debug;
633 + unsigned short enabled;
634 + unsigned short bzip2;
635 + unsigned short sync_flush;
636 + unsigned short output_buffer_size;
637 + unsigned short min_compress_size;
638 + unsigned short work_block_size;
640 + short compression_level;
643 + buffer *nocompress_url;
644 +#if defined(HAVE_PCRE_H)
645 + pcre *nocompress_regex;
653 + plugin_config **config_storage;
654 + plugin_config conf;
660 + chunkqueue *in_queue;
662 + /* compression type & state */
663 + int compression_type;
668 + unsigned short gzip_header;
673 + plugin_data *plugin_data;
676 +static handler_ctx *handler_ctx_init() {
679 + hctx = calloc(1, sizeof(*hctx));
680 + hctx->in_queue = chunkqueue_init();
685 +static void handler_ctx_free(handler_ctx *hctx) {
686 + chunkqueue_free(hctx->in_queue);
690 +INIT_FUNC(mod_deflate_init) {
693 + p = calloc(1, sizeof(*p));
695 + p->tmp_buf = buffer_init();
700 +FREE_FUNC(mod_deflate_free) {
701 + plugin_data *p = p_d;
705 + if (!p) return HANDLER_GO_ON;
707 + if (p->config_storage) {
709 + for (i = 0; i < srv->config_context->used; i++) {
710 + plugin_config *s = p->config_storage[i];
714 + array_free(s->mimetypes);
715 + buffer_free(s->nocompress_url);
716 +#if defined(HAVE_PCRE_H)
717 + if (s->nocompress_regex) pcre_free(s->nocompress_regex);
721 + free(p->config_storage);
724 + buffer_free(p->tmp_buf);
728 + return HANDLER_GO_ON;
731 +SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
732 + plugin_data *p = p_d;
735 + config_values_t cv[] = {
736 + { "deflate.output-buffer-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
737 + { "deflate.mimetypes", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
738 + { "deflate.compression-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
739 + { "deflate.mem-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
740 + { "deflate.window-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
741 + { "deflate.min-compress-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
742 + { "deflate.work-block-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
743 + { "deflate.enabled", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
744 + { "deflate.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
745 + { "deflate.bzip2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
746 + { "deflate.sync-flush", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
747 + { "deflate.nocompress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
748 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
751 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
753 + for (i = 0; i < srv->config_context->used; i++) {
755 +#if defined(HAVE_PCRE_H)
756 + const char *errptr;
760 + s = calloc(1, sizeof(plugin_config));
765 + s->output_buffer_size = 0;
767 + s->window_size = 15;
768 + s->min_compress_size = 0;
769 + s->work_block_size = 2048;
770 + s->compression_level = Z_DEFAULT_COMPRESSION;
771 + s->mimetypes = array_init();
772 + s->nocompress_url = buffer_init();
773 +#if defined(HAVE_PCRE_H)
774 + s->nocompress_regex = NULL;
777 + cv[0].destination = &(s->output_buffer_size);
778 + cv[1].destination = s->mimetypes;
779 + cv[2].destination = &(s->compression_level);
780 + cv[3].destination = &(s->mem_level);
781 + cv[4].destination = &(s->window_size);
782 + cv[5].destination = &(s->min_compress_size);
783 + cv[6].destination = &(s->work_block_size);
784 + cv[7].destination = &(s->enabled);
785 + cv[8].destination = &(s->debug);
786 + cv[9].destination = &(s->bzip2);
787 + cv[10].destination = &(s->sync_flush);
788 + cv[11].destination = s->nocompress_url;
790 + p->config_storage[i] = s;
792 + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
793 + return HANDLER_ERROR;
796 +#if defined(HAVE_PCRE_H)
797 + if (!buffer_is_empty(s->nocompress_url)) {
798 + if (NULL == (s->nocompress_regex = pcre_compile(s->nocompress_url->ptr,
799 + 0, &errptr, &erroff, NULL))) {
801 + log_error_write(srv, __FILE__, __LINE__, "sbss",
802 + "compiling regex for nocompress-url failed:",
803 + s->nocompress_url, "pos:", erroff);
804 + return HANDLER_ERROR;
808 + if((s->compression_level < 1 || s->compression_level > 9) &&
809 + s->compression_level != Z_DEFAULT_COMPRESSION) {
810 + log_error_write(srv, __FILE__, __LINE__, "sd",
811 + "compression-level must be between 1 and 9:", s->compression_level);
812 + return HANDLER_ERROR;
815 + if(s->mem_level < 1 || s->mem_level > 9) {
816 + log_error_write(srv, __FILE__, __LINE__, "sd",
817 + "mem-level must be between 1 and 9:", s->mem_level);
818 + return HANDLER_ERROR;
821 + if(s->window_size < 1 || s->window_size > 15) {
822 + log_error_write(srv, __FILE__, __LINE__, "sd",
823 + "window-size must be between 1 and 15:", s->window_size);
824 + return HANDLER_ERROR;
826 + s->window_size = 0 - s->window_size;
828 + if(s->sync_flush) {
829 + s->output_buffer_size = 0;
833 + return HANDLER_GO_ON;
838 +/* Copied gzip_header from apache 2.2's mod_deflate.c */
839 +/* RFC 1952 Section 2.3 defines the gzip header:
841 + * +---+---+---+---+---+---+---+---+---+---+
842 + * |ID1|ID2|CM |FLG| MTIME |XFL|OS |
843 + * +---+---+---+---+---+---+---+---+---+---+
845 +static const char gzip_header[10] =
846 +{ '\037', '\213', Z_DEFLATED, 0,
847 + 0, 0, 0, 0, /* mtime */
848 + 0, 0x03 /* Unix OS_CODE */
850 +static int stream_deflate_init(server *srv, connection *con, handler_ctx *hctx) {
851 + plugin_data *p = hctx->plugin_data;
858 + z->zalloc = Z_NULL;
860 + z->opaque = Z_NULL;
863 + z->next_out = NULL;
866 + if(p->conf.debug) {
867 + log_error_write(srv, __FILE__, __LINE__, "sd",
868 + "output-buffer-size:", p->conf.output_buffer_size);
869 + log_error_write(srv, __FILE__, __LINE__, "sd",
870 + "compression-level:", p->conf.compression_level);
871 + log_error_write(srv, __FILE__, __LINE__, "sd",
872 + "mem-level:", p->conf.mem_level);
873 + log_error_write(srv, __FILE__, __LINE__, "sd",
874 + "window-size:", p->conf.window_size);
875 + log_error_write(srv, __FILE__, __LINE__, "sd",
876 + "min-compress-size:", p->conf.min_compress_size);
877 + log_error_write(srv, __FILE__, __LINE__, "sd",
878 + "work-block-size:", p->conf.work_block_size);
880 + if (Z_OK != deflateInit2(z,
881 + p->conf.compression_level,
883 + p->conf.window_size, /* supress zlib-header */
885 + Z_DEFAULT_STRATEGY)) {
888 + hctx->stream_open = 1;
893 +static int stream_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
894 + plugin_data *p = hctx->plugin_data;
897 + int in = 0, out = 0;
902 + if(z->next_out == NULL) {
903 + z->next_out = (unsigned char *)hctx->output->ptr;
904 + z->avail_out = hctx->output->size;
907 + if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP) {
908 + if(hctx->gzip_header == 0) {
909 + hctx->gzip_header = 1;
910 + /* copy gzip header into output buffer */
911 + buffer_copy_memory(hctx->output, gzip_header, sizeof(gzip_header));
912 + if(p->conf.debug) {
913 + log_error_write(srv, __FILE__, __LINE__, "sd",
914 + "gzip_header len=", sizeof(gzip_header));
916 + /* initialize crc32 */
917 + hctx->crc = crc32(0L, Z_NULL, 0);
918 + z->next_out = (unsigned char *)(hctx->output->ptr + sizeof(gzip_header));
919 + z->avail_out = hctx->output->size - sizeof(gzip_header);
921 + hctx->crc = crc32(hctx->crc, start, st_size);
924 + z->next_in = start;
925 + z->avail_in = st_size;
926 + hctx->bytes_in += st_size;
928 + /* compress data */
931 + if (Z_OK != deflate(z, Z_NO_FLUSH)) {
933 + hctx->stream_open = 0;
937 + if(z->avail_out == 0 || z->avail_in > 0) {
938 + len = hctx->output->size - z->avail_out;
939 + hctx->bytes_out += len;
941 + chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
942 + z->next_out = (unsigned char *)hctx->output->ptr;
943 + z->avail_out = hctx->output->size;
945 + } while (z->avail_in > 0);
947 + if(p->conf.debug) {
948 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
949 + "compress: in=", in, ", out=", out);
954 +static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
955 + plugin_data *p = hctx->plugin_data;
961 + int in = 0, out = 0;
967 + if(z->next_out == NULL) {
968 + z->next_out = (unsigned char *)hctx->output->ptr;
969 + z->avail_out = hctx->output->size;
971 + /* compress data */
976 + rc = deflate(z, Z_FINISH);
979 + } else if (rc != Z_STREAM_END) {
981 + hctx->stream_open = 0;
985 + if(p->conf.sync_flush) {
986 + rc = deflate(z, Z_SYNC_FLUSH);
987 + } else if(z->avail_in > 0) {
988 + if(p->conf.output_buffer_size > 0) flush = 0;
989 + rc = deflate(z, Z_NO_FLUSH);
991 + if(p->conf.output_buffer_size > 0) flush = 0;
996 + hctx->stream_open = 0;
1001 + len = hctx->output->size - z->avail_out;
1002 + if(z->avail_out == 0 || (flush && len > 0)) {
1003 + hctx->bytes_out += len;
1005 + chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
1006 + z->next_out = (unsigned char *)hctx->output->ptr;
1007 + z->avail_out = hctx->output->size;
1009 + } while (z->avail_in != 0 || !done);
1012 + if(p->conf.debug) {
1013 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
1014 + "flush: in=", in, ", out=", out);
1016 + if(p->conf.sync_flush) {
1017 + z->next_out = NULL;
1023 +static int stream_deflate_end(server *srv, connection *con, handler_ctx *hctx) {
1024 + plugin_data *p = hctx->plugin_data;
1031 + if(!hctx->stream_open) return 0;
1032 + hctx->stream_open = 0;
1034 + if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP && hctx->bytes_out > 0 &&
1035 + (unsigned int )hctx->bytes_out >= sizeof(gzip_header)) {
1036 + /* write gzip footer */
1037 + unsigned char c[8];
1039 + c[0] = (hctx->crc >> 0) & 0xff;
1040 + c[1] = (hctx->crc >> 8) & 0xff;
1041 + c[2] = (hctx->crc >> 16) & 0xff;
1042 + c[3] = (hctx->crc >> 24) & 0xff;
1043 + c[4] = (z->total_in >> 0) & 0xff;
1044 + c[5] = (z->total_in >> 8) & 0xff;
1045 + c[6] = (z->total_in >> 16) & 0xff;
1046 + c[7] = (z->total_in >> 24) & 0xff;
1047 + /* append footer to write_queue */
1048 + chunkqueue_append_mem(con->write_queue, (char *)c, 9);
1049 + hctx->bytes_out += 8;
1050 + if(p->conf.debug) {
1051 + log_error_write(srv, __FILE__, __LINE__, "sd",
1052 + "gzip_footer len=", 8);
1056 + if ((rc = deflateEnd(z)) != Z_OK) {
1057 + if(rc == Z_DATA_ERROR) return 0;
1058 + if(z->msg != NULL) {
1059 + log_error_write(srv, __FILE__, __LINE__, "sdss",
1060 + "deflateEnd error ret=", rc, ", msg=", z->msg);
1062 + log_error_write(srv, __FILE__, __LINE__, "sd",
1063 + "deflateEnd error ret=", rc);
1073 +static int stream_bzip2_init(server *srv, connection *con, handler_ctx *hctx) {
1074 + plugin_data *p = hctx->plugin_data;
1081 + bz->bzalloc = NULL;
1082 + bz->bzfree = NULL;
1083 + bz->opaque = NULL;
1084 + bz->total_in_lo32 = 0;
1085 + bz->total_in_hi32 = 0;
1086 + bz->total_out_lo32 = 0;
1087 + bz->total_out_hi32 = 0;
1089 + if(p->conf.debug) {
1090 + log_error_write(srv, __FILE__, __LINE__, "sd",
1091 + "output-buffer-size:", p->conf.output_buffer_size);
1092 + log_error_write(srv, __FILE__, __LINE__, "sd",
1093 + "compression-level:", p->conf.compression_level);
1094 + log_error_write(srv, __FILE__, __LINE__, "sd",
1095 + "mem-level:", p->conf.mem_level);
1096 + log_error_write(srv, __FILE__, __LINE__, "sd",
1097 + "window-size:", p->conf.window_size);
1098 + log_error_write(srv, __FILE__, __LINE__, "sd",
1099 + "min-compress-size:", p->conf.min_compress_size);
1100 + log_error_write(srv, __FILE__, __LINE__, "sd",
1101 + "work-block-size:", p->conf.work_block_size);
1103 + if (BZ_OK != BZ2_bzCompressInit(bz,
1104 + p->conf.compression_level, /* blocksize = 900k */
1105 + 0, /* no output */
1106 + 30)) { /* workFactor: default */
1109 + hctx->stream_open = 1;
1114 +static int stream_bzip2_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
1115 + plugin_data *p = hctx->plugin_data;
1119 + int in = 0, out = 0;
1125 + if(bz->next_out == NULL) {
1126 + bz->next_out = hctx->output->ptr;
1127 + bz->avail_out = hctx->output->size;
1130 + bz->next_in = (char *)start;
1131 + bz->avail_in = st_size;
1132 + hctx->bytes_in += st_size;
1134 + /* compress data */
1135 + in = bz->avail_in;
1137 + rc = BZ2_bzCompress(bz, BZ_RUN);
1138 + if (rc != BZ_RUN_OK) {
1139 + BZ2_bzCompressEnd(bz);
1140 + hctx->stream_open = 0;
1144 + if(bz->avail_out == 0 || bz->avail_in > 0) {
1145 + len = hctx->output->size - bz->avail_out;
1146 + hctx->bytes_out += len;
1148 + chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
1149 + bz->next_out = hctx->output->ptr;
1150 + bz->avail_out = hctx->output->size;
1152 + } while (bz->avail_in > 0);
1153 + if(p->conf.debug) {
1154 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
1155 + "compress: in=", in, ", out=", out);
1160 +static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
1161 + plugin_data *p = hctx->plugin_data;
1167 + int in = 0, out = 0;
1173 + if(bz->next_out == NULL) {
1174 + bz->next_out = hctx->output->ptr;
1175 + bz->avail_out = hctx->output->size;
1177 + /* compress data */
1178 + in = bz->avail_in;
1182 + rc = BZ2_bzCompress(bz, BZ_FINISH);
1183 + if (rc == BZ_FINISH_OK) {
1185 + } else if (rc != BZ_STREAM_END) {
1186 + BZ2_bzCompressEnd(bz);
1187 + hctx->stream_open = 0;
1190 + } else if(bz->avail_in > 0) {
1191 + rc = BZ2_bzCompress(bz, BZ_RUN);
1192 + if (rc != BZ_RUN_OK) {
1193 + BZ2_bzCompressEnd(bz);
1194 + hctx->stream_open = 0;
1197 + if(p->conf.output_buffer_size > 0) flush = 0;
1200 + len = hctx->output->size - bz->avail_out;
1201 + if(bz->avail_out == 0 || (flush && len > 0)) {
1202 + hctx->bytes_out += len;
1204 + chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
1205 + bz->next_out = hctx->output->ptr;
1206 + bz->avail_out = hctx->output->size;
1208 + } while (bz->avail_in != 0 || !done);
1209 + if(p->conf.debug) {
1210 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
1211 + "flush: in=", in, ", out=", out);
1213 + if(p->conf.sync_flush) {
1214 + bz->next_out = NULL;
1215 + bz->avail_out = 0;
1220 +static int stream_bzip2_end(server *srv, connection *con, handler_ctx *hctx) {
1221 + plugin_data *p = hctx->plugin_data;
1229 + if(!hctx->stream_open) return 0;
1230 + hctx->stream_open = 0;
1232 + if ((rc = BZ2_bzCompressEnd(bz)) != BZ_OK) {
1233 + if(rc == BZ_DATA_ERROR) return 0;
1234 + log_error_write(srv, __FILE__, __LINE__, "sd",
1235 + "BZ2_bzCompressEnd error ret=", rc);
1243 +static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
1245 + if(st_size == 0) return 0;
1246 + switch(hctx->compression_type) {
1248 + case HTTP_ACCEPT_ENCODING_GZIP:
1249 + case HTTP_ACCEPT_ENCODING_DEFLATE:
1250 + ret = stream_deflate_compress(srv, con, hctx, start, st_size);
1254 + case HTTP_ACCEPT_ENCODING_BZIP2:
1255 + ret = stream_bzip2_compress(srv, con, hctx, start, st_size);
1266 +static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
1268 + if(hctx->bytes_in == 0) return 0;
1269 + switch(hctx->compression_type) {
1271 + case HTTP_ACCEPT_ENCODING_GZIP:
1272 + case HTTP_ACCEPT_ENCODING_DEFLATE:
1273 + ret = stream_deflate_flush(srv, con, hctx, end);
1277 + case HTTP_ACCEPT_ENCODING_BZIP2:
1278 + ret = stream_bzip2_flush(srv, con, hctx, end);
1289 +static int mod_deflate_stream_end(server *srv, connection *con, handler_ctx *hctx) {
1291 + switch(hctx->compression_type) {
1293 + case HTTP_ACCEPT_ENCODING_GZIP:
1294 + case HTTP_ACCEPT_ENCODING_DEFLATE:
1295 + ret = stream_deflate_end(srv, con, hctx);
1299 + case HTTP_ACCEPT_ENCODING_BZIP2:
1300 + ret = stream_bzip2_end(srv, con, hctx);
1311 +static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hctx, chunk *c, off_t st_size) {
1312 + plugin_data *p = hctx->plugin_data;
1315 + stat_cache_entry *sce = NULL;
1316 + off_t we_want_to_mmap = 2 MByte;
1317 + off_t we_want_to_send = st_size;
1318 + char *start = NULL;
1320 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
1321 + log_error_write(srv, __FILE__, __LINE__, "sb",
1322 + strerror(errno), c->file.name);
1326 + abs_offset = c->file.start + c->offset;
1328 + if (abs_offset > sce->st.st_size) {
1329 + log_error_write(srv, __FILE__, __LINE__, "sb",
1330 + "file was shrinked:", c->file.name);
1335 + we_want_to_send = st_size;
1336 + /* mmap the buffer
1338 + * - new mmap as the we are at the end of the last one */
1339 + if (c->file.mmap.start == MAP_FAILED ||
1340 + abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
1342 + /* Optimizations for the future:
1344 + * adaptive mem-mapping
1346 + * we mmap() the whole file. If someone has alot large files and 32bit
1347 + * machine the virtual address area will be unrun and we will have a failing
1350 + * only mmap 16M in one chunk and move the window as soon as we have finished
1353 + * read-ahead buffering
1355 + * sending out several large files in parallel trashes the read-ahead of the
1356 + * kernel leading to long wait-for-seek times.
1357 + * solutions: (increasing complexity)
1359 + * 2. use a internal read-ahead buffer in the chunk-structure
1360 + * 3. use non-blocking IO for file-transfers
1363 + /* all mmap()ed areas are 512kb expect the last which might be smaller */
1366 + /* this is a remap, move the mmap-offset */
1367 + if (c->file.mmap.start != MAP_FAILED) {
1368 + munmap(c->file.mmap.start, c->file.mmap.length);
1369 + c->file.mmap.offset += we_want_to_mmap;
1371 + /* in case the range-offset is after the first mmap()ed area we skip the area */
1372 + c->file.mmap.offset = 0;
1374 + while (c->file.mmap.offset + we_want_to_mmap < c->file.start) {
1375 + c->file.mmap.offset += we_want_to_mmap;
1379 + /* length is rel, c->offset too, assume there is no limit at the mmap-boundaries */
1380 + to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset;
1381 + if(to_mmap > we_want_to_mmap) to_mmap = we_want_to_mmap;
1382 + /* we have more to send than we can mmap() at once */
1383 + if(we_want_to_send > to_mmap) we_want_to_send = to_mmap;
1385 + if (-1 == c->file.fd) { /* open the file if not already open */
1386 + if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
1387 + log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
1392 + fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
1396 + if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
1397 + /* close it here, otherwise we'd have to set FD_CLOEXEC */
1399 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
1400 + strerror(errno), c->file.name, c->file.fd);
1405 + c->file.mmap.length = to_mmap;
1406 +#ifdef LOCAL_BUFFERING
1407 + buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
1409 +#ifdef HAVE_MADVISE
1410 + /* don't advise files < 64Kb */
1411 + if (c->file.mmap.length > (64 KByte) &&
1412 + 0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) {
1413 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "madvise failed:",
1414 + strerror(errno), c->file.name, c->file.fd);
1419 + /* chunk_reset() or chunk_free() will cleanup for us */
1422 + /* to_send = abs_mmap_end - abs_offset */
1423 + toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
1424 + if(toSend > we_want_to_send) toSend = we_want_to_send;
1427 + log_error_write(srv, __FILE__, __LINE__, "soooo",
1428 + "toSend is negative:",
1430 + c->file.mmap.length,
1432 + c->file.mmap.offset);
1433 + assert(toSend < 0);
1436 +#ifdef LOCAL_BUFFERING
1437 + start = c->mem->ptr;
1439 + start = c->file.mmap.start;
1442 + if(p->conf.debug) {
1443 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
1444 + "compress file chunk: offset=", (int)c->offset,
1445 + ", toSend=", (int)toSend);
1447 + if (mod_deflate_compress(srv, con, hctx,
1448 + (unsigned char *)start + (abs_offset - c->file.mmap.offset), toSend) < 0) {
1449 + log_error_write(srv, __FILE__, __LINE__, "s",
1450 + "compress failed.");
1454 + c->offset += toSend;
1455 + if (c->offset == c->file.length) {
1456 + /* we don't need the mmaping anymore */
1457 + if (c->file.mmap.start != MAP_FAILED) {
1458 + munmap(c->file.mmap.start, c->file.mmap.length);
1459 + c->file.mmap.start = MAP_FAILED;
1466 +static int deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) {
1467 + plugin_data *p = hctx->plugin_data;
1470 + rc = mod_deflate_stream_end(srv, con, hctx);
1472 + log_error_write(srv, __FILE__, __LINE__, "s", "error closing stream");
1475 + if (hctx->bytes_in < hctx->bytes_out) {
1476 + log_error_write(srv, __FILE__, __LINE__, "sbsdsd",
1477 + "uri ", con->uri.path_raw, " in=", hctx->bytes_in, " smaller than out=", hctx->bytes_out);
1480 + if(p->conf.debug) {
1481 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
1482 + " in:", hctx->bytes_in,
1483 + " out:", hctx->bytes_out);
1486 + /* cleanup compression state */
1487 + if(hctx->output != p->tmp_buf) {
1488 + buffer_free(hctx->output);
1490 + handler_ctx_free(hctx);
1491 + con->plugin_ctx[p->id] = NULL;
1496 +static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx, int end) {
1497 + plugin_data *p = hctx->plugin_data;
1499 + size_t chunks_written = 0;
1500 + int chunk_finished = 0;
1502 + int close_stream = 0, len = 0;
1503 + unsigned int out = 0, max = 0;
1505 + /* move all chunk from write_queue into our in_queue */
1506 + chunkqueue_append_chunkqueue(hctx->in_queue, con->write_queue);
1508 + len = chunkqueue_length(hctx->in_queue);
1509 + if(p->conf.debug) {
1510 + log_error_write(srv, __FILE__, __LINE__, "sd",
1511 + "compress: in_queue len=", len);
1513 + /* calculate max bytes to compress for this call. */
1515 + max = p->conf.work_block_size * 1024;
1516 + if(max == 0 || max > len) max = len;
1521 + /* Compress chunks from in_queue into chunks for write_queue */
1522 + for(c = hctx->in_queue->first; c && out < max; c = c->next) {
1523 + chunk_finished = 0;
1528 + len = c->mem->used - 1;
1529 + if(len > (max - out)) len = max - out;
1530 + if (mod_deflate_compress(srv, con, hctx, (unsigned char *)c->mem->ptr, len) < 0) {
1531 + log_error_write(srv, __FILE__, __LINE__, "s",
1532 + "compress failed.");
1533 + return HANDLER_ERROR;
1537 + if (c->offset == c->mem->used - 1) {
1538 + chunk_finished = 1;
1543 + len = c->file.length - c->offset;
1544 + if(len > (max - out)) len = max - out;
1545 + if ((len = mod_deflate_file_chunk(srv, con, hctx, c, len)) < 0) {
1546 + log_error_write(srv, __FILE__, __LINE__, "s",
1547 + "compress file chunk failed.");
1548 + return HANDLER_ERROR;
1551 + if (c->offset == c->file.length) {
1552 + chunk_finished = 1;
1558 + log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
1560 + return HANDLER_ERROR;
1562 + if(!chunk_finished) break;
1564 + if(p->conf.debug) {
1565 + log_error_write(srv, __FILE__, __LINE__, "sd",
1566 + "compressed bytes:", out);
1568 + hctx->in_queue->bytes_out += out;
1570 + if(chunks_written > 0) {
1571 + chunkqueue_remove_finished_chunks(hctx->in_queue);
1574 + close_stream = (con->file_finished && chunkqueue_is_empty(hctx->in_queue));
1575 + rc = mod_deflate_stream_flush(srv, con, hctx, close_stream);
1577 + log_error_write(srv, __FILE__, __LINE__, "s", "flush error");
1579 + if(close_stream || end) {
1580 + deflate_compress_cleanup(srv, con, hctx);
1581 + if(p->conf.debug) {
1582 + log_error_write(srv, __FILE__, __LINE__, "sbsb",
1583 + "finished uri:", con->uri.path_raw, ", query:", con->uri.query);
1585 + return HANDLER_FINISHED;
1587 + if(!chunkqueue_is_empty(hctx->in_queue)) {
1588 + /* We have more data to compress. */
1589 + joblist_append(srv, con);
1591 + return HANDLER_COMEBACK;
1597 +static int mod_deflate_patch_connection(server *srv, connection *con, plugin_data *p) {
1599 + plugin_config *s = p->config_storage[0];
1601 + PATCH(output_buffer_size);
1603 + PATCH(compression_level);
1605 + PATCH(window_size);
1606 + PATCH(min_compress_size);
1607 + PATCH(work_block_size);
1611 + PATCH(sync_flush);
1612 +#if defined(HAVE_PCRE_H)
1613 + PATCH(nocompress_regex);
1616 + /* skip the first, the global context */
1617 + for (i = 1; i < srv->config_context->used; i++) {
1618 + data_config *dc = (data_config *)srv->config_context->data[i];
1619 + s = p->config_storage[i];
1621 + /* condition didn't match */
1622 + if (!config_check_cond(srv, con, dc)) continue;
1624 + /* merge config */
1625 + for (j = 0; j < dc->value->used; j++) {
1626 + data_unset *du = dc->value->data[j];
1628 + if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.output-buffer-size"))) {
1629 + PATCH(output_buffer_size);
1630 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.mimetypes"))) {
1632 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.compression-level"))) {
1633 + PATCH(compression_level);
1634 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.mem-level"))) {
1636 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.window-size"))) {
1637 + PATCH(window_size);
1638 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.min-compress-size"))) {
1639 + PATCH(min_compress_size);
1640 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.work-block-size"))) {
1641 + PATCH(work_block_size);
1642 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.enabled"))) {
1644 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.debug"))) {
1646 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.bzip2"))) {
1648 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.sync-flush"))) {
1649 + PATCH(sync_flush);
1650 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.nocompress-url"))) {
1651 +#if defined(HAVE_PCRE_H)
1652 + PATCH(nocompress_regex);
1662 +PHYSICALPATH_FUNC(mod_deflate_handle_response_start) {
1663 + plugin_data *p = p_d;
1664 + handler_ctx *hctx;
1666 + int accept_encoding = 0;
1668 + int srv_encodings = 0;
1669 + int matched_encodings = 0;
1670 + const char *dflt_gzip = "gzip";
1671 + const char *dflt_deflate = "deflate";
1672 + const char *dflt_bzip2 = "bzip2";
1673 + const char *compression_name = NULL;
1678 +#if defined(HAVE_PCRE_H)
1684 + /* disable compression for some http status types. */
1685 + switch(con->http_status) {
1691 + /* disable compression as we have no response entity */
1692 + return HANDLER_GO_ON;
1697 + mod_deflate_patch_connection(srv, con, p);
1699 + /* is compression allowed */
1700 + if(!p->conf.enabled) {
1701 + if(p->conf.debug) {
1702 + log_error_write(srv, __FILE__, __LINE__, "s", "compression disabled.");
1704 + return HANDLER_GO_ON;
1707 +#if defined(HAVE_PCRE_H)
1708 + if(p->conf.nocompress_regex) { /*check no compress regex now */
1709 + if ((n = pcre_exec(p->conf.nocompress_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
1710 + if (n != PCRE_ERROR_NOMATCH) {
1711 + log_error_write(srv, __FILE__, __LINE__, "sd",
1712 + "execution error while matching:", n);
1713 + return HANDLER_ERROR;
1716 + if(p->conf.debug) {
1717 + log_error_write(srv, __FILE__, __LINE__, "sb", "no compress for url:", con->uri.path);
1719 + return HANDLER_GO_ON;
1723 + /* Check if response has a Content-Encoding. */
1724 + if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Encoding"))) {
1725 + return HANDLER_GO_ON;
1728 + /* Check Accept-Encoding for supported encoding. */
1729 + if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
1730 + return HANDLER_GO_ON;
1733 + /* get client side support encodings */
1734 + value = ds->value->ptr;
1736 + if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
1737 + if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
1739 + /* if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; */
1741 + if(p->conf.bzip2) {
1742 + if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
1745 + if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
1747 + /* get server side supported ones */
1749 + if(p->conf.bzip2) {
1750 + srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
1754 + srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
1755 + srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
1758 + /* find matching encodings */
1759 + matched_encodings = accept_encoding & srv_encodings;
1760 + if (!matched_encodings) {
1761 + return HANDLER_GO_ON;
1764 + if (con->request.true_http_10_client) {
1765 + /*disable gzip/bzip2 when we meet HTTP 1.0 client with Accept-Encoding
1766 + * maybe old buggy proxy server
1768 + /* most of buggy clients are Yahoo Slurp;) */
1769 + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ss",
1770 + "Buggy HTTP 1.0 client sending Accept Encoding: gzip, deflate",
1771 + (char *) inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
1772 + return HANDLER_GO_ON;
1774 + /* check if size of response is below min-compress-size */
1775 + if(con->file_finished && con->request.http_method != HTTP_METHOD_HEAD) {
1776 + file_len = chunkqueue_length(con->write_queue);
1777 + if(file_len == 0) return HANDLER_GO_ON;
1782 + if(file_len > 0 && p->conf.min_compress_size > 0 && file_len < p->conf.min_compress_size) {
1783 + if(p->conf.debug) {
1784 + log_error_write(srv, __FILE__, __LINE__, "sd",
1785 + "Content-Length smaller then min_compress_size: file_len=", file_len);
1787 + return HANDLER_GO_ON;
1790 + /* Check mimetype in response header "Content-Type" */
1791 + if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
1793 + if(p->conf.debug) {
1794 + log_error_write(srv, __FILE__, __LINE__, "sb",
1795 + "Content-Type:", ds->value);
1797 + for (m = 0; m < p->conf.mimetypes->used; m++) {
1798 + data_string *mimetype = (data_string *)p->conf.mimetypes->data[m];
1800 + if(p->conf.debug) {
1801 + log_error_write(srv, __FILE__, __LINE__, "sb",
1802 + "mime-type:", mimetype->value);
1804 + if (strncmp(mimetype->value->ptr, ds->value->ptr, mimetype->value->used-1) == 0) {
1805 +/* if (buffer_is_equal(mimetype->value, ds->value)) { */
1806 + /* mimetype found */
1811 + if(!found && p->conf.mimetypes->used > 0) {
1812 + if(p->conf.debug) {
1813 + log_error_write(srv, __FILE__, __LINE__, "sb",
1814 + "No compression for mimetype:", ds->value);
1816 + return HANDLER_GO_ON;
1819 + if(strncasecmp(ds->value->ptr, "application/x-javascript", 24) == 0) {
1820 + /*reset compress type to deflate for javascript
1821 + * prevent buggy IE6 SP1 doesn't work for js in IFrame
1823 + matched_encodings = HTTP_ACCEPT_ENCODING_DEFLATE;
1828 + if(p->conf.debug) {
1829 + log_error_write(srv, __FILE__, __LINE__, "sb",
1830 + "enable compression for ", con->uri.path);
1833 + /* the response might change according to Accept-Encoding */
1834 + if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Vary"))) {
1835 + /* append Accept-Encoding to Vary header */
1836 + if (NULL == strstr(ds->value->ptr, "Accept-Encoding")) {
1837 + buffer_append_string(ds->value, ",Accept-Encoding");
1838 + if (p->conf.debug) {
1839 + log_error_write(srv, __FILE__, __LINE__, "sb",
1840 + "appending ,Accept-Encoding for ", con->uri.path);
1844 + if (p->conf.debug) {
1845 + log_error_write(srv, __FILE__, __LINE__, "sb",
1846 + "add Vary: Accept-Encoding for ", con->uri.path);
1848 + response_header_insert(srv, con, CONST_STR_LEN("Vary"),
1849 + CONST_STR_LEN("Accept-Encoding"));
1852 + /* enable compression */
1853 + hctx = handler_ctx_init();
1854 + hctx->plugin_data = p;
1856 + /* select best matching encoding */
1857 + if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
1858 + hctx->compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
1859 + compression_name = dflt_bzip2;
1860 + rc = stream_bzip2_init(srv, con, hctx);
1861 + } else if (matched_encodings & HTTP_ACCEPT_ENCODING_GZIP) {
1862 + hctx->compression_type = HTTP_ACCEPT_ENCODING_GZIP;
1863 + compression_name = dflt_gzip;
1864 + rc = stream_deflate_init(srv, con, hctx);
1865 + } else if (matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE) {
1866 + hctx->compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
1867 + compression_name = dflt_deflate;
1868 + rc = stream_deflate_init(srv, con, hctx);
1871 + log_error_write(srv, __FILE__, __LINE__, "s",
1872 + "Failed to initialize compression.");
1876 + handler_ctx_free(hctx);
1877 + return HANDLER_GO_ON;
1880 + /* setup output buffer. */
1881 + if(p->conf.sync_flush || p->conf.output_buffer_size == 0) {
1882 + buffer_prepare_copy(p->tmp_buf, 32 * 1024);
1883 + hctx->output = p->tmp_buf;
1885 + hctx->output = buffer_init();
1886 + buffer_prepare_copy(hctx->output, p->conf.output_buffer_size);
1888 + con->plugin_ctx[p->id] = hctx;
1890 + /* set Content-Encoding to show selected compression type. */
1891 + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
1893 + if (con->file_finished) end = 1;
1895 + con->parsed_response &= ~(HTTP_CONTENT_LENGTH);
1898 + if (con->parsed_response & HTTP_TRANSFER_ENCODING_CHUNKED)
1899 + log_error_write(srv, __FILE__, __LINE__, "s",
1900 + "deflate: response with chunked encoding");
1901 + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED)
1902 + log_error_write(srv, __FILE__, __LINE__, "s",
1903 + "deflate: transfer encoding with chunked encoding");
1906 + if (con->file_finished && (p->conf.work_block_size == 0 || file_len < (p->conf.work_block_size * 1024))
1907 + && con->request.http_method != HTTP_METHOD_HEAD) {
1908 + /* disable chunk transfer */
1909 + con->response.transfer_encoding = 0;
1910 + con->parsed_response &= ~(HTTP_TRANSFER_ENCODING_CHUNKED);
1911 + if(p->conf.debug) {
1912 + log_error_write(srv, __FILE__, __LINE__, "sd",
1913 + "Compress all content and use Content-Length header: uncompress len=", file_len);
1915 + return deflate_compress_response(srv, con, hctx, end);
1917 + if (con->request.http_version == HTTP_VERSION_1_1) {
1918 + if (p->conf.debug)
1919 + log_error_write(srv, __FILE__, __LINE__, "sb",
1920 + "chunk transfer encoding for uri", con->uri.path);
1921 + /* Make sure to use chunked encoding. */
1922 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
1924 + if (p->conf.debug)
1925 + log_error_write(srv, __FILE__, __LINE__, "sb",
1926 + "http 1.0 encoding for uri", con->uri.path);
1927 + /* We don't have to use chunked encoding because HTTP 1.0 don't support it. */
1928 + con->response.transfer_encoding = 0;
1929 + con->parsed_response &= ~(HTTP_TRANSFER_ENCODING_CHUNKED);
1933 + if (p->conf.debug)
1934 + log_error_write(srv, __FILE__, __LINE__, "sdsb", "end =", end, "for uri", con->uri.path);
1936 + deflate_compress_response(srv, con, hctx, end);
1937 + return HANDLER_GO_ON;
1940 +JOBLIST_FUNC(mod_deflate_handle_response_filter) {
1941 + plugin_data *p = p_d;
1942 + handler_ctx *hctx = con->plugin_ctx[p->id];
1944 + if(hctx == NULL) return HANDLER_GO_ON;
1945 + if(!hctx->stream_open) return HANDLER_GO_ON;
1946 + if(con->request.http_method == HTTP_METHOD_HEAD) return HANDLER_GO_ON;
1948 + return deflate_compress_response(srv, con, hctx, 0);
1951 +handler_t mod_deflate_cleanup(server *srv, connection *con, void *p_d) {
1952 + plugin_data *p = p_d;
1953 + handler_ctx *hctx = con->plugin_ctx[p->id];
1955 + if(hctx == NULL) return HANDLER_GO_ON;
1957 + if(p->conf.debug && hctx->stream_open) {
1958 + log_error_write(srv, __FILE__, __LINE__, "sbsb",
1959 + "stream open at cleanup. uri=", con->uri.path_raw, ", query=", con->uri.query);
1962 + deflate_compress_cleanup(srv, con, hctx);
1964 + return HANDLER_GO_ON;
1967 +int mod_deflate_plugin_init(plugin *p) {
1968 + p->version = LIGHTTPD_VERSION_ID;
1969 + p->name = buffer_init_string("deflate");
1971 + p->init = mod_deflate_init;
1972 + p->cleanup = mod_deflate_free;
1973 + p->set_defaults = mod_deflate_setdefaults;
1974 + p->connection_reset = mod_deflate_cleanup;
1975 + p->handle_connection_close = mod_deflate_cleanup;
1976 + p->handle_response_start = mod_deflate_handle_response_start;
1977 + p->handle_response_filter = mod_deflate_handle_response_filter;
1983 diff -Naur lighttpd-1.4.19/src/plugin.c lighttpd-1.4.19.mod_deflate.jz/src/plugin.c
1984 --- lighttpd-1.4.19/src/plugin.c
1985 +++ lighttpd-1.4.19.mod_deflate.jz/src/plugin.c
1987 PLUGIN_FUNC_HANDLE_SIGHUP,
1988 PLUGIN_FUNC_HANDLE_SUBREQUEST,
1989 PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
1990 + PLUGIN_FUNC_HANDLE_RESPONSE_START,
1991 + PLUGIN_FUNC_HANDLE_RESPONSE_FILTER,
1992 PLUGIN_FUNC_HANDLE_JOBLIST,
1993 PLUGIN_FUNC_HANDLE_DOCROOT,
1994 PLUGIN_FUNC_HANDLE_PHYSICAL,
1996 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
1997 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
1998 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
1999 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
2000 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, handle_response_filter)
2001 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
2002 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
2003 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
2005 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
2006 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
2007 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
2008 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start);
2009 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, handle_response_filter);
2010 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
2011 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
2012 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
2013 diff -Naur lighttpd-1.4.19/src/plugin.h lighttpd-1.4.19.mod_deflate.jz/src/plugin.h
2014 --- lighttpd-1.4.19/src/plugin.h
2015 +++ lighttpd-1.4.19.mod_deflate.jz/src/plugin.h
2019 handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
2020 + handler_t (* handle_response_start) (server *srv, connection *con, void *p_d); /* before response headers are written */
2021 + handler_t (* handle_response_filter) (server *srv, connection *con, void *p_d); /* response content filter */
2022 handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
2026 handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
2027 handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
2028 handler_t plugins_call_handle_subrequest(server *srv, connection *con);
2029 +handler_t plugins_call_handle_response_start(server *srv, connection *con);
2030 +handler_t plugins_call_handle_response_filter(server *srv, connection *con);
2031 handler_t plugins_call_handle_request_done(server *srv, connection *con);
2032 handler_t plugins_call_handle_docroot(server *srv, connection *con);
2033 handler_t plugins_call_handle_physical(server *srv, connection *con);
2034 diff -Naur lighttpd-1.4.19/src/request.c lighttpd-1.4.19.mod_deflate.jz/src/request.c
2035 --- lighttpd-1.4.19/src/request.c
2036 +++ lighttpd-1.4.19.mod_deflate.jz/src/request.c
2037 @@ -415,8 +415,10 @@
2039 if (major_num == 1 && minor_num == 1) {
2040 con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
2041 + con->request.true_http_10_client = 0;
2042 } else if (major_num == 1 && minor_num == 0) {
2043 con->request.http_version = HTTP_VERSION_1_0;
2044 + con->request.true_http_10_client = 1;
2046 con->http_status = 505;
2048 diff -Naur lighttpd-1.4.19/src/response.c lighttpd-1.4.19.mod_deflate.jz/src/response.c
2049 --- lighttpd-1.4.19/src/response.c
2050 +++ lighttpd-1.4.19.mod_deflate.jz/src/response.c
2053 int have_server = 0;
2055 - b = chunkqueue_get_prepend_buffer(con->write_queue);
2056 + b = chunkqueue_get_prepend_buffer(con->output_queue);
2058 if (con->request.http_version == HTTP_VERSION_1_1) {
2059 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
2063 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
2064 +/* if (!(con->parsed_response & HTTP_TRANSFER_ENCODING_CHUNKED) &&
2065 + (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED)) { */
2066 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
2070 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
2071 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
2073 + /* remove Transfer-Encoding: chunked header when HTTP 1.0
2074 + * or transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED == 0
2076 + if ( (con->request.http_version == HTTP_VERSION_1_0 ||
2077 + !(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED)) &&
2078 + 0 == strncasecmp(ds->value->ptr, "chunked", sizeof("chunked")-1) &&
2079 + 0 == strncasecmp(ds->key->ptr, "Transfer-Encoding", sizeof("Transfer-Encoding") - 1)) {
2083 BUFFER_APPEND_STRING_CONST(b, "\r\n");
2084 buffer_append_string_buffer(b, ds->key);
2085 BUFFER_APPEND_STRING_CONST(b, ": ");
2089 if (slash) pathinfo = slash;
2090 - } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));
2091 + } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > con->physical.basedir->used - 2));
2094 /* no it really doesn't exists */
2095 diff -Naur lighttpd-1.4.19/src/server.c lighttpd-1.4.19.mod_deflate.jz/src/server.c
2096 --- lighttpd-1.4.19/src/server.c
2097 +++ lighttpd-1.4.19.mod_deflate.jz/src/server.c
2099 srv->joblist = calloc(1, sizeof(*srv->joblist));
2100 assert(srv->joblist);
2102 + srv->joblist_prev = calloc(1, sizeof(*srv->joblist));
2103 + assert(srv->joblist_prev);
2105 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
2106 assert(srv->fdwaitqueue);
2111 joblist_free(srv, srv->joblist);
2112 + joblist_free(srv, srv->joblist_prev);
2113 fdwaitqueue_free(srv, srv->fdwaitqueue);
2115 if (srv->stat_cache) {
2116 @@ -1137,6 +1141,7 @@
2118 while (!srv_shutdown) {
2124 @@ -1388,7 +1393,12 @@
2128 - if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
2129 + if(srv->joblist->used > 0) {
2134 + if ((n = fdevent_poll(srv->ev, timeout)) > 0) {
2135 /* n is the number of events */
2138 @@ -1436,10 +1446,16 @@
2142 - for (ndx = 0; ndx < srv->joblist->used; ndx++) {
2143 - connection *con = srv->joblist->ptr[ndx];
2144 + if(srv->joblist->used > 0) {
2145 + connections *joblist = srv->joblist;
2146 + /* switch joblist queues. */
2147 + srv->joblist = srv->joblist_prev;
2148 + srv->joblist_prev = joblist;
2149 + for (ndx = 0; ndx < joblist->used; ndx++) {
2150 + connection *con = joblist->ptr[ndx];
2153 + con->in_joblist = 0;
2154 connection_state_machine(srv, con);
2156 switch(r = plugins_call_handle_joblist(srv, con)) {
2157 @@ -1450,11 +1466,9 @@
2158 log_error_write(srv, __FILE__, __LINE__, "d", r);
2162 - con->in_joblist = 0;
2165 - srv->joblist->used = 0;
2166 + joblist->used = 0;
2170 if (srv->srvconf.pid_file->used &&