]> git.pld-linux.org Git - packages/lighttpd.git/blame - lighttpd-mod_deflate.patch
no dist-xz for ac
[packages/lighttpd.git] / lighttpd-mod_deflate.patch
CommitLineData
ba805dd8
ER
1diff -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
4@@ -558,7 +558,7 @@
5 AC_OUTPUT
3572bf55 6
3572bf55 7
ba805dd8
ER
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"
10
11 plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
12 features="regex-conditionals"
13diff -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
16@@ -149,6 +149,7 @@
17
18 http_method_t http_method;
19 http_version_t http_version;
20+ int true_http_10_client;
21
22 buffer *request_line;
23
24@@ -360,8 +361,10 @@
25
3572bf55
SP
26 int file_started;
27 int file_finished;
28+ int end_chunk; /* used for chunked transfer encoding. */
ba805dd8 29
3572bf55
SP
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 ]*/
ba805dd8
ER
35
36@@ -596,6 +599,7 @@
37
3572bf55
SP
38 connections *conns;
39 connections *joblist;
40+ connections *joblist_prev;
41 connections *fdwaitqueue;
ba805dd8 42
3572bf55 43 stat_cache *stat_cache;
ba805dd8
ER
44diff -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
47@@ -16,7 +16,9 @@
48 #include <errno.h>
49 #include <string.h>
50
51+#include "server.h"
52 #include "chunk.h"
53+#include "log.h"
54
55 chunkqueue *chunkqueue_init(void) {
56 chunkqueue *cq;
57@@ -241,6 +243,16 @@
3572bf55
SP
58 return 0;
59 }
60
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;
65+ src->first = NULL;
66+ src->last = NULL;
67+
68+ return 0;
69+}
70+
71 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
72 chunk *c;
3572bf55 73
ba805dd8
ER
74@@ -400,3 +412,105 @@
75
76 return 0;
77 }
78+
3572bf55
SP
79+/**
80+ * the HTTP chunk-API
81+ *
82+ *
83+ */
84+
3572bf55
SP
85+static int chunk_encode_append_len(chunkqueue *cq, size_t len) {
86+ size_t i, olen = len, j;
87+ buffer *b;
88+
89+ /*b = srv->tmp_chunk_len;*/
90+ /*b = buffer_init();*/
91+ b = chunkqueue_get_append_buffer(cq);
92+
93+ if (len == 0) {
94+ buffer_copy_string(b, "0");
95+ } else {
96+ for (i = 0; i < 8 && len; i++) {
97+ len >>= 4;
98+ }
99+
100+ /* i is the number of hex digits we have */
101+ buffer_prepare_copy(b, i + 1);
102+
103+ for (j = i-1, len = olen; j+1 > 0; j--) {
104+ b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
105+ len >>= 4;
106+ }
107+ b->used = i;
108+ b->ptr[b->used++] = '\0';
109+ }
110+
111+ buffer_append_string(b, "\r\n");
112+ /*
113+ chunkqueue_append_buffer(cq, b);
114+ buffer_free(b);
115+ */
116+
117+ return 0;
118+}
119+
120+
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;
124+
125+ chunk_encode_append_len(cq, len);
126+
127+ chunkqueue_append_file(cq, fn, offset, len);
128+
129+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
130+
131+ return 0;
132+}
133+
134+int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem) {
135+ if (!cq) return -1;
136+ if (mem->used <= 1) return 0;
137+
138+ chunk_encode_append_len(cq, mem->used - 1);
139+
140+ chunkqueue_append_buffer(cq, mem);
141+
142+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
143+
144+ return 0;
145+}
146+
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;
150+
151+ chunk_encode_append_len(cq, len - 1);
152+
153+ chunkqueue_append_mem(cq, mem, len);
154+
155+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
156+
157+ return 0;
158+}
159+
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;
164+
165+ chunk_encode_append_len(cq, len);
166+
167+ chunkqueue_append_chunkqueue(cq, src);
168+
169+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
170+
171+ return 0;
172+}
173+
174+int chunk_encode_end(chunkqueue *cq) {
175+ chunk_encode_append_len(cq, 0);
176+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
177+ return 0;
178+}
179+
ba805dd8
ER
180diff -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
183@@ -52,6 +52,7 @@
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);
189
190 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
191@@ -67,4 +68,10 @@
192
193 int chunkqueue_is_empty(chunkqueue *c);
194
3572bf55
SP
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);
200+
ba805dd8
ER
201 #endif
202diff -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
3572bf55
SP
205@@ -18,6 +18,7 @@
206 #include "response.h"
207 #include "network.h"
208 #include "http_chunk.h"
ba805dd8 209+#include "chunk.h"
3572bf55
SP
210 #include "stat_cache.h"
211 #include "joblist.h"
212
213@@ -146,6 +147,12 @@
214 return 0;
215 }
216
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;
220+ return 1;
221+}
222+
223 #if 0
224 static void dump_packet(const unsigned char *data, size_t len) {
225 size_t i, j;
ba805dd8 226@@ -405,6 +412,7 @@
3572bf55
SP
227 con->file_finished = 1;
228
229 chunkqueue_reset(con->write_queue);
230+ chunkqueue_reset(con->output_queue);
231 }
232 break;
233 default:
ba805dd8 234@@ -517,12 +525,27 @@
3572bf55
SP
235 /* disable chunked encoding again as we have no body */
236 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
ba805dd8 237 con->parsed_response &= ~HTTP_CONTENT_LENGTH;
3572bf55
SP
238 chunkqueue_reset(con->write_queue);
239+ chunkqueue_reset(con->output_queue);
ba805dd8 240
3572bf55
SP
241 con->file_finished = 1;
242 break;
243 }
3572bf55
SP
244
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 */
250+ break;
251+ default:
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);
256+ break;
257+ }
258+
259 if (con->file_finished) {
ba805dd8
ER
260 /* we have all the content and chunked encoding is not used, set a content-length */
261
262@@ -592,8 +615,9 @@
263 * without the content
264 */
265 con->file_finished = 1;
266
3572bf55
SP
267 chunkqueue_reset(con->write_queue);
268+ chunkqueue_reset(con->output_queue);
ba805dd8 269 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
3572bf55
SP
270 }
271
ba805dd8 272@@ -603,11 +627,57 @@
3572bf55
SP
273 }
274
275 static int connection_handle_write(server *srv, connection *con) {
276- switch(network_write_chunkqueue(srv, con, con->write_queue)) {
277+ int finished = 0;
278+ int len;
279+
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 */
285+ break;
286+ case HANDLER_COMEBACK:
287+ /* response filter has more work */
288+ finished = 0;
289+ break;
290+ case HANDLER_FINISHED:
291+ /* response filter is finished */
292+ finished = 1;
293+ break;
294+ default:
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);
299+ finished = 1;
300+ break;
301+ }
302+
303+ /* move chunks from write_queue to output_queue. */
304+ if (con->request.http_method == HTTP_METHOD_HEAD) {
305+ chunkqueue_reset(con->write_queue);
306+ } else {
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);
313+ }
314+ } else {
315+ chunkqueue_append_chunkqueue(con->output_queue, con->write_queue);
316+ }
317+ con->write_queue->bytes_out += len;
318+ }
319+ /* write chunks from output_queue to network */
320+ switch(network_write_chunkqueue(srv, con, con->output_queue)) {
321 case 0:
322- if (con->file_finished) {
323+ if (finished) {
324 connection_set_state(srv, con, CON_STATE_RESPONSE_END);
325 joblist_append(srv, con);
326+ } else {
327+ /* not finished yet -> WRITE */
328+ con->is_writable = 1;
329 }
330 break;
331 case -1: /* error on our side */
ba805dd8
ER
332@@ -678,6 +747,7 @@
333
3572bf55
SP
334 #undef CLEAN
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);
ba805dd8 340@@ -705,6 +776,7 @@
3572bf55 341 connection_reset(srv, con);
ba805dd8 342
3572bf55
SP
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);
ba805dd8 348@@ -759,7 +831,10 @@
3572bf55
SP
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;
ba805dd8
ER
354+// con->use_cache_file = 0;
355+// con->write_cache_file = 0;
356
3572bf55 357 con->parsed_response = 0;
ba805dd8
ER
358
359@@ -829,6 +904,7 @@
3572bf55 360 array_reset(con->environment);
ba805dd8 361
3572bf55
SP
362 chunkqueue_reset(con->write_queue);
363+ chunkqueue_reset(con->output_queue);
364 chunkqueue_reset(con->request_content_queue);
365
ba805dd8
ER
366 /* the plugins should cleanup themself */
367@@ -1223,7 +1299,6 @@
3572bf55 368 }
ba805dd8 369
3572bf55
SP
370 if (con->state == CON_STATE_WRITE &&
371- !chunkqueue_is_empty(con->write_queue) &&
372 con->is_writable) {
ba805dd8 373
3572bf55 374 if (-1 == connection_handle_write(srv, con)) {
ba805dd8 375@@ -1640,15 +1715,15 @@
3572bf55 376 }
ba805dd8 377
3572bf55
SP
378 /* only try to write if we have something in the queue */
379- if (!chunkqueue_is_empty(con->write_queue)) {
380 #if 0
381+ if (!connection_queue_is_empty(con)) {
382 log_error_write(srv, __FILE__, __LINE__, "dsd",
383 con->fd,
384 "packets to write:",
385- con->write_queue->used);
386-#endif
387+ con->output_queue->used);
388 }
389- if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
390+#endif
391+ if (con->is_writable) {
392 if (-1 == connection_handle_write(srv, con)) {
393 log_error_write(srv, __FILE__, __LINE__, "ds",
394 con->fd,
ba805dd8 395@@ -1758,9 +1833,9 @@
3572bf55 396 * - if we have data to write
ba805dd8 397 * - if the socket is not writable yet
3572bf55 398 */
ba805dd8 399- if (!chunkqueue_is_empty(con->write_queue) &&
3572bf55
SP
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);
406 } else {
407 fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
ba805dd8
ER
408diff -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
3572bf55 411@@ -58,16 +58,9 @@
ba805dd8 412
3572bf55 413 cq = con->write_queue;
ba805dd8 414
3572bf55
SP
415- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
416- http_chunk_append_len(srv, con, len);
417- }
ba805dd8 418
3572bf55 419 chunkqueue_append_file(cq, fn, offset, len);
ba805dd8 420
3572bf55
SP
421- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
422- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
423- }
ba805dd8 424-
3572bf55
SP
425 return 0;
426 }
427
428@@ -78,16 +71,9 @@
ba805dd8 429
3572bf55 430 cq = con->write_queue;
ba805dd8 431
3572bf55
SP
432- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
433- http_chunk_append_len(srv, con, mem->used - 1);
434- }
ba805dd8 435
3572bf55 436 chunkqueue_append_buffer(cq, mem);
ba805dd8 437
3572bf55
SP
438- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
439- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
440- }
ba805dd8 441-
3572bf55
SP
442 return 0;
443 }
444
ba805dd8 445@@ -99,24 +85,11 @@
3572bf55 446 cq = con->write_queue;
ba805dd8 447
3572bf55
SP
448 if (len == 0) {
449- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
ba805dd8 450- chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1);
3572bf55
SP
451- } else {
452- chunkqueue_append_mem(cq, "", 1);
453- }
454 return 0;
455 }
ba805dd8 456
3572bf55
SP
457- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
458- http_chunk_append_len(srv, con, len - 1);
459- }
ba805dd8 460-
3572bf55 461 chunkqueue_append_mem(cq, mem, len);
ba805dd8 462
3572bf55
SP
463- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
464- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
465- }
ba805dd8 466-
3572bf55
SP
467 return 0;
468 }
469
ba805dd8
ER
470diff -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
3572bf55
SP
473@@ -7,6 +7,7 @@
474
475 int joblist_append(server *srv, connection *con) {
476 if (con->in_joblist) return 0;
477+ con->in_joblist = 1;
ba805dd8 478
3572bf55
SP
479 if (srv->joblist->size == 0) {
480 srv->joblist->size = 16;
ba805dd8
ER
481diff -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
484@@ -241,6 +241,11 @@
485 mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
486 mod_accesslog_la_LIBADD = $(common_libadd)
487
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)
492+
493
494 hdr = server.h buffer.h network.h log.h keyvalue.h \
495 response.h request.h fastcgi.h chunk.h \
496diff -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
499@@ -158,8 +158,15 @@
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
515@@ -399,6 +404,7 @@
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) \
523@@ -614,7 +619,7 @@
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
532@@ -721,6 +726,9 @@
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 \
542@@ -832,6 +840,8 @@
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@
559diff -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
562@@ -0,0 +1,1420 @@
9ff48f50 563+/* bug fix on Robert Jakabosky from alphatrade.com's lighttp 1.4.10 mod_deflate patch
ba805dd8
ER
564+ *
565+ * new module option:
566+ * deflate.nocompress-url = "^/nocompressurl/" # pcre regex which don't compress
567+ *
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)
572+ *
573+ * deflate.sync-flush = "enable" is buggy on chunk encoding transfer. Use it carefully,
574+ */
3572bf55
SP
575+#include <sys/types.h>
576+#include <sys/stat.h>
577+
578+#include <fcntl.h>
579+#include <unistd.h>
580+#include <ctype.h>
581+#include <stdlib.h>
582+#include <string.h>
583+#include <errno.h>
584+#include <time.h>
585+#include <assert.h>
586+
ba805dd8
ER
587+#if defined(HAVE_PCRE_H)
588+#include <pcre.h>
589+#endif
590+
3572bf55
SP
591+#include "base.h"
592+#include "log.h"
593+#include "buffer.h"
594+#include "response.h"
595+#include "joblist.h"
596+#include "stat_cache.h"
597+
598+#include "plugin.h"
599+
600+#include "crc32.h"
601+#include "etag.h"
ba805dd8 602+#include "inet_ntop_cache.h"
3572bf55
SP
603+
604+#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
605+# define USE_ZLIB
606+# include <zlib.h>
607+#else
608+# define Z_DEFAULT_COMPRESSION 1
609+#endif
610+
611+#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
612+# define USE_BZ2LIB
613+/* we don't need stdio interface */
614+# define BZ_NO_STDIO
615+# include <bzlib.h>
616+#endif
617+
618+#include "sys-mmap.h"
619+
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)
626+
627+#define KByte * 1024
628+#define MByte * 1024 KByte
629+#define GByte * 1024 MByte
630+
631+typedef struct {
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;
639+ short mem_level;
640+ short compression_level;
641+ short window_size;
642+ array *mimetypes;
ba805dd8
ER
643+ buffer *nocompress_url;
644+#if defined(HAVE_PCRE_H)
645+ pcre *nocompress_regex;
646+#endif
3572bf55
SP
647+} plugin_config;
648+
649+typedef struct {
650+ PLUGIN_DATA;
651+ buffer *tmp_buf;
652+
653+ plugin_config **config_storage;
654+ plugin_config conf;
655+} plugin_data;
656+
657+typedef struct {
658+ int bytes_in;
659+ int bytes_out;
660+ chunkqueue *in_queue;
661+ buffer *output;
662+ /* compression type & state */
663+ int compression_type;
664+ int stream_open;
665+#ifdef USE_ZLIB
666+ unsigned long crc;
667+ z_stream z;
668+ unsigned short gzip_header;
669+#endif
670+#ifdef USE_BZ2LIB
671+ bz_stream bz;
672+#endif
673+ plugin_data *plugin_data;
674+} handler_ctx;
675+
676+static handler_ctx *handler_ctx_init() {
677+ handler_ctx *hctx;
678+
679+ hctx = calloc(1, sizeof(*hctx));
680+ hctx->in_queue = chunkqueue_init();
681+
682+ return hctx;
683+}
684+
685+static void handler_ctx_free(handler_ctx *hctx) {
686+ chunkqueue_free(hctx->in_queue);
687+ free(hctx);
688+}
689+
690+INIT_FUNC(mod_deflate_init) {
691+ plugin_data *p;
692+
693+ p = calloc(1, sizeof(*p));
694+
695+ p->tmp_buf = buffer_init();
696+
697+ return p;
698+}
699+
700+FREE_FUNC(mod_deflate_free) {
701+ plugin_data *p = p_d;
702+
703+ UNUSED(srv);
704+
705+ if (!p) return HANDLER_GO_ON;
706+
707+ if (p->config_storage) {
708+ size_t i;
709+ for (i = 0; i < srv->config_context->used; i++) {
710+ plugin_config *s = p->config_storage[i];
711+
712+ if (!s) continue;
713+
714+ array_free(s->mimetypes);
ba805dd8
ER
715+ buffer_free(s->nocompress_url);
716+#if defined(HAVE_PCRE_H)
717+ if (s->nocompress_regex) pcre_free(s->nocompress_regex);
718+#endif
3572bf55
SP
719+ free(s);
720+ }
721+ free(p->config_storage);
722+ }
723+
724+ buffer_free(p->tmp_buf);
725+
726+ free(p);
727+
728+ return HANDLER_GO_ON;
729+}
730+
731+SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
732+ plugin_data *p = p_d;
733+ size_t i = 0;
734+
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 },
ba805dd8 747+ { "deflate.nocompress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
3572bf55
SP
748+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
749+ };
750+
751+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
752+
753+ for (i = 0; i < srv->config_context->used; i++) {
754+ plugin_config *s;
ba805dd8
ER
755+#if defined(HAVE_PCRE_H)
756+ const char *errptr;
757+ int erroff;
758+#endif
3572bf55
SP
759+
760+ s = calloc(1, sizeof(plugin_config));
761+ s->enabled = 1;
762+ s->bzip2 = 1;
763+ s->sync_flush = 0;
764+ s->debug = 0;
765+ s->output_buffer_size = 0;
766+ s->mem_level = 9;
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();
ba805dd8
ER
772+ s->nocompress_url = buffer_init();
773+#if defined(HAVE_PCRE_H)
774+ s->nocompress_regex = NULL;
775+#endif
3572bf55
SP
776+
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);
ba805dd8 788+ cv[11].destination = s->nocompress_url;
3572bf55
SP
789+
790+ p->config_storage[i] = s;
791+
792+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
793+ return HANDLER_ERROR;
794+ }
795+
ba805dd8
ER
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))) {
800+
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;
805+ }
806+ }
807+#endif
3572bf55
SP
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;
813+ }
814+
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;
819+ }
820+
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;
825+ }
826+ s->window_size = 0 - s->window_size;
827+
828+ if(s->sync_flush) {
829+ s->output_buffer_size = 0;
830+ }
831+ }
832+
833+ return HANDLER_GO_ON;
834+
835+}
836+
837+#ifdef USE_ZLIB
838+/* Copied gzip_header from apache 2.2's mod_deflate.c */
839+/* RFC 1952 Section 2.3 defines the gzip header:
840+ *
841+ * +---+---+---+---+---+---+---+---+---+---+
842+ * |ID1|ID2|CM |FLG| MTIME |XFL|OS |
843+ * +---+---+---+---+---+---+---+---+---+---+
844+ */
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 */
849+};
850+static int stream_deflate_init(server *srv, connection *con, handler_ctx *hctx) {
851+ plugin_data *p = hctx->plugin_data;
852+ z_stream *z;
853+
854+ UNUSED(srv);
855+ UNUSED(con);
856+
857+ z = &(hctx->z);
858+ z->zalloc = Z_NULL;
859+ z->zfree = Z_NULL;
860+ z->opaque = Z_NULL;
861+ z->total_in = 0;
862+ z->total_out = 0;
863+ z->next_out = NULL;
864+ z->avail_out = 0;
865+
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);
879+ }
880+ if (Z_OK != deflateInit2(z,
881+ p->conf.compression_level,
882+ Z_DEFLATED,
883+ p->conf.window_size, /* supress zlib-header */
884+ p->conf.mem_level,
885+ Z_DEFAULT_STRATEGY)) {
886+ return -1;
887+ }
888+ hctx->stream_open = 1;
889+
890+ return 0;
891+}
892+
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;
895+ z_stream *z;
896+ int len;
897+ int in = 0, out = 0;
898+
899+ UNUSED(srv);
900+ z = &(hctx->z);
901+
902+ if(z->next_out == NULL) {
903+ z->next_out = (unsigned char *)hctx->output->ptr;
904+ z->avail_out = hctx->output->size;
905+ }
906+
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));
915+ }
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);
920+ }
921+ hctx->crc = crc32(hctx->crc, start, st_size);
922+ }
923+
924+ z->next_in = start;
925+ z->avail_in = st_size;
926+ hctx->bytes_in += st_size;
927+
928+ /* compress data */
929+ in = z->avail_in;
930+ do {
931+ if (Z_OK != deflate(z, Z_NO_FLUSH)) {
932+ deflateEnd(z);
933+ hctx->stream_open = 0;
934+ return -1;
935+ }
936+
937+ if(z->avail_out == 0 || z->avail_in > 0) {
938+ len = hctx->output->size - z->avail_out;
939+ hctx->bytes_out += len;
940+ 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;
944+ }
945+ } while (z->avail_in > 0);
ba805dd8 946+
3572bf55
SP
947+ if(p->conf.debug) {
948+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
949+ "compress: in=", in, ", out=", out);
950+ }
951+ return 0;
952+}
953+
954+static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
955+ plugin_data *p = hctx->plugin_data;
956+ z_stream *z;
957+ int len;
958+ int rc = 0;
959+ int done;
960+ int flush = 1;
961+ int in = 0, out = 0;
962+
963+ UNUSED(srv);
964+
965+ z = &(hctx->z);
966+
967+ if(z->next_out == NULL) {
968+ z->next_out = (unsigned char *)hctx->output->ptr;
969+ z->avail_out = hctx->output->size;
970+ }
971+ /* compress data */
972+ in = z->avail_in;
973+ do {
974+ done = 1;
975+ if(end) {
976+ rc = deflate(z, Z_FINISH);
977+ if (rc == Z_OK) {
978+ done = 0;
979+ } else if (rc != Z_STREAM_END) {
980+ deflateEnd(z);
981+ hctx->stream_open = 0;
982+ return -1;
983+ }
984+ } else {
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);
990+ } else {
991+ if(p->conf.output_buffer_size > 0) flush = 0;
992+ rc = Z_OK;
993+ }
994+ if (rc != Z_OK) {
995+ deflateEnd(z);
996+ hctx->stream_open = 0;
997+ return -1;
998+ }
999+ }
1000+
1001+ len = hctx->output->size - z->avail_out;
1002+ if(z->avail_out == 0 || (flush && len > 0)) {
1003+ hctx->bytes_out += len;
1004+ 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;
1008+ }
1009+ } while (z->avail_in != 0 || !done);
ba805dd8
ER
1010+
1011+
3572bf55
SP
1012+ if(p->conf.debug) {
1013+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
1014+ "flush: in=", in, ", out=", out);
1015+ }
1016+ if(p->conf.sync_flush) {
1017+ z->next_out = NULL;
1018+ z->avail_out = 0;
1019+ }
1020+ return 0;
1021+}
1022+
1023+static int stream_deflate_end(server *srv, connection *con, handler_ctx *hctx) {
1024+ plugin_data *p = hctx->plugin_data;
1025+ z_stream *z;
1026+ int rc;
1027+
1028+ UNUSED(srv);
1029+
1030+ z = &(hctx->z);
1031+ if(!hctx->stream_open) return 0;
1032+ hctx->stream_open = 0;
1033+
1034+ if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP && hctx->bytes_out > 0 &&
ba805dd8 1035+ (unsigned int )hctx->bytes_out >= sizeof(gzip_header)) {
3572bf55
SP
1036+ /* write gzip footer */
1037+ unsigned char c[8];
1038+
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);
1053+ }
1054+ }
1055+
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);
1061+ } else {
1062+ log_error_write(srv, __FILE__, __LINE__, "sd",
1063+ "deflateEnd error ret=", rc);
1064+ }
1065+ return -1;
1066+ }
1067+ return 0;
1068+}
1069+
1070+#endif
1071+
1072+#ifdef USE_BZ2LIB
1073+static int stream_bzip2_init(server *srv, connection *con, handler_ctx *hctx) {
1074+ plugin_data *p = hctx->plugin_data;
1075+ bz_stream *bz;
1076+
1077+ UNUSED(srv);
1078+ UNUSED(con);
1079+
1080+ bz = &(hctx->bz);
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;
1088+
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);
1102+ }
1103+ if (BZ_OK != BZ2_bzCompressInit(bz,
1104+ p->conf.compression_level, /* blocksize = 900k */
1105+ 0, /* no output */
1106+ 30)) { /* workFactor: default */
1107+ return -1;
1108+ }
1109+ hctx->stream_open = 1;
1110+
1111+ return 0;
1112+}
1113+
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;
1116+ bz_stream *bz;
1117+ int len;
1118+ int rc;
1119+ int in = 0, out = 0;
1120+
1121+ UNUSED(srv);
1122+
1123+ bz = &(hctx->bz);
1124+
1125+ if(bz->next_out == NULL) {
1126+ bz->next_out = hctx->output->ptr;
1127+ bz->avail_out = hctx->output->size;
1128+ }
1129+
1130+ bz->next_in = (char *)start;
1131+ bz->avail_in = st_size;
1132+ hctx->bytes_in += st_size;
1133+
1134+ /* compress data */
1135+ in = bz->avail_in;
1136+ do {
1137+ rc = BZ2_bzCompress(bz, BZ_RUN);
1138+ if (rc != BZ_RUN_OK) {
1139+ BZ2_bzCompressEnd(bz);
1140+ hctx->stream_open = 0;
1141+ return -1;
1142+ }
1143+
1144+ if(bz->avail_out == 0 || bz->avail_in > 0) {
1145+ len = hctx->output->size - bz->avail_out;
1146+ hctx->bytes_out += len;
1147+ 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;
1151+ }
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);
1156+ }
1157+ return 0;
1158+}
1159+
1160+static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
1161+ plugin_data *p = hctx->plugin_data;
1162+ bz_stream *bz;
1163+ int len;
1164+ int rc;
1165+ int done;
1166+ int flush = 1;
1167+ int in = 0, out = 0;
1168+
1169+ UNUSED(srv);
1170+
1171+ bz = &(hctx->bz);
1172+
1173+ if(bz->next_out == NULL) {
1174+ bz->next_out = hctx->output->ptr;
1175+ bz->avail_out = hctx->output->size;
1176+ }
1177+ /* compress data */
1178+ in = bz->avail_in;
1179+ do {
1180+ done = 1;
1181+ if(end) {
1182+ rc = BZ2_bzCompress(bz, BZ_FINISH);
1183+ if (rc == BZ_FINISH_OK) {
1184+ done = 0;
1185+ } else if (rc != BZ_STREAM_END) {
1186+ BZ2_bzCompressEnd(bz);
1187+ hctx->stream_open = 0;
1188+ return -1;
1189+ }
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;
1195+ return -1;
1196+ }
1197+ if(p->conf.output_buffer_size > 0) flush = 0;
1198+ }
1199+
1200+ len = hctx->output->size - bz->avail_out;
1201+ if(bz->avail_out == 0 || (flush && len > 0)) {
1202+ hctx->bytes_out += len;
1203+ 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;
1207+ }
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);
1212+ }
1213+ if(p->conf.sync_flush) {
1214+ bz->next_out = NULL;
1215+ bz->avail_out = 0;
1216+ }
1217+ return 0;
1218+}
1219+
1220+static int stream_bzip2_end(server *srv, connection *con, handler_ctx *hctx) {
1221+ plugin_data *p = hctx->plugin_data;
1222+ bz_stream *bz;
1223+ int rc;
1224+
1225+ UNUSED(p);
1226+ UNUSED(con);
1227+
1228+ bz = &(hctx->bz);
1229+ if(!hctx->stream_open) return 0;
1230+ hctx->stream_open = 0;
1231+
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);
1236+ return -1;
1237+ }
1238+ return 0;
1239+}
1240+
1241+#endif
1242+
1243+static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
1244+ int ret = -1;
1245+ if(st_size == 0) return 0;
1246+ switch(hctx->compression_type) {
1247+#ifdef USE_ZLIB
1248+ case HTTP_ACCEPT_ENCODING_GZIP:
1249+ case HTTP_ACCEPT_ENCODING_DEFLATE:
1250+ ret = stream_deflate_compress(srv, con, hctx, start, st_size);
1251+ break;
1252+#endif
1253+#ifdef USE_BZ2LIB
1254+ case HTTP_ACCEPT_ENCODING_BZIP2:
1255+ ret = stream_bzip2_compress(srv, con, hctx, start, st_size);
1256+ break;
1257+#endif
1258+ default:
1259+ ret = -1;
1260+ break;
1261+ }
1262+
1263+ return ret;
1264+}
1265+
1266+static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
1267+ int ret = -1;
1268+ if(hctx->bytes_in == 0) return 0;
1269+ switch(hctx->compression_type) {
1270+#ifdef USE_ZLIB
1271+ case HTTP_ACCEPT_ENCODING_GZIP:
1272+ case HTTP_ACCEPT_ENCODING_DEFLATE:
1273+ ret = stream_deflate_flush(srv, con, hctx, end);
1274+ break;
1275+#endif
1276+#ifdef USE_BZ2LIB
1277+ case HTTP_ACCEPT_ENCODING_BZIP2:
1278+ ret = stream_bzip2_flush(srv, con, hctx, end);
1279+ break;
1280+#endif
1281+ default:
1282+ ret = -1;
1283+ break;
1284+ }
1285+
1286+ return ret;
1287+}
1288+
1289+static int mod_deflate_stream_end(server *srv, connection *con, handler_ctx *hctx) {
1290+ int ret = -1;
1291+ switch(hctx->compression_type) {
1292+#ifdef USE_ZLIB
1293+ case HTTP_ACCEPT_ENCODING_GZIP:
1294+ case HTTP_ACCEPT_ENCODING_DEFLATE:
1295+ ret = stream_deflate_end(srv, con, hctx);
1296+ break;
1297+#endif
1298+#ifdef USE_BZ2LIB
1299+ case HTTP_ACCEPT_ENCODING_BZIP2:
1300+ ret = stream_bzip2_end(srv, con, hctx);
1301+ break;
1302+#endif
1303+ default:
1304+ ret = -1;
1305+ break;
1306+ }
1307+
1308+ return ret;
1309+}
1310+
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;
1313+ off_t abs_offset;
1314+ off_t toSend;
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;
1319+
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);
1323+ return -1;
1324+ }
1325+
1326+ abs_offset = c->file.start + c->offset;
1327+
1328+ if (abs_offset > sce->st.st_size) {
1329+ log_error_write(srv, __FILE__, __LINE__, "sb",
1330+ "file was shrinked:", c->file.name);
1331+
1332+ return -1;
1333+ }
1334+
1335+ we_want_to_send = st_size;
1336+ /* mmap the buffer
1337+ * - first mmap
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)) {
1341+
1342+ /* Optimizations for the future:
1343+ *
1344+ * adaptive mem-mapping
1345+ * the problem:
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
1348+ * mmap() call.
1349+ * solution:
1350+ * only mmap 16M in one chunk and move the window as soon as we have finished
1351+ * the first 8M
1352+ *
1353+ * read-ahead buffering
1354+ * the problem:
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)
1358+ * 1. use madvise
1359+ * 2. use a internal read-ahead buffer in the chunk-structure
1360+ * 3. use non-blocking IO for file-transfers
1361+ * */
1362+
1363+ /* all mmap()ed areas are 512kb expect the last which might be smaller */
1364+ size_t to_mmap;
1365+
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;
1370+ } else {
1371+ /* in case the range-offset is after the first mmap()ed area we skip the area */
1372+ c->file.mmap.offset = 0;
1373+
1374+ while (c->file.mmap.offset + we_want_to_mmap < c->file.start) {
1375+ c->file.mmap.offset += we_want_to_mmap;
1376+ }
1377+ }
1378+
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;
1384+
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));
1388+
1389+ return -1;
1390+ }
1391+#ifdef FD_CLOEXEC
1392+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
1393+#endif
1394+ }
1395+
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 */
1398+
1399+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
1400+ strerror(errno), c->file.name, c->file.fd);
1401+
1402+ return -1;
1403+ }
1404+
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);
1408+#else
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);
1415+ }
1416+#endif
1417+#endif
1418+
1419+ /* chunk_reset() or chunk_free() will cleanup for us */
1420+ }
1421+
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;
1425+
1426+ if (toSend < 0) {
1427+ log_error_write(srv, __FILE__, __LINE__, "soooo",
1428+ "toSend is negative:",
1429+ toSend,
1430+ c->file.mmap.length,
1431+ abs_offset,
1432+ c->file.mmap.offset);
1433+ assert(toSend < 0);
1434+ }
1435+
1436+#ifdef LOCAL_BUFFERING
1437+ start = c->mem->ptr;
1438+#else
1439+ start = c->file.mmap.start;
1440+#endif
1441+
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);
1446+ }
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.");
1451+ return -1;
1452+ }
1453+
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;
1460+ }
1461+ }
1462+
1463+ return toSend;
1464+}
1465+
1466+static int deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) {
1467+ plugin_data *p = hctx->plugin_data;
1468+ int rc;
1469+
1470+ rc = mod_deflate_stream_end(srv, con, hctx);
1471+ if(rc < 0) {
1472+ log_error_write(srv, __FILE__, __LINE__, "s", "error closing stream");
1473+ }
ba805dd8
ER
1474+
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);
1478+ }
1479+
3572bf55
SP
1480+ if(p->conf.debug) {
1481+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
1482+ " in:", hctx->bytes_in,
1483+ " out:", hctx->bytes_out);
1484+ }
1485+
1486+ /* cleanup compression state */
1487+ if(hctx->output != p->tmp_buf) {
1488+ buffer_free(hctx->output);
1489+ }
1490+ handler_ctx_free(hctx);
1491+ con->plugin_ctx[p->id] = NULL;
1492+
1493+ return 0;
1494+}
1495+
ba805dd8 1496+static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx, int end) {
3572bf55
SP
1497+ plugin_data *p = hctx->plugin_data;
1498+ chunk *c;
1499+ size_t chunks_written = 0;
1500+ int chunk_finished = 0;
3572bf55 1501+ int rc=-1;
ba805dd8
ER
1502+ int close_stream = 0, len = 0;
1503+ unsigned int out = 0, max = 0;
3572bf55
SP
1504+
1505+ /* move all chunk from write_queue into our in_queue */
1506+ chunkqueue_append_chunkqueue(hctx->in_queue, con->write_queue);
1507+
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);
1512+ }
1513+ /* calculate max bytes to compress for this call. */
1514+ if(!end) {
1515+ max = p->conf.work_block_size * 1024;
1516+ if(max == 0 || max > len) max = len;
1517+ } else {
1518+ max = len;
1519+ }
1520+
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;
1524+ len = 0;
1525+
1526+ switch(c->type) {
1527+ case MEM_CHUNK:
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;
1534+ }
1535+ c->offset += len;
1536+ out += len;
1537+ if (c->offset == c->mem->used - 1) {
1538+ chunk_finished = 1;
1539+ chunks_written++;
1540+ }
1541+ break;
1542+ case FILE_CHUNK:
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;
1549+ }
1550+ out += len;
1551+ if (c->offset == c->file.length) {
1552+ chunk_finished = 1;
1553+ chunks_written++;
1554+ }
1555+ break;
1556+ default:
1557+
1558+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
1559+
1560+ return HANDLER_ERROR;
1561+ }
1562+ if(!chunk_finished) break;
1563+ }
1564+ if(p->conf.debug) {
1565+ log_error_write(srv, __FILE__, __LINE__, "sd",
1566+ "compressed bytes:", out);
1567+ }
1568+ hctx->in_queue->bytes_out += out;
1569+
1570+ if(chunks_written > 0) {
1571+ chunkqueue_remove_finished_chunks(hctx->in_queue);
1572+ }
1573+
1574+ close_stream = (con->file_finished && chunkqueue_is_empty(hctx->in_queue));
1575+ rc = mod_deflate_stream_flush(srv, con, hctx, close_stream);
1576+ if(rc < 0) {
1577+ log_error_write(srv, __FILE__, __LINE__, "s", "flush error");
1578+ }
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);
1584+ }
1585+ return HANDLER_FINISHED;
1586+ } else {
1587+ if(!chunkqueue_is_empty(hctx->in_queue)) {
1588+ /* We have more data to compress. */
1589+ joblist_append(srv, con);
1590+ }
1591+ return HANDLER_COMEBACK;
1592+ }
1593+}
1594+
1595+#define PATCH(x) \
1596+ p->conf.x = s->x;
1597+static int mod_deflate_patch_connection(server *srv, connection *con, plugin_data *p) {
1598+ size_t i, j;
1599+ plugin_config *s = p->config_storage[0];
1600+
1601+ PATCH(output_buffer_size);
1602+ PATCH(mimetypes);
1603+ PATCH(compression_level);
1604+ PATCH(mem_level);
1605+ PATCH(window_size);
1606+ PATCH(min_compress_size);
1607+ PATCH(work_block_size);
1608+ PATCH(enabled);
1609+ PATCH(debug);
1610+ PATCH(bzip2);
1611+ PATCH(sync_flush);
ba805dd8
ER
1612+#if defined(HAVE_PCRE_H)
1613+ PATCH(nocompress_regex);
1614+#endif
3572bf55
SP
1615+
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];
1620+
1621+ /* condition didn't match */
1622+ if (!config_check_cond(srv, con, dc)) continue;
1623+
1624+ /* merge config */
1625+ for (j = 0; j < dc->value->used; j++) {
1626+ data_unset *du = dc->value->data[j];
1627+
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"))) {
1631+ PATCH(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"))) {
1635+ PATCH(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"))) {
1643+ PATCH(enabled);
1644+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.debug"))) {
1645+ PATCH(debug);
1646+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.bzip2"))) {
1647+ PATCH(bzip2);
1648+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.sync-flush"))) {
1649+ PATCH(sync_flush);
ba805dd8
ER
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);
1653+#endif
3572bf55
SP
1654+ }
1655+ }
1656+ }
1657+
1658+ return 0;
1659+}
1660+#undef PATCH
1661+
1662+PHYSICALPATH_FUNC(mod_deflate_handle_response_start) {
1663+ plugin_data *p = p_d;
1664+ handler_ctx *hctx;
1665+ data_string *ds;
1666+ int accept_encoding = 0;
1667+ char *value;
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;
1674+ int file_len=0;
1675+ int rc=-2;
ba805dd8 1676+ int end = 0;
3572bf55 1677+ size_t m;
ba805dd8
ER
1678+#if defined(HAVE_PCRE_H)
1679+ int n;
1680+# define N 10
1681+ int ovec[N * 3];
1682+#endif
3572bf55
SP
1683+
1684+ /* disable compression for some http status types. */
1685+ switch(con->http_status) {
1686+ case 100:
1687+ case 101:
1688+ case 204:
1689+ case 205:
1690+ case 304:
1691+ /* disable compression as we have no response entity */
1692+ return HANDLER_GO_ON;
1693+ default:
1694+ break;
1695+ }
1696+
1697+ mod_deflate_patch_connection(srv, con, p);
1698+
1699+ /* is compression allowed */
1700+ if(!p->conf.enabled) {
1701+ if(p->conf.debug) {
1702+ log_error_write(srv, __FILE__, __LINE__, "s", "compression disabled.");
1703+ }
1704+ return HANDLER_GO_ON;
1705+ }
3572bf55 1706+
ba805dd8
ER
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;
1714+ }
1715+ } else {
1716+ if(p->conf.debug) {
1717+ log_error_write(srv, __FILE__, __LINE__, "sb", "no compress for url:", con->uri.path);
1718+ }
1719+ return HANDLER_GO_ON;
1720+ }
1721+ }
1722+#endif
3572bf55
SP
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;
1726+ }
1727+
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;
1731+ }
1732+
1733+ /* get client side support encodings */
1734+ value = ds->value->ptr;
1735+#ifdef USE_ZLIB
1736+ if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
1737+ if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
1738+#endif
1739+ /* if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; */
1740+#ifdef USE_BZ2LIB
1741+ if(p->conf.bzip2) {
1742+ if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
1743+ }
1744+#endif
1745+ if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
1746+
1747+ /* get server side supported ones */
1748+#ifdef USE_BZ2LIB
1749+ if(p->conf.bzip2) {
1750+ srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
1751+ }
1752+#endif
1753+#ifdef USE_ZLIB
1754+ srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
1755+ srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
1756+#endif
1757+
1758+ /* find matching encodings */
1759+ matched_encodings = accept_encoding & srv_encodings;
1760+ if (!matched_encodings) {
1761+ return HANDLER_GO_ON;
1762+ }
1763+
ba805dd8
ER
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
1767+ */
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;
1773+ }
3572bf55
SP
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;
1778+ } else {
1779+ file_len = 0;
1780+ }
ba805dd8 1781+
3572bf55
SP
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);
1786+ }
1787+ return HANDLER_GO_ON;
1788+ }
1789+
1790+ /* Check mimetype in response header "Content-Type" */
1791+ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
1792+ int found = 0;
1793+ if(p->conf.debug) {
1794+ log_error_write(srv, __FILE__, __LINE__, "sb",
1795+ "Content-Type:", ds->value);
1796+ }
1797+ for (m = 0; m < p->conf.mimetypes->used; m++) {
1798+ data_string *mimetype = (data_string *)p->conf.mimetypes->data[m];
1799+
1800+ if(p->conf.debug) {
1801+ log_error_write(srv, __FILE__, __LINE__, "sb",
1802+ "mime-type:", mimetype->value);
1803+ }
ba805dd8
ER
1804+ if (strncmp(mimetype->value->ptr, ds->value->ptr, mimetype->value->used-1) == 0) {
1805+/* if (buffer_is_equal(mimetype->value, ds->value)) { */
3572bf55
SP
1806+ /* mimetype found */
1807+ found = 1;
1808+ break;
1809+ }
1810+ }
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);
1815+ }
1816+ return HANDLER_GO_ON;
1817+ }
ba805dd8
ER
1818+#if 0
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
1822+ */
1823+ matched_encodings = HTTP_ACCEPT_ENCODING_DEFLATE;
1824+ }
1825+#endif
3572bf55
SP
1826+ }
1827+
1828+ if(p->conf.debug) {
ba805dd8
ER
1829+ log_error_write(srv, __FILE__, __LINE__, "sb",
1830+ "enable compression for ", con->uri.path);
3572bf55 1831+ }
ba805dd8
ER
1832+
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);
1841+ }
1842+ }
1843+ } else {
1844+ if (p->conf.debug) {
1845+ log_error_write(srv, __FILE__, __LINE__, "sb",
1846+ "add Vary: Accept-Encoding for ", con->uri.path);
1847+ }
1848+ response_header_insert(srv, con, CONST_STR_LEN("Vary"),
1849+ CONST_STR_LEN("Accept-Encoding"));
1850+ }
1851+
3572bf55
SP
1852+ /* enable compression */
1853+ hctx = handler_ctx_init();
1854+ hctx->plugin_data = p;
1855+
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);
1869+ }
1870+ if(rc == -1) {
1871+ log_error_write(srv, __FILE__, __LINE__, "s",
1872+ "Failed to initialize compression.");
1873+ }
ba805dd8 1874+
3572bf55
SP
1875+ if(rc < 0) {
1876+ handler_ctx_free(hctx);
1877+ return HANDLER_GO_ON;
1878+ }
1879+
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;
1884+ } else {
1885+ hctx->output = buffer_init();
1886+ buffer_prepare_copy(hctx->output, p->conf.output_buffer_size);
1887+ }
1888+ con->plugin_ctx[p->id] = hctx;
1889+
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));
1892+
ba805dd8
ER
1893+ if (con->file_finished) end = 1;
1894+
1895+ con->parsed_response &= ~(HTTP_CONTENT_LENGTH);
1896+#if 0
1897+ /* debug */
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");
1904+#endif
1905+
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);
3572bf55
SP
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);
1914+ }
ba805dd8 1915+ return deflate_compress_response(srv, con, hctx, end);
3572bf55 1916+ } else {
3572bf55 1917+ if (con->request.http_version == HTTP_VERSION_1_1) {
ba805dd8
ER
1918+ if (p->conf.debug)
1919+ log_error_write(srv, __FILE__, __LINE__, "sb",
1920+ "chunk transfer encoding for uri", con->uri.path);
3572bf55 1921+ /* Make sure to use chunked encoding. */
ba805dd8 1922+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
3572bf55 1923+ } else {
ba805dd8
ER
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. */
3572bf55 1928+ con->response.transfer_encoding = 0;
ba805dd8 1929+ con->parsed_response &= ~(HTTP_TRANSFER_ENCODING_CHUNKED);
3572bf55
SP
1930+ }
1931+ }
1932+
ba805dd8
ER
1933+ if (p->conf.debug)
1934+ log_error_write(srv, __FILE__, __LINE__, "sdsb", "end =", end, "for uri", con->uri.path);
1935+
1936+ deflate_compress_response(srv, con, hctx, end);
3572bf55
SP
1937+ return HANDLER_GO_ON;
1938+}
1939+
1940+JOBLIST_FUNC(mod_deflate_handle_response_filter) {
1941+ plugin_data *p = p_d;
1942+ handler_ctx *hctx = con->plugin_ctx[p->id];
1943+
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;
1947+
ba805dd8 1948+ return deflate_compress_response(srv, con, hctx, 0);
3572bf55
SP
1949+}
1950+
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];
1954+
1955+ if(hctx == NULL) return HANDLER_GO_ON;
1956+
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);
1960+ }
1961+
1962+ deflate_compress_cleanup(srv, con, hctx);
1963+
1964+ return HANDLER_GO_ON;
1965+}
1966+
1967+int mod_deflate_plugin_init(plugin *p) {
1968+ p->version = LIGHTTPD_VERSION_ID;
1969+ p->name = buffer_init_string("deflate");
1970+
ba805dd8
ER
1971+ p->init = mod_deflate_init;
1972+ p->cleanup = mod_deflate_free;
3572bf55 1973+ p->set_defaults = mod_deflate_setdefaults;
ba805dd8 1974+ p->connection_reset = mod_deflate_cleanup;
3572bf55 1975+ p->handle_connection_close = mod_deflate_cleanup;
ba805dd8
ER
1976+ p->handle_response_start = mod_deflate_handle_response_start;
1977+ p->handle_response_filter = mod_deflate_handle_response_filter;
3572bf55
SP
1978+
1979+ p->data = NULL;
1980+
1981+ return 0;
1982+}
ba805dd8
ER
1983diff -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
3572bf55
SP
1986@@ -40,6 +40,8 @@
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,
1995@@ -266,6 +268,8 @@
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)
2004@@ -395,6 +399,8 @@
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);
ba805dd8
ER
2013diff -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
3572bf55
SP
2016@@ -54,6 +54,8 @@
2017 * has to be found
2018 */
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); /* */
2023 void *data;
ba805dd8 2024
3572bf55
SP
2025@@ -68,6 +70,8 @@
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);
ba805dd8
ER
2034diff -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 @@
2038
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;
2045 } else {
2046 con->http_status = 505;
2047
2048diff -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
2051@@ -32,7 +32,7 @@
3572bf55
SP
2052 int have_date = 0;
2053 int have_server = 0;
ba805dd8 2054
3572bf55
SP
2055- b = chunkqueue_get_prepend_buffer(con->write_queue);
2056+ b = chunkqueue_get_prepend_buffer(con->output_queue);
ba805dd8 2057
3572bf55
SP
2058 if (con->request.http_version == HTTP_VERSION_1_1) {
2059 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
ba805dd8
ER
2060@@ -49,6 +49,8 @@
2061 }
2062
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");
2067 }
2068
2069@@ -65,6 +67,16 @@
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;
2072
2073+ /* remove Transfer-Encoding: chunked header when HTTP 1.0
2074+ * or transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED == 0
2075+ */
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)) {
2080+ continue ;
2081+ }
2082+
2083 BUFFER_APPEND_STRING_CONST(b, "\r\n");
2084 buffer_append_string_buffer(b, ds->key);
2085 BUFFER_APPEND_STRING_CONST(b, ": ");
2086@@ -576,7 +588,7 @@
2087 }
2088
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));
2092
2093 if (found == 0) {
2094 /* no it really doesn't exists */
2095diff -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
2098@@ -203,6 +203,9 @@
3572bf55
SP
2099 srv->joblist = calloc(1, sizeof(*srv->joblist));
2100 assert(srv->joblist);
ba805dd8 2101
3572bf55
SP
2102+ srv->joblist_prev = calloc(1, sizeof(*srv->joblist));
2103+ assert(srv->joblist_prev);
2104+
2105 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
2106 assert(srv->fdwaitqueue);
ba805dd8
ER
2107
2108@@ -294,6 +297,7 @@
3572bf55 2109 #undef CLEAN
ba805dd8 2110
3572bf55
SP
2111 joblist_free(srv, srv->joblist);
2112+ joblist_free(srv, srv->joblist_prev);
2113 fdwaitqueue_free(srv, srv->fdwaitqueue);
ba805dd8 2114
3572bf55 2115 if (srv->stat_cache) {
ba805dd8 2116@@ -1137,6 +1141,7 @@
3572bf55
SP
2117 /* main-loop */
2118 while (!srv_shutdown) {
2119 int n;
2120+ int timeout;
2121 size_t ndx;
2122 time_t min_ts;
ba805dd8
ER
2123
2124@@ -1388,7 +1393,12 @@
3572bf55
SP
2125 }
2126 }
2127
2128- if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
2129+ if(srv->joblist->used > 0) {
2130+ timeout = 500;
2131+ } else {
2132+ timeout = 1000;
2133+ }
2134+ if ((n = fdevent_poll(srv->ev, timeout)) > 0) {
2135 /* n is the number of events */
2136 int revents;
2137 int fd_ndx;
ba805dd8 2138@@ -1436,10 +1446,16 @@
3572bf55
SP
2139 strerror(errno));
2140 }
ba805dd8 2141
3572bf55
SP
2142- for (ndx = 0; ndx < srv->joblist->used; ndx++) {
2143- connection *con = srv->joblist->ptr[ndx];
3572bf55
SP
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];
ba805dd8
ER
2151 handler_t r;
2152
3572bf55 2153+ con->in_joblist = 0;
ba805dd8
ER
2154 connection_state_machine(srv, con);
2155
2156 switch(r = plugins_call_handle_joblist(srv, con)) {
2157@@ -1450,11 +1466,9 @@
2158 log_error_write(srv, __FILE__, __LINE__, "d", r);
2159 break;
3572bf55 2160 }
ba805dd8 2161-
3572bf55 2162- con->in_joblist = 0;
3572bf55 2163 }
ba805dd8 2164-
3572bf55 2165- srv->joblist->used = 0;
ba805dd8
ER
2166+ joblist->used = 0;
2167+ }
3572bf55 2168 }
ba805dd8 2169
3572bf55 2170 if (srv->srvconf.pid_file->used &&
This page took 0.509815 seconds and 4 git commands to generate.