]> git.pld-linux.org Git - packages/lighttpd.git/blame - lighttpd-mod_deflate.patch
- update to r2199:
[packages/lighttpd.git] / lighttpd-mod_deflate.patch
CommitLineData
3572bf55
SP
1diff -Naur lighttpd-1.4.10.orig/src/Makefile.am lighttpd-1.4.10/src/Makefile.am
2--- lighttpd-1.4.10.orig/src/Makefile.am 2006-01-04 06:08:03.000000000 -0800
3+++ lighttpd-1.4.10/src/Makefile.am 2006-02-16 22:25:16.504347041 -0800
4@@ -28,7 +28,7 @@
5 mod_ssi_expr.c: mod_ssi_exprparser.h
6
7 common_src=buffer.c log.c \
8- keyvalue.c chunk.c \
9+ keyvalue.c chunk.c chunk_encode.c \
10 http_chunk.c stream.c fdevent.c \
11 stat_cache.c plugin.c joblist.c etag.c array.c \
12 data_string.c data_count.c data_array.c \
13@@ -222,9 +222,14 @@
14 mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
15 mod_accesslog_la_LIBADD = $(common_libadd)
16
17+lib_LTLIBRARIES += mod_deflate.la
18+mod_deflate_la_SOURCES = mod_deflate.c
19+mod_deflate_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
20+mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
21+
22
23 hdr = server.h buffer.h network.h log.h keyvalue.h \
24- response.h request.h fastcgi.h chunk.h \
25+ response.h request.h fastcgi.h chunk.h chunk_encode.h \
26 settings.h http_chunk.h http_auth_digest.h \
27 md5.h http_auth.h stream.h \
28 fdevent.h connections.h base.h stat_cache.h \
29diff -Naur lighttpd-1.4.10.orig/src/base.h lighttpd-1.4.10/src/base.h
30--- lighttpd-1.4.10.orig/src/base.h 2006-01-11 06:51:04.000000000 -0800
31+++ lighttpd-1.4.10/src/base.h 2006-02-16 22:25:16.504347041 -0800
32@@ -345,8 +345,10 @@
33
34 int file_started;
35 int file_finished;
36+ int end_chunk; /* used for chunked transfer encoding. */
37
38- chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
39+ chunkqueue *write_queue; /* a large queue for HTTP response content [ file, mem ] */
40+ chunkqueue *output_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
41 chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
42 chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
43
44@@ -570,6 +572,7 @@
45
46 connections *conns;
47 connections *joblist;
48+ connections *joblist_prev;
49 connections *fdwaitqueue;
50
51 stat_cache *stat_cache;
52diff -Naur lighttpd-1.4.10.orig/src/chunk.c lighttpd-1.4.10/src/chunk.c
53--- lighttpd-1.4.10.orig/src/chunk.c 2005-11-18 05:18:19.000000000 -0800
54+++ lighttpd-1.4.10/src/chunk.c 2006-02-16 22:25:16.505346873 -0800
55@@ -224,6 +224,16 @@
56 return 0;
57 }
58
59+int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src) {
60+ if(src == NULL) return 0;
61+ chunkqueue_append_chunk(cq, src->first);
62+ cq->last = src->last;
63+ src->first = NULL;
64+ src->last = NULL;
65+
66+ return 0;
67+}
68+
69 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
70 chunk *c;
71
72diff -Naur lighttpd-1.4.10.orig/src/chunk.h lighttpd-1.4.10/src/chunk.h
73--- lighttpd-1.4.10.orig/src/chunk.h 2005-10-31 23:32:21.000000000 -0800
74+++ lighttpd-1.4.10/src/chunk.h 2006-02-16 22:25:16.505346873 -0800
75@@ -51,6 +51,7 @@
76 int chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len);
77 int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len);
78 int chunkqueue_append_buffer(chunkqueue *c, buffer *mem);
79+int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src);
80 int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem);
81
82 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
83diff -Naur lighttpd-1.4.10.orig/src/chunk_encode.c lighttpd-1.4.10/src/chunk_encode.c
84--- lighttpd-1.4.10.orig/src/chunk_encode.c 1969-12-31 16:00:00.000000000 -0800
85+++ lighttpd-1.4.10/src/chunk_encode.c 2006-02-16 22:25:16.505346873 -0800
86@@ -0,0 +1,117 @@
87+/**
88+ * the HTTP chunk-API
89+ *
90+ *
91+ */
92+
93+#include <sys/types.h>
94+#include <sys/stat.h>
95+
96+#include <stdlib.h>
97+#include <fcntl.h>
98+#include <unistd.h>
99+
100+#include <stdio.h>
101+#include <errno.h>
102+#include <string.h>
103+
104+#include "server.h"
105+#include "chunk.h"
106+#include "chunk_encode.h"
107+#include "log.h"
108+
109+static int chunk_encode_append_len(chunkqueue *cq, size_t len) {
110+ size_t i, olen = len, j;
111+ buffer *b;
112+
113+ /*b = srv->tmp_chunk_len;*/
114+ /*b = buffer_init();*/
115+ b = chunkqueue_get_append_buffer(cq);
116+
117+ if (len == 0) {
118+ buffer_copy_string(b, "0");
119+ } else {
120+ for (i = 0; i < 8 && len; i++) {
121+ len >>= 4;
122+ }
123+
124+ /* i is the number of hex digits we have */
125+ buffer_prepare_copy(b, i + 1);
126+
127+ for (j = i-1, len = olen; j+1 > 0; j--) {
128+ b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
129+ len >>= 4;
130+ }
131+ b->used = i;
132+ b->ptr[b->used++] = '\0';
133+ }
134+
135+ buffer_append_string(b, "\r\n");
136+ /*
137+ chunkqueue_append_buffer(cq, b);
138+ buffer_free(b);
139+ */
140+
141+ return 0;
142+}
143+
144+
145+int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
146+ if (!cq) return -1;
147+ if (len == 0) return 0;
148+
149+ chunk_encode_append_len(cq, len);
150+
151+ chunkqueue_append_file(cq, fn, offset, len);
152+
153+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
154+
155+ return 0;
156+}
157+
158+int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem) {
159+ if (!cq) return -1;
160+ if (mem->used <= 1) return 0;
161+
162+ chunk_encode_append_len(cq, mem->used - 1);
163+
164+ chunkqueue_append_buffer(cq, mem);
165+
166+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
167+
168+ return 0;
169+}
170+
171+int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len) {
172+ if (!cq) return -1;
173+ if (len <= 1) return 0;
174+
175+ chunk_encode_append_len(cq, len - 1);
176+
177+ chunkqueue_append_mem(cq, mem, len);
178+
179+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
180+
181+ return 0;
182+}
183+
184+int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src) {
185+ int len = chunkqueue_length(src);
186+ if (!cq) return -1;
187+ if (len == 0) return 0;
188+
189+ chunk_encode_append_len(cq, len);
190+
191+ chunkqueue_append_chunkqueue(cq, src);
192+
193+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
194+
195+ return 0;
196+}
197+
198+int chunk_encode_end(chunkqueue *cq) {
199+ chunk_encode_append_len(cq, 0);
200+ chunkqueue_append_mem(cq, "\r\n", 2 + 1);
201+ return 0;
202+}
203+
204diff -Naur lighttpd-1.4.10.orig/src/chunk_encode.h lighttpd-1.4.10/src/chunk_encode.h
205--- lighttpd-1.4.10.orig/src/chunk_encode.h 1969-12-31 16:00:00.000000000 -0800
206+++ lighttpd-1.4.10/src/chunk_encode.h 2006-02-16 22:25:16.506346704 -0800
207@@ -0,0 +1,13 @@
208+#ifndef _CHUNK_ENCODE_H_
209+#define _CHUNK_ENCODE_H_
210+
211+#include "server.h"
212+#include <sys/types.h>
213+
214+int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len);
215+int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem);
216+int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len);
217+int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src);
218+int chunk_encode_end(chunkqueue *cq);
219+
220+#endif
221diff -Naur lighttpd-1.4.10.orig/src/connections.c lighttpd-1.4.10/src/connections.c
222--- lighttpd-1.4.10.orig/src/connections.c 2006-02-08 04:27:20.000000000 -0800
223+++ lighttpd-1.4.10/src/connections.c 2006-02-16 22:25:16.507346536 -0800
224@@ -18,6 +18,7 @@
225 #include "response.h"
226 #include "network.h"
227 #include "http_chunk.h"
228+#include "chunk_encode.h"
229 #include "stat_cache.h"
230 #include "joblist.h"
231
232@@ -146,6 +147,12 @@
233 return 0;
234 }
235
236+int connection_queue_is_empty(connection *con) {
237+ if(!chunkqueue_is_empty(con->write_queue)) return 0;
238+ if(!chunkqueue_is_empty(con->output_queue)) return 0;
239+ return 1;
240+}
241+
242 #if 0
243 static void dump_packet(const unsigned char *data, size_t len) {
244 size_t i, j;
245@@ -365,6 +372,7 @@
246 con->file_finished = 1;
247
248 chunkqueue_reset(con->write_queue);
249+ chunkqueue_reset(con->output_queue);
250 }
251 break;
252 default:
253@@ -472,12 +480,27 @@
254 /* disable chunked encoding again as we have no body */
255 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
256 chunkqueue_reset(con->write_queue);
257+ chunkqueue_reset(con->output_queue);
258
259 con->file_finished = 1;
260 break;
261 }
262
263
264+ /* Allow filter plugins to change response headers before they are written. */
265+ switch(plugins_call_handle_response_start(srv, con)) {
266+ case HANDLER_GO_ON:
267+ case HANDLER_FINISHED:
268+ /* response start is finished */
269+ break;
270+ default:
271+ /* something strange happend */
272+ log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed.");
273+ connection_set_state(srv, con, CON_STATE_ERROR);
274+ joblist_append(srv, con);
275+ break;
276+ }
277+
278 if (con->file_finished) {
279 /* we have all the content and chunked encoding is not used, set a content-length */
280
281@@ -517,6 +540,7 @@
282
283 if (con->request.http_method == HTTP_METHOD_HEAD) {
284 chunkqueue_reset(con->write_queue);
285+ chunkqueue_reset(con->output_queue);
286 }
287
288 http_response_write_header(srv, con);
289@@ -525,11 +549,57 @@
290 }
291
292 static int connection_handle_write(server *srv, connection *con) {
293- switch(network_write_chunkqueue(srv, con, con->write_queue)) {
294+ int finished = 0;
295+ int len;
296+
297+ /* Allow filter plugins to modify response conent */
298+ switch(plugins_call_handle_response_filter(srv, con)) {
299+ case HANDLER_GO_ON:
300+ finished = con->file_finished;
301+ /* response content not changed */
302+ break;
303+ case HANDLER_COMEBACK:
304+ /* response filter has more work */
305+ finished = 0;
306+ break;
307+ case HANDLER_FINISHED:
308+ /* response filter is finished */
309+ finished = 1;
310+ break;
311+ default:
312+ /* something strange happend */
313+ log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed.");
314+ connection_set_state(srv, con, CON_STATE_ERROR);
315+ joblist_append(srv, con);
316+ finished = 1;
317+ break;
318+ }
319+
320+ /* move chunks from write_queue to output_queue. */
321+ if (con->request.http_method == HTTP_METHOD_HEAD) {
322+ chunkqueue_reset(con->write_queue);
323+ } else {
324+ len = chunkqueue_length(con->write_queue);
325+ if(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
326+ chunk_encode_append_queue(con->output_queue, con->write_queue);
327+ if(finished && !con->end_chunk) {
328+ con->end_chunk = 1;
329+ chunk_encode_end(con->output_queue);
330+ }
331+ } else {
332+ chunkqueue_append_chunkqueue(con->output_queue, con->write_queue);
333+ }
334+ con->write_queue->bytes_out += len;
335+ }
336+ /* write chunks from output_queue to network */
337+ switch(network_write_chunkqueue(srv, con, con->output_queue)) {
338 case 0:
339- if (con->file_finished) {
340+ if (finished) {
341 connection_set_state(srv, con, CON_STATE_RESPONSE_END);
342 joblist_append(srv, con);
343+ } else {
344+ /* not finished yet -> WRITE */
345+ con->is_writable = 1;
346 }
347 break;
348 case -1: /* error on our side */
349@@ -599,6 +669,7 @@
350
351 #undef CLEAN
352 con->write_queue = chunkqueue_init();
353+ con->output_queue = chunkqueue_init();
354 con->read_queue = chunkqueue_init();
355 con->request_content_queue = chunkqueue_init();
356 chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs);
357@@ -627,6 +698,7 @@
358 connection_reset(srv, con);
359
360 chunkqueue_free(con->write_queue);
361+ chunkqueue_free(con->output_queue);
362 chunkqueue_free(con->read_queue);
363 chunkqueue_free(con->request_content_queue);
364 array_free(con->request.headers);
365@@ -681,6 +753,7 @@
366 con->http_status = 0;
367 con->file_finished = 0;
368 con->file_started = 0;
369+ con->end_chunk = 0;
370 con->got_response = 0;
371
372 con->parsed_response = 0;
373@@ -751,6 +824,7 @@
374 array_reset(con->environment);
375
376 chunkqueue_reset(con->write_queue);
377+ chunkqueue_reset(con->output_queue);
378 chunkqueue_reset(con->request_content_queue);
379
380 /* the plugins should cleanup themself */
381@@ -1178,7 +1252,6 @@
382 }
383
384 if (con->state == CON_STATE_WRITE &&
385- !chunkqueue_is_empty(con->write_queue) &&
386 con->is_writable) {
387
388 if (-1 == connection_handle_write(srv, con)) {
389@@ -1573,15 +1646,15 @@
390 }
391
392 /* only try to write if we have something in the queue */
393- if (!chunkqueue_is_empty(con->write_queue)) {
394 #if 0
395+ if (!connection_queue_is_empty(con)) {
396 log_error_write(srv, __FILE__, __LINE__, "dsd",
397 con->fd,
398 "packets to write:",
399- con->write_queue->used);
400-#endif
401+ con->output_queue->used);
402 }
403- if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
404+#endif
405+ if (con->is_writable) {
406 if (-1 == connection_handle_write(srv, con)) {
407 log_error_write(srv, __FILE__, __LINE__, "ds",
408 con->fd,
409@@ -1691,9 +1764,9 @@
410 * - if we have data to write
411 * - if the socket is not writable yet
412 */
413- if (!chunkqueue_is_empty(con->write_queue) &&
414- (con->is_writable == 0) &&
415- (con->traffic_limit_reached == 0)) {
416+ if ((con->is_writable == 0) &&
417+ (con->traffic_limit_reached == 0) &&
418+ !connection_queue_is_empty(con)) {
419 fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
420 } else {
421 fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
422diff -Naur lighttpd-1.4.10.orig/src/http_chunk.c lighttpd-1.4.10/src/http_chunk.c
423--- lighttpd-1.4.10.orig/src/http_chunk.c 2005-08-10 15:26:50.000000000 -0700
424+++ lighttpd-1.4.10/src/http_chunk.c 2006-02-16 22:25:16.508346367 -0800
425@@ -58,16 +58,9 @@
426
427 cq = con->write_queue;
428
429- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
430- http_chunk_append_len(srv, con, len);
431- }
432-
433+
434 chunkqueue_append_file(cq, fn, offset, len);
435
436- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
437- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
438- }
439-
440 return 0;
441 }
442
443@@ -78,16 +71,9 @@
444
445 cq = con->write_queue;
446
447- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
448- http_chunk_append_len(srv, con, mem->used - 1);
449- }
450-
451+
452 chunkqueue_append_buffer(cq, mem);
453
454- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
455- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
456- }
457-
458 return 0;
459 }
460
461@@ -99,25 +85,11 @@
462 cq = con->write_queue;
463
464 if (len == 0) {
465- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
466- http_chunk_append_len(srv, con, 0);
467- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
468- } else {
469- chunkqueue_append_mem(cq, "", 1);
470- }
471 return 0;
472 }
473
474- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
475- http_chunk_append_len(srv, con, len - 1);
476- }
477-
478 chunkqueue_append_mem(cq, mem, len);
479
480- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
481- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
482- }
483-
484 return 0;
485 }
486
487diff -Naur lighttpd-1.4.10.orig/src/joblist.c lighttpd-1.4.10/src/joblist.c
488--- lighttpd-1.4.10.orig/src/joblist.c 2005-08-10 15:26:41.000000000 -0700
489+++ lighttpd-1.4.10/src/joblist.c 2006-02-16 22:25:16.508346367 -0800
490@@ -7,6 +7,7 @@
491
492 int joblist_append(server *srv, connection *con) {
493 if (con->in_joblist) return 0;
494+ con->in_joblist = 1;
495
496 if (srv->joblist->size == 0) {
497 srv->joblist->size = 16;
498diff -Naur lighttpd-1.4.10.orig/src/mod_deflate.c lighttpd-1.4.10/src/mod_deflate.c
499--- lighttpd-1.4.10.orig/src/mod_deflate.c 1969-12-31 16:00:00.000000000 -0800
500+++ lighttpd-1.4.10/src/mod_deflate.c 2006-02-17 23:26:45.885437687 -0800
501@@ -0,0 +1,1291 @@
502+#include <sys/types.h>
503+#include <sys/stat.h>
504+
505+#include <fcntl.h>
506+#include <unistd.h>
507+#include <ctype.h>
508+#include <stdlib.h>
509+#include <string.h>
510+#include <errno.h>
511+#include <time.h>
512+#include <assert.h>
513+
514+#include "base.h"
515+#include "log.h"
516+#include "buffer.h"
517+#include "response.h"
518+#include "joblist.h"
519+#include "stat_cache.h"
520+
521+#include "plugin.h"
522+
523+#include "crc32.h"
524+#include "etag.h"
525+
526+#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
527+# define USE_ZLIB
528+# include <zlib.h>
529+#else
530+# define Z_DEFAULT_COMPRESSION 1
531+#endif
532+
533+#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
534+# define USE_BZ2LIB
535+/* we don't need stdio interface */
536+# define BZ_NO_STDIO
537+# include <bzlib.h>
538+#endif
539+
540+#include "sys-mmap.h"
541+
542+/* request: accept-encoding */
543+#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
544+#define HTTP_ACCEPT_ENCODING_GZIP BV(1)
545+#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2)
546+#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3)
547+#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4)
548+
549+#define KByte * 1024
550+#define MByte * 1024 KByte
551+#define GByte * 1024 MByte
552+
553+typedef struct {
554+ unsigned short debug;
555+ unsigned short enabled;
556+ unsigned short bzip2;
557+ unsigned short sync_flush;
558+ unsigned short output_buffer_size;
559+ unsigned short min_compress_size;
560+ unsigned short work_block_size;
561+ short mem_level;
562+ short compression_level;
563+ short window_size;
564+ array *mimetypes;
565+} plugin_config;
566+
567+typedef struct {
568+ PLUGIN_DATA;
569+ buffer *tmp_buf;
570+
571+ plugin_config **config_storage;
572+ plugin_config conf;
573+} plugin_data;
574+
575+typedef struct {
576+ int bytes_in;
577+ int bytes_out;
578+ chunkqueue *in_queue;
579+ buffer *output;
580+ /* compression type & state */
581+ int compression_type;
582+ int stream_open;
583+#ifdef USE_ZLIB
584+ unsigned long crc;
585+ z_stream z;
586+ unsigned short gzip_header;
587+#endif
588+#ifdef USE_BZ2LIB
589+ bz_stream bz;
590+#endif
591+ plugin_data *plugin_data;
592+} handler_ctx;
593+
594+static handler_ctx *handler_ctx_init() {
595+ handler_ctx *hctx;
596+
597+ hctx = calloc(1, sizeof(*hctx));
598+ hctx->in_queue = chunkqueue_init();
599+
600+ return hctx;
601+}
602+
603+static void handler_ctx_free(handler_ctx *hctx) {
604+ chunkqueue_free(hctx->in_queue);
605+ free(hctx);
606+}
607+
608+INIT_FUNC(mod_deflate_init) {
609+ plugin_data *p;
610+
611+ p = calloc(1, sizeof(*p));
612+
613+ p->tmp_buf = buffer_init();
614+
615+ return p;
616+}
617+
618+FREE_FUNC(mod_deflate_free) {
619+ plugin_data *p = p_d;
620+
621+ UNUSED(srv);
622+
623+ if (!p) return HANDLER_GO_ON;
624+
625+ if (p->config_storage) {
626+ size_t i;
627+ for (i = 0; i < srv->config_context->used; i++) {
628+ plugin_config *s = p->config_storage[i];
629+
630+ if (!s) continue;
631+
632+ array_free(s->mimetypes);
633+
634+ free(s);
635+ }
636+ free(p->config_storage);
637+ }
638+
639+ buffer_free(p->tmp_buf);
640+
641+ free(p);
642+
643+ return HANDLER_GO_ON;
644+}
645+
646+SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
647+ plugin_data *p = p_d;
648+ size_t i = 0;
649+
650+ config_values_t cv[] = {
651+ { "deflate.output-buffer-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
652+ { "deflate.mimetypes", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
653+ { "deflate.compression-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
654+ { "deflate.mem-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
655+ { "deflate.window-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
656+ { "deflate.min-compress-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
657+ { "deflate.work-block-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
658+ { "deflate.enabled", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
659+ { "deflate.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
660+ { "deflate.bzip2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
661+ { "deflate.sync-flush", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
662+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
663+ };
664+
665+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
666+
667+ for (i = 0; i < srv->config_context->used; i++) {
668+ plugin_config *s;
669+
670+ s = calloc(1, sizeof(plugin_config));
671+ s->enabled = 1;
672+ s->bzip2 = 1;
673+ s->sync_flush = 0;
674+ s->debug = 0;
675+ s->output_buffer_size = 0;
676+ s->mem_level = 9;
677+ s->window_size = 15;
678+ s->min_compress_size = 0;
679+ s->work_block_size = 2048;
680+ s->compression_level = Z_DEFAULT_COMPRESSION;
681+ s->mimetypes = array_init();
682+
683+ cv[0].destination = &(s->output_buffer_size);
684+ cv[1].destination = s->mimetypes;
685+ cv[2].destination = &(s->compression_level);
686+ cv[3].destination = &(s->mem_level);
687+ cv[4].destination = &(s->window_size);
688+ cv[5].destination = &(s->min_compress_size);
689+ cv[6].destination = &(s->work_block_size);
690+ cv[7].destination = &(s->enabled);
691+ cv[8].destination = &(s->debug);
692+ cv[9].destination = &(s->bzip2);
693+ cv[10].destination = &(s->sync_flush);
694+
695+ p->config_storage[i] = s;
696+
697+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
698+ return HANDLER_ERROR;
699+ }
700+
701+ if((s->compression_level < 1 || s->compression_level > 9) &&
702+ s->compression_level != Z_DEFAULT_COMPRESSION) {
703+ log_error_write(srv, __FILE__, __LINE__, "sd",
704+ "compression-level must be between 1 and 9:", s->compression_level);
705+ return HANDLER_ERROR;
706+ }
707+
708+ if(s->mem_level < 1 || s->mem_level > 9) {
709+ log_error_write(srv, __FILE__, __LINE__, "sd",
710+ "mem-level must be between 1 and 9:", s->mem_level);
711+ return HANDLER_ERROR;
712+ }
713+
714+ if(s->window_size < 1 || s->window_size > 15) {
715+ log_error_write(srv, __FILE__, __LINE__, "sd",
716+ "window-size must be between 1 and 15:", s->window_size);
717+ return HANDLER_ERROR;
718+ }
719+ s->window_size = 0 - s->window_size;
720+
721+ if(s->sync_flush) {
722+ s->output_buffer_size = 0;
723+ }
724+ }
725+
726+ return HANDLER_GO_ON;
727+
728+}
729+
730+#ifdef USE_ZLIB
731+/* Copied gzip_header from apache 2.2's mod_deflate.c */
732+/* RFC 1952 Section 2.3 defines the gzip header:
733+ *
734+ * +---+---+---+---+---+---+---+---+---+---+
735+ * |ID1|ID2|CM |FLG| MTIME |XFL|OS |
736+ * +---+---+---+---+---+---+---+---+---+---+
737+ */
738+static const char gzip_header[10] =
739+{ '\037', '\213', Z_DEFLATED, 0,
740+ 0, 0, 0, 0, /* mtime */
741+ 0, 0x03 /* Unix OS_CODE */
742+};
743+static int stream_deflate_init(server *srv, connection *con, handler_ctx *hctx) {
744+ plugin_data *p = hctx->plugin_data;
745+ z_stream *z;
746+
747+ UNUSED(srv);
748+ UNUSED(con);
749+
750+ z = &(hctx->z);
751+ z->zalloc = Z_NULL;
752+ z->zfree = Z_NULL;
753+ z->opaque = Z_NULL;
754+ z->total_in = 0;
755+ z->total_out = 0;
756+ z->next_out = NULL;
757+ z->avail_out = 0;
758+
759+ if(p->conf.debug) {
760+ log_error_write(srv, __FILE__, __LINE__, "sd",
761+ "output-buffer-size:", p->conf.output_buffer_size);
762+ log_error_write(srv, __FILE__, __LINE__, "sd",
763+ "compression-level:", p->conf.compression_level);
764+ log_error_write(srv, __FILE__, __LINE__, "sd",
765+ "mem-level:", p->conf.mem_level);
766+ log_error_write(srv, __FILE__, __LINE__, "sd",
767+ "window-size:", p->conf.window_size);
768+ log_error_write(srv, __FILE__, __LINE__, "sd",
769+ "min-compress-size:", p->conf.min_compress_size);
770+ log_error_write(srv, __FILE__, __LINE__, "sd",
771+ "work-block-size:", p->conf.work_block_size);
772+ }
773+ if (Z_OK != deflateInit2(z,
774+ p->conf.compression_level,
775+ Z_DEFLATED,
776+ p->conf.window_size, /* supress zlib-header */
777+ p->conf.mem_level,
778+ Z_DEFAULT_STRATEGY)) {
779+ return -1;
780+ }
781+ hctx->stream_open = 1;
782+
783+ return 0;
784+}
785+
786+static int stream_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
787+ plugin_data *p = hctx->plugin_data;
788+ z_stream *z;
789+ int len;
790+ int in = 0, out = 0;
791+
792+ UNUSED(srv);
793+ z = &(hctx->z);
794+
795+ if(z->next_out == NULL) {
796+ z->next_out = (unsigned char *)hctx->output->ptr;
797+ z->avail_out = hctx->output->size;
798+ }
799+
800+ if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP) {
801+ if(hctx->gzip_header == 0) {
802+ hctx->gzip_header = 1;
803+ /* copy gzip header into output buffer */
804+ buffer_copy_memory(hctx->output, gzip_header, sizeof(gzip_header));
805+ if(p->conf.debug) {
806+ log_error_write(srv, __FILE__, __LINE__, "sd",
807+ "gzip_header len=", sizeof(gzip_header));
808+ }
809+ /* initialize crc32 */
810+ hctx->crc = crc32(0L, Z_NULL, 0);
811+ z->next_out = (unsigned char *)(hctx->output->ptr + sizeof(gzip_header));
812+ z->avail_out = hctx->output->size - sizeof(gzip_header);
813+ }
814+ hctx->crc = crc32(hctx->crc, start, st_size);
815+ }
816+
817+ z->next_in = start;
818+ z->avail_in = st_size;
819+ hctx->bytes_in += st_size;
820+
821+ /* compress data */
822+ in = z->avail_in;
823+ do {
824+ if (Z_OK != deflate(z, Z_NO_FLUSH)) {
825+ deflateEnd(z);
826+ hctx->stream_open = 0;
827+ return -1;
828+ }
829+
830+ if(z->avail_out == 0 || z->avail_in > 0) {
831+ len = hctx->output->size - z->avail_out;
832+ hctx->bytes_out += len;
833+ out += len;
834+ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
835+ z->next_out = (unsigned char *)hctx->output->ptr;
836+ z->avail_out = hctx->output->size;
837+ }
838+ } while (z->avail_in > 0);
839+ if(p->conf.debug) {
840+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
841+ "compress: in=", in, ", out=", out);
842+ }
843+ return 0;
844+}
845+
846+static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
847+ plugin_data *p = hctx->plugin_data;
848+ z_stream *z;
849+ int len;
850+ int rc = 0;
851+ int done;
852+ int flush = 1;
853+ int in = 0, out = 0;
854+
855+ UNUSED(srv);
856+
857+ z = &(hctx->z);
858+
859+ if(z->next_out == NULL) {
860+ z->next_out = (unsigned char *)hctx->output->ptr;
861+ z->avail_out = hctx->output->size;
862+ }
863+ /* compress data */
864+ in = z->avail_in;
865+ do {
866+ done = 1;
867+ if(end) {
868+ rc = deflate(z, Z_FINISH);
869+ if (rc == Z_OK) {
870+ done = 0;
871+ } else if (rc != Z_STREAM_END) {
872+ deflateEnd(z);
873+ hctx->stream_open = 0;
874+ return -1;
875+ }
876+ } else {
877+ if(p->conf.sync_flush) {
878+ rc = deflate(z, Z_SYNC_FLUSH);
879+ } else if(z->avail_in > 0) {
880+ if(p->conf.output_buffer_size > 0) flush = 0;
881+ rc = deflate(z, Z_NO_FLUSH);
882+ } else {
883+ if(p->conf.output_buffer_size > 0) flush = 0;
884+ rc = Z_OK;
885+ }
886+ if (rc != Z_OK) {
887+ deflateEnd(z);
888+ hctx->stream_open = 0;
889+ return -1;
890+ }
891+ }
892+
893+ len = hctx->output->size - z->avail_out;
894+ if(z->avail_out == 0 || (flush && len > 0)) {
895+ hctx->bytes_out += len;
896+ out += len;
897+ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
898+ z->next_out = (unsigned char *)hctx->output->ptr;
899+ z->avail_out = hctx->output->size;
900+ }
901+ } while (z->avail_in != 0 || !done);
902+ if(p->conf.debug) {
903+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
904+ "flush: in=", in, ", out=", out);
905+ }
906+ if(p->conf.sync_flush) {
907+ z->next_out = NULL;
908+ z->avail_out = 0;
909+ }
910+ return 0;
911+}
912+
913+static int stream_deflate_end(server *srv, connection *con, handler_ctx *hctx) {
914+ plugin_data *p = hctx->plugin_data;
915+ z_stream *z;
916+ int rc;
917+
918+ UNUSED(srv);
919+
920+ z = &(hctx->z);
921+ if(!hctx->stream_open) return 0;
922+ hctx->stream_open = 0;
923+
924+ if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP && hctx->bytes_out > 0 &&
925+ hctx->bytes_out >= sizeof(gzip_header)) {
926+ /* write gzip footer */
927+ unsigned char c[8];
928+
929+ c[0] = (hctx->crc >> 0) & 0xff;
930+ c[1] = (hctx->crc >> 8) & 0xff;
931+ c[2] = (hctx->crc >> 16) & 0xff;
932+ c[3] = (hctx->crc >> 24) & 0xff;
933+ c[4] = (z->total_in >> 0) & 0xff;
934+ c[5] = (z->total_in >> 8) & 0xff;
935+ c[6] = (z->total_in >> 16) & 0xff;
936+ c[7] = (z->total_in >> 24) & 0xff;
937+ /* append footer to write_queue */
938+ chunkqueue_append_mem(con->write_queue, (char *)c, 9);
939+ hctx->bytes_out += 8;
940+ if(p->conf.debug) {
941+ log_error_write(srv, __FILE__, __LINE__, "sd",
942+ "gzip_footer len=", 8);
943+ }
944+ }
945+
946+ if ((rc = deflateEnd(z)) != Z_OK) {
947+ if(rc == Z_DATA_ERROR) return 0;
948+ if(z->msg != NULL) {
949+ log_error_write(srv, __FILE__, __LINE__, "sdss",
950+ "deflateEnd error ret=", rc, ", msg=", z->msg);
951+ } else {
952+ log_error_write(srv, __FILE__, __LINE__, "sd",
953+ "deflateEnd error ret=", rc);
954+ }
955+ return -1;
956+ }
957+ return 0;
958+}
959+
960+#endif
961+
962+#ifdef USE_BZ2LIB
963+static int stream_bzip2_init(server *srv, connection *con, handler_ctx *hctx) {
964+ plugin_data *p = hctx->plugin_data;
965+ bz_stream *bz;
966+
967+ UNUSED(srv);
968+ UNUSED(con);
969+
970+ bz = &(hctx->bz);
971+ bz->bzalloc = NULL;
972+ bz->bzfree = NULL;
973+ bz->opaque = NULL;
974+ bz->total_in_lo32 = 0;
975+ bz->total_in_hi32 = 0;
976+ bz->total_out_lo32 = 0;
977+ bz->total_out_hi32 = 0;
978+
979+ if(p->conf.debug) {
980+ log_error_write(srv, __FILE__, __LINE__, "sd",
981+ "output-buffer-size:", p->conf.output_buffer_size);
982+ log_error_write(srv, __FILE__, __LINE__, "sd",
983+ "compression-level:", p->conf.compression_level);
984+ log_error_write(srv, __FILE__, __LINE__, "sd",
985+ "mem-level:", p->conf.mem_level);
986+ log_error_write(srv, __FILE__, __LINE__, "sd",
987+ "window-size:", p->conf.window_size);
988+ log_error_write(srv, __FILE__, __LINE__, "sd",
989+ "min-compress-size:", p->conf.min_compress_size);
990+ log_error_write(srv, __FILE__, __LINE__, "sd",
991+ "work-block-size:", p->conf.work_block_size);
992+ }
993+ if (BZ_OK != BZ2_bzCompressInit(bz,
994+ p->conf.compression_level, /* blocksize = 900k */
995+ 0, /* no output */
996+ 30)) { /* workFactor: default */
997+ return -1;
998+ }
999+ hctx->stream_open = 1;
1000+
1001+ return 0;
1002+}
1003+
1004+static int stream_bzip2_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
1005+ plugin_data *p = hctx->plugin_data;
1006+ bz_stream *bz;
1007+ int len;
1008+ int rc;
1009+ int in = 0, out = 0;
1010+
1011+ UNUSED(srv);
1012+
1013+ bz = &(hctx->bz);
1014+
1015+ if(bz->next_out == NULL) {
1016+ bz->next_out = hctx->output->ptr;
1017+ bz->avail_out = hctx->output->size;
1018+ }
1019+
1020+ bz->next_in = (char *)start;
1021+ bz->avail_in = st_size;
1022+ hctx->bytes_in += st_size;
1023+
1024+ /* compress data */
1025+ in = bz->avail_in;
1026+ do {
1027+ rc = BZ2_bzCompress(bz, BZ_RUN);
1028+ if (rc != BZ_RUN_OK) {
1029+ BZ2_bzCompressEnd(bz);
1030+ hctx->stream_open = 0;
1031+ return -1;
1032+ }
1033+
1034+ if(bz->avail_out == 0 || bz->avail_in > 0) {
1035+ len = hctx->output->size - bz->avail_out;
1036+ hctx->bytes_out += len;
1037+ out += len;
1038+ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
1039+ bz->next_out = hctx->output->ptr;
1040+ bz->avail_out = hctx->output->size;
1041+ }
1042+ } while (bz->avail_in > 0);
1043+ if(p->conf.debug) {
1044+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
1045+ "compress: in=", in, ", out=", out);
1046+ }
1047+ return 0;
1048+}
1049+
1050+static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
1051+ plugin_data *p = hctx->plugin_data;
1052+ bz_stream *bz;
1053+ int len;
1054+ int rc;
1055+ int done;
1056+ int flush = 1;
1057+ int in = 0, out = 0;
1058+
1059+ UNUSED(srv);
1060+
1061+ bz = &(hctx->bz);
1062+
1063+ if(bz->next_out == NULL) {
1064+ bz->next_out = hctx->output->ptr;
1065+ bz->avail_out = hctx->output->size;
1066+ }
1067+ /* compress data */
1068+ in = bz->avail_in;
1069+ do {
1070+ done = 1;
1071+ if(end) {
1072+ rc = BZ2_bzCompress(bz, BZ_FINISH);
1073+ if (rc == BZ_FINISH_OK) {
1074+ done = 0;
1075+ } else if (rc != BZ_STREAM_END) {
1076+ BZ2_bzCompressEnd(bz);
1077+ hctx->stream_open = 0;
1078+ return -1;
1079+ }
1080+ } else if(bz->avail_in > 0) {
1081+ rc = BZ2_bzCompress(bz, BZ_RUN);
1082+ if (rc != BZ_RUN_OK) {
1083+ BZ2_bzCompressEnd(bz);
1084+ hctx->stream_open = 0;
1085+ return -1;
1086+ }
1087+ if(p->conf.output_buffer_size > 0) flush = 0;
1088+ }
1089+
1090+ len = hctx->output->size - bz->avail_out;
1091+ if(bz->avail_out == 0 || (flush && len > 0)) {
1092+ hctx->bytes_out += len;
1093+ out += len;
1094+ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
1095+ bz->next_out = hctx->output->ptr;
1096+ bz->avail_out = hctx->output->size;
1097+ }
1098+ } while (bz->avail_in != 0 || !done);
1099+ if(p->conf.debug) {
1100+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
1101+ "flush: in=", in, ", out=", out);
1102+ }
1103+ if(p->conf.sync_flush) {
1104+ bz->next_out = NULL;
1105+ bz->avail_out = 0;
1106+ }
1107+ return 0;
1108+}
1109+
1110+static int stream_bzip2_end(server *srv, connection *con, handler_ctx *hctx) {
1111+ plugin_data *p = hctx->plugin_data;
1112+ bz_stream *bz;
1113+ int rc;
1114+
1115+ UNUSED(p);
1116+ UNUSED(con);
1117+
1118+ bz = &(hctx->bz);
1119+ if(!hctx->stream_open) return 0;
1120+ hctx->stream_open = 0;
1121+
1122+ if ((rc = BZ2_bzCompressEnd(bz)) != BZ_OK) {
1123+ if(rc == BZ_DATA_ERROR) return 0;
1124+ log_error_write(srv, __FILE__, __LINE__, "sd",
1125+ "BZ2_bzCompressEnd error ret=", rc);
1126+ return -1;
1127+ }
1128+ return 0;
1129+}
1130+
1131+#endif
1132+
1133+static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
1134+ int ret = -1;
1135+ if(st_size == 0) return 0;
1136+ switch(hctx->compression_type) {
1137+#ifdef USE_ZLIB
1138+ case HTTP_ACCEPT_ENCODING_GZIP:
1139+ case HTTP_ACCEPT_ENCODING_DEFLATE:
1140+ ret = stream_deflate_compress(srv, con, hctx, start, st_size);
1141+ break;
1142+#endif
1143+#ifdef USE_BZ2LIB
1144+ case HTTP_ACCEPT_ENCODING_BZIP2:
1145+ ret = stream_bzip2_compress(srv, con, hctx, start, st_size);
1146+ break;
1147+#endif
1148+ default:
1149+ ret = -1;
1150+ break;
1151+ }
1152+
1153+ return ret;
1154+}
1155+
1156+static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
1157+ int ret = -1;
1158+ if(hctx->bytes_in == 0) return 0;
1159+ switch(hctx->compression_type) {
1160+#ifdef USE_ZLIB
1161+ case HTTP_ACCEPT_ENCODING_GZIP:
1162+ case HTTP_ACCEPT_ENCODING_DEFLATE:
1163+ ret = stream_deflate_flush(srv, con, hctx, end);
1164+ break;
1165+#endif
1166+#ifdef USE_BZ2LIB
1167+ case HTTP_ACCEPT_ENCODING_BZIP2:
1168+ ret = stream_bzip2_flush(srv, con, hctx, end);
1169+ break;
1170+#endif
1171+ default:
1172+ ret = -1;
1173+ break;
1174+ }
1175+
1176+ return ret;
1177+}
1178+
1179+static int mod_deflate_stream_end(server *srv, connection *con, handler_ctx *hctx) {
1180+ int ret = -1;
1181+ switch(hctx->compression_type) {
1182+#ifdef USE_ZLIB
1183+ case HTTP_ACCEPT_ENCODING_GZIP:
1184+ case HTTP_ACCEPT_ENCODING_DEFLATE:
1185+ ret = stream_deflate_end(srv, con, hctx);
1186+ break;
1187+#endif
1188+#ifdef USE_BZ2LIB
1189+ case HTTP_ACCEPT_ENCODING_BZIP2:
1190+ ret = stream_bzip2_end(srv, con, hctx);
1191+ break;
1192+#endif
1193+ default:
1194+ ret = -1;
1195+ break;
1196+ }
1197+
1198+ return ret;
1199+}
1200+
1201+static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hctx, chunk *c, off_t st_size) {
1202+ plugin_data *p = hctx->plugin_data;
1203+ off_t abs_offset;
1204+ off_t toSend;
1205+ stat_cache_entry *sce = NULL;
1206+ off_t we_want_to_mmap = 2 MByte;
1207+ off_t we_want_to_send = st_size;
1208+ char *start = NULL;
1209+
1210+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
1211+ log_error_write(srv, __FILE__, __LINE__, "sb",
1212+ strerror(errno), c->file.name);
1213+ return -1;
1214+ }
1215+
1216+ abs_offset = c->file.start + c->offset;
1217+
1218+ if (abs_offset > sce->st.st_size) {
1219+ log_error_write(srv, __FILE__, __LINE__, "sb",
1220+ "file was shrinked:", c->file.name);
1221+
1222+ return -1;
1223+ }
1224+
1225+ we_want_to_send = st_size;
1226+ /* mmap the buffer
1227+ * - first mmap
1228+ * - new mmap as the we are at the end of the last one */
1229+ if (c->file.mmap.start == MAP_FAILED ||
1230+ abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
1231+
1232+ /* Optimizations for the future:
1233+ *
1234+ * adaptive mem-mapping
1235+ * the problem:
1236+ * we mmap() the whole file. If someone has alot large files and 32bit
1237+ * machine the virtual address area will be unrun and we will have a failing
1238+ * mmap() call.
1239+ * solution:
1240+ * only mmap 16M in one chunk and move the window as soon as we have finished
1241+ * the first 8M
1242+ *
1243+ * read-ahead buffering
1244+ * the problem:
1245+ * sending out several large files in parallel trashes the read-ahead of the
1246+ * kernel leading to long wait-for-seek times.
1247+ * solutions: (increasing complexity)
1248+ * 1. use madvise
1249+ * 2. use a internal read-ahead buffer in the chunk-structure
1250+ * 3. use non-blocking IO for file-transfers
1251+ * */
1252+
1253+ /* all mmap()ed areas are 512kb expect the last which might be smaller */
1254+ size_t to_mmap;
1255+
1256+ /* this is a remap, move the mmap-offset */
1257+ if (c->file.mmap.start != MAP_FAILED) {
1258+ munmap(c->file.mmap.start, c->file.mmap.length);
1259+ c->file.mmap.offset += we_want_to_mmap;
1260+ } else {
1261+ /* in case the range-offset is after the first mmap()ed area we skip the area */
1262+ c->file.mmap.offset = 0;
1263+
1264+ while (c->file.mmap.offset + we_want_to_mmap < c->file.start) {
1265+ c->file.mmap.offset += we_want_to_mmap;
1266+ }
1267+ }
1268+
1269+ /* length is rel, c->offset too, assume there is no limit at the mmap-boundaries */
1270+ to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset;
1271+ if(to_mmap > we_want_to_mmap) to_mmap = we_want_to_mmap;
1272+ /* we have more to send than we can mmap() at once */
1273+ if(we_want_to_send > to_mmap) we_want_to_send = to_mmap;
1274+
1275+ if (-1 == c->file.fd) { /* open the file if not already open */
1276+ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
1277+ log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
1278+
1279+ return -1;
1280+ }
1281+#ifdef FD_CLOEXEC
1282+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
1283+#endif
1284+ }
1285+
1286+ if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
1287+ /* close it here, otherwise we'd have to set FD_CLOEXEC */
1288+
1289+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
1290+ strerror(errno), c->file.name, c->file.fd);
1291+
1292+ return -1;
1293+ }
1294+
1295+ c->file.mmap.length = to_mmap;
1296+#ifdef LOCAL_BUFFERING
1297+ buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
1298+#else
1299+#ifdef HAVE_MADVISE
1300+ /* don't advise files < 64Kb */
1301+ if (c->file.mmap.length > (64 KByte) &&
1302+ 0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) {
1303+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "madvise failed:",
1304+ strerror(errno), c->file.name, c->file.fd);
1305+ }
1306+#endif
1307+#endif
1308+
1309+ /* chunk_reset() or chunk_free() will cleanup for us */
1310+ }
1311+
1312+ /* to_send = abs_mmap_end - abs_offset */
1313+ toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
1314+ if(toSend > we_want_to_send) toSend = we_want_to_send;
1315+
1316+ if (toSend < 0) {
1317+ log_error_write(srv, __FILE__, __LINE__, "soooo",
1318+ "toSend is negative:",
1319+ toSend,
1320+ c->file.mmap.length,
1321+ abs_offset,
1322+ c->file.mmap.offset);
1323+ assert(toSend < 0);
1324+ }
1325+
1326+#ifdef LOCAL_BUFFERING
1327+ start = c->mem->ptr;
1328+#else
1329+ start = c->file.mmap.start;
1330+#endif
1331+
1332+ if(p->conf.debug) {
1333+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
1334+ "compress file chunk: offset=", (int)c->offset,
1335+ ", toSend=", (int)toSend);
1336+ }
1337+ if (mod_deflate_compress(srv, con, hctx,
1338+ (unsigned char *)start + (abs_offset - c->file.mmap.offset), toSend) < 0) {
1339+ log_error_write(srv, __FILE__, __LINE__, "s",
1340+ "compress failed.");
1341+ return -1;
1342+ }
1343+
1344+ c->offset += toSend;
1345+ if (c->offset == c->file.length) {
1346+ /* we don't need the mmaping anymore */
1347+ if (c->file.mmap.start != MAP_FAILED) {
1348+ munmap(c->file.mmap.start, c->file.mmap.length);
1349+ c->file.mmap.start = MAP_FAILED;
1350+ }
1351+ }
1352+
1353+ return toSend;
1354+}
1355+
1356+static int deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) {
1357+ plugin_data *p = hctx->plugin_data;
1358+ int rc;
1359+
1360+ rc = mod_deflate_stream_end(srv, con, hctx);
1361+ if(rc < 0) {
1362+ log_error_write(srv, __FILE__, __LINE__, "s", "error closing stream");
1363+ }
1364+ if(p->conf.debug) {
1365+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
1366+ " in:", hctx->bytes_in,
1367+ " out:", hctx->bytes_out);
1368+ }
1369+
1370+ /* cleanup compression state */
1371+ if(hctx->output != p->tmp_buf) {
1372+ buffer_free(hctx->output);
1373+ }
1374+ handler_ctx_free(hctx);
1375+ con->plugin_ctx[p->id] = NULL;
1376+
1377+ return 0;
1378+}
1379+
1380+static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx, int end) {
1381+ plugin_data *p = hctx->plugin_data;
1382+ chunk *c;
1383+ size_t chunks_written = 0;
1384+ int chunk_finished = 0;
1385+ int len = 0;
1386+ int rc=-1;
1387+ int close_stream = 0;
1388+ int out = 0;
1389+ int max = 0;
1390+
1391+ /* move all chunk from write_queue into our in_queue */
1392+ chunkqueue_append_chunkqueue(hctx->in_queue, con->write_queue);
1393+
1394+ len = chunkqueue_length(hctx->in_queue);
1395+ if(p->conf.debug) {
1396+ log_error_write(srv, __FILE__, __LINE__, "sd",
1397+ "compress: in_queue len=", len);
1398+ }
1399+ /* calculate max bytes to compress for this call. */
1400+ if(!end) {
1401+ max = p->conf.work_block_size * 1024;
1402+ if(max == 0 || max > len) max = len;
1403+ } else {
1404+ max = len;
1405+ }
1406+
1407+ /* Compress chunks from in_queue into chunks for write_queue */
1408+ for(c = hctx->in_queue->first; c && out < max; c = c->next) {
1409+ chunk_finished = 0;
1410+ len = 0;
1411+
1412+ switch(c->type) {
1413+ case MEM_CHUNK:
1414+ len = c->mem->used - 1;
1415+ if(len > (max - out)) len = max - out;
1416+ if (mod_deflate_compress(srv, con, hctx, (unsigned char *)c->mem->ptr, len) < 0) {
1417+ log_error_write(srv, __FILE__, __LINE__, "s",
1418+ "compress failed.");
1419+ return HANDLER_ERROR;
1420+ }
1421+ c->offset += len;
1422+ out += len;
1423+ if (c->offset == c->mem->used - 1) {
1424+ chunk_finished = 1;
1425+ chunks_written++;
1426+ }
1427+ break;
1428+ case FILE_CHUNK:
1429+ len = c->file.length - c->offset;
1430+ if(len > (max - out)) len = max - out;
1431+ if ((len = mod_deflate_file_chunk(srv, con, hctx, c, len)) < 0) {
1432+ log_error_write(srv, __FILE__, __LINE__, "s",
1433+ "compress file chunk failed.");
1434+ return HANDLER_ERROR;
1435+ }
1436+ out += len;
1437+ if (c->offset == c->file.length) {
1438+ chunk_finished = 1;
1439+ chunks_written++;
1440+ }
1441+ break;
1442+ default:
1443+
1444+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
1445+
1446+ return HANDLER_ERROR;
1447+ }
1448+ if(!chunk_finished) break;
1449+ }
1450+ if(p->conf.debug) {
1451+ log_error_write(srv, __FILE__, __LINE__, "sd",
1452+ "compressed bytes:", out);
1453+ }
1454+ hctx->in_queue->bytes_out += out;
1455+
1456+ if(chunks_written > 0) {
1457+ chunkqueue_remove_finished_chunks(hctx->in_queue);
1458+ }
1459+
1460+ close_stream = (con->file_finished && chunkqueue_is_empty(hctx->in_queue));
1461+ rc = mod_deflate_stream_flush(srv, con, hctx, close_stream);
1462+ if(rc < 0) {
1463+ log_error_write(srv, __FILE__, __LINE__, "s", "flush error");
1464+ }
1465+ if(close_stream || end) {
1466+ deflate_compress_cleanup(srv, con, hctx);
1467+ if(p->conf.debug) {
1468+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
1469+ "finished uri:", con->uri.path_raw, ", query:", con->uri.query);
1470+ }
1471+ return HANDLER_FINISHED;
1472+ } else {
1473+ if(!chunkqueue_is_empty(hctx->in_queue)) {
1474+ /* We have more data to compress. */
1475+ joblist_append(srv, con);
1476+ }
1477+ return HANDLER_COMEBACK;
1478+ }
1479+}
1480+
1481+#define PATCH(x) \
1482+ p->conf.x = s->x;
1483+static int mod_deflate_patch_connection(server *srv, connection *con, plugin_data *p) {
1484+ size_t i, j;
1485+ plugin_config *s = p->config_storage[0];
1486+
1487+ PATCH(output_buffer_size);
1488+ PATCH(mimetypes);
1489+ PATCH(compression_level);
1490+ PATCH(mem_level);
1491+ PATCH(window_size);
1492+ PATCH(min_compress_size);
1493+ PATCH(work_block_size);
1494+ PATCH(enabled);
1495+ PATCH(debug);
1496+ PATCH(bzip2);
1497+ PATCH(sync_flush);
1498+
1499+ /* skip the first, the global context */
1500+ for (i = 1; i < srv->config_context->used; i++) {
1501+ data_config *dc = (data_config *)srv->config_context->data[i];
1502+ s = p->config_storage[i];
1503+
1504+ /* condition didn't match */
1505+ if (!config_check_cond(srv, con, dc)) continue;
1506+
1507+ /* merge config */
1508+ for (j = 0; j < dc->value->used; j++) {
1509+ data_unset *du = dc->value->data[j];
1510+
1511+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.output-buffer-size"))) {
1512+ PATCH(output_buffer_size);
1513+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.mimetypes"))) {
1514+ PATCH(mimetypes);
1515+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.compression-level"))) {
1516+ PATCH(compression_level);
1517+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.mem-level"))) {
1518+ PATCH(mem_level);
1519+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.window-size"))) {
1520+ PATCH(window_size);
1521+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.min-compress-size"))) {
1522+ PATCH(min_compress_size);
1523+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.work-block-size"))) {
1524+ PATCH(work_block_size);
1525+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.enabled"))) {
1526+ PATCH(enabled);
1527+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.debug"))) {
1528+ PATCH(debug);
1529+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.bzip2"))) {
1530+ PATCH(bzip2);
1531+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.sync-flush"))) {
1532+ PATCH(sync_flush);
1533+ }
1534+ }
1535+ }
1536+
1537+ return 0;
1538+}
1539+#undef PATCH
1540+
1541+PHYSICALPATH_FUNC(mod_deflate_handle_response_start) {
1542+ plugin_data *p = p_d;
1543+ handler_ctx *hctx;
1544+ data_string *ds;
1545+ int accept_encoding = 0;
1546+ char *value;
1547+ int srv_encodings = 0;
1548+ int matched_encodings = 0;
1549+ const char *dflt_gzip = "gzip";
1550+ const char *dflt_deflate = "deflate";
1551+ const char *dflt_bzip2 = "bzip2";
1552+ const char *compression_name = NULL;
1553+ int file_len=0;
1554+ int rc=-2;
1555+ size_t m;
1556+
1557+ /* disable compression for some http status types. */
1558+ switch(con->http_status) {
1559+ case 100:
1560+ case 101:
1561+ case 204:
1562+ case 205:
1563+ case 304:
1564+ /* disable compression as we have no response entity */
1565+ return HANDLER_GO_ON;
1566+ default:
1567+ break;
1568+ }
1569+
1570+ mod_deflate_patch_connection(srv, con, p);
1571+
1572+ /* is compression allowed */
1573+ if(!p->conf.enabled) {
1574+ if(p->conf.debug) {
1575+ log_error_write(srv, __FILE__, __LINE__, "s", "compression disabled.");
1576+ }
1577+ return HANDLER_GO_ON;
1578+ }
1579+
1580+ /* the response might change according to Accept-Encoding */
1581+ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Vary"))) {
1582+ /* append Accept-Encoding to Vary header */
1583+ if (NULL == strstr(ds->value->ptr, "Accept-Encoding")) {
1584+ buffer_append_string(ds->value, ",Accept-Encoding");
1585+ }
1586+ } else {
1587+ response_header_insert(srv, con, CONST_STR_LEN("Vary"),
1588+ CONST_STR_LEN("Accept-Encoding"));
1589+ }
1590+
1591+ /* Check if response has a Content-Encoding. */
1592+ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Encoding"))) {
1593+ return HANDLER_GO_ON;
1594+ }
1595+
1596+ /* Check Accept-Encoding for supported encoding. */
1597+ if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
1598+ return HANDLER_GO_ON;
1599+ }
1600+
1601+ /* get client side support encodings */
1602+ value = ds->value->ptr;
1603+#ifdef USE_ZLIB
1604+ if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
1605+ if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
1606+#endif
1607+ /* if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; */
1608+#ifdef USE_BZ2LIB
1609+ if(p->conf.bzip2) {
1610+ if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
1611+ }
1612+#endif
1613+ if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
1614+
1615+ /* get server side supported ones */
1616+#ifdef USE_BZ2LIB
1617+ if(p->conf.bzip2) {
1618+ srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
1619+ }
1620+#endif
1621+#ifdef USE_ZLIB
1622+ srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
1623+ srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
1624+#endif
1625+
1626+ /* find matching encodings */
1627+ matched_encodings = accept_encoding & srv_encodings;
1628+ if (!matched_encodings) {
1629+ return HANDLER_GO_ON;
1630+ }
1631+
1632+ /* check if size of response is below min-compress-size */
1633+ if(con->file_finished && con->request.http_method != HTTP_METHOD_HEAD) {
1634+ file_len = chunkqueue_length(con->write_queue);
1635+ if(file_len == 0) return HANDLER_GO_ON;
1636+ } else {
1637+ file_len = 0;
1638+ }
1639+ if(file_len > 0 && p->conf.min_compress_size > 0 && file_len < p->conf.min_compress_size) {
1640+ if(p->conf.debug) {
1641+ log_error_write(srv, __FILE__, __LINE__, "sd",
1642+ "Content-Length smaller then min_compress_size: file_len=", file_len);
1643+ }
1644+ return HANDLER_GO_ON;
1645+ }
1646+
1647+ /* Check mimetype in response header "Content-Type" */
1648+ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
1649+ int found = 0;
1650+ if(p->conf.debug) {
1651+ log_error_write(srv, __FILE__, __LINE__, "sb",
1652+ "Content-Type:", ds->value);
1653+ }
1654+ for (m = 0; m < p->conf.mimetypes->used; m++) {
1655+ data_string *mimetype = (data_string *)p->conf.mimetypes->data[m];
1656+
1657+ if(p->conf.debug) {
1658+ log_error_write(srv, __FILE__, __LINE__, "sb",
1659+ "mime-type:", mimetype->value);
1660+ }
1661+ if (buffer_is_equal(mimetype->value, ds->value)) {
1662+ /* mimetype found */
1663+ found = 1;
1664+ break;
1665+ }
1666+ }
1667+ if(!found && p->conf.mimetypes->used > 0) {
1668+ if(p->conf.debug) {
1669+ log_error_write(srv, __FILE__, __LINE__, "sb",
1670+ "No compression for mimetype:", ds->value);
1671+ }
1672+ return HANDLER_GO_ON;
1673+ }
1674+ }
1675+
1676+ if(p->conf.debug) {
1677+ log_error_write(srv, __FILE__, __LINE__, "s",
1678+ "enable compression.");
1679+ }
1680+ /* enable compression */
1681+ hctx = handler_ctx_init();
1682+ hctx->plugin_data = p;
1683+
1684+ /* select best matching encoding */
1685+ if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
1686+ hctx->compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
1687+ compression_name = dflt_bzip2;
1688+ rc = stream_bzip2_init(srv, con, hctx);
1689+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_GZIP) {
1690+ hctx->compression_type = HTTP_ACCEPT_ENCODING_GZIP;
1691+ compression_name = dflt_gzip;
1692+ rc = stream_deflate_init(srv, con, hctx);
1693+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE) {
1694+ hctx->compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
1695+ compression_name = dflt_deflate;
1696+ rc = stream_deflate_init(srv, con, hctx);
1697+ }
1698+ if(rc == -1) {
1699+ log_error_write(srv, __FILE__, __LINE__, "s",
1700+ "Failed to initialize compression.");
1701+ }
1702+ if(rc < 0) {
1703+ handler_ctx_free(hctx);
1704+ return HANDLER_GO_ON;
1705+ }
1706+
1707+ /* setup output buffer. */
1708+ if(p->conf.sync_flush || p->conf.output_buffer_size == 0) {
1709+ buffer_prepare_copy(p->tmp_buf, 32 * 1024);
1710+ hctx->output = p->tmp_buf;
1711+ } else {
1712+ hctx->output = buffer_init();
1713+ buffer_prepare_copy(hctx->output, p->conf.output_buffer_size);
1714+ }
1715+ con->plugin_ctx[p->id] = hctx;
1716+
1717+ /* set Content-Encoding to show selected compression type. */
1718+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
1719+
1720+ /* if file finished and size less then work-block-size, then compress the content now. */
1721+ if(con->file_finished && (p->conf.work_block_size == 0 || file_len < (p->conf.work_block_size * 1024)) &&
1722+ con->request.http_method != HTTP_METHOD_HEAD) {
1723+ /* We don't have to use chunked encoding. */
1724+ con->response.transfer_encoding = 0;
1725+ con->parsed_response &= ~(HTTP_CONTENT_LENGTH);
1726+ /* Compress all response content. */
1727+ if(p->conf.debug) {
1728+ log_error_write(srv, __FILE__, __LINE__, "sd",
1729+ "Compress all content and use Content-Length header: uncompress len=", file_len);
1730+ }
1731+ return deflate_compress_response(srv, con, hctx, 1);
1732+ } else {
1733+ /* Remove Content-Length header. We don't know the length. */
1734+ con->parsed_response &= ~(HTTP_CONTENT_LENGTH);
1735+ if (con->request.http_version == HTTP_VERSION_1_1) {
1736+ /* Make sure to use chunked encoding. */
1737+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
1738+ /* Remove Content-Length header. We don't know the length. */
1739+ con->parsed_response &= ~(HTTP_CONTENT_LENGTH);
1740+ } else {
1741+ /* HTTP/1.0 doesn't support chunked transfer encoding. */
1742+ con->response.transfer_encoding = 0;
1743+ return deflate_compress_response(srv, con, hctx, 1);
1744+ }
1745+ }
1746+
1747+ return HANDLER_GO_ON;
1748+}
1749+
1750+JOBLIST_FUNC(mod_deflate_handle_response_filter) {
1751+ plugin_data *p = p_d;
1752+ handler_ctx *hctx = con->plugin_ctx[p->id];
1753+
1754+ if(hctx == NULL) return HANDLER_GO_ON;
1755+ if(!hctx->stream_open) return HANDLER_GO_ON;
1756+ if(con->request.http_method == HTTP_METHOD_HEAD) return HANDLER_GO_ON;
1757+
1758+ return deflate_compress_response(srv, con, hctx, 0);
1759+}
1760+
1761+handler_t mod_deflate_cleanup(server *srv, connection *con, void *p_d) {
1762+ plugin_data *p = p_d;
1763+ handler_ctx *hctx = con->plugin_ctx[p->id];
1764+
1765+ if(hctx == NULL) return HANDLER_GO_ON;
1766+
1767+ if(p->conf.debug && hctx->stream_open) {
1768+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
1769+ "stream open at cleanup. uri=", con->uri.path_raw, ", query=", con->uri.query);
1770+ }
1771+
1772+ deflate_compress_cleanup(srv, con, hctx);
1773+
1774+ return HANDLER_GO_ON;
1775+}
1776+
1777+int mod_deflate_plugin_init(plugin *p) {
1778+ p->version = LIGHTTPD_VERSION_ID;
1779+ p->name = buffer_init_string("deflate");
1780+
1781+ p->init = mod_deflate_init;
1782+ p->cleanup = mod_deflate_free;
1783+ p->set_defaults = mod_deflate_setdefaults;
1784+ p->connection_reset = mod_deflate_cleanup;
1785+ p->handle_connection_close = mod_deflate_cleanup;
1786+ p->handle_response_start = mod_deflate_handle_response_start;
1787+ p->handle_response_filter = mod_deflate_handle_response_filter;
1788+
1789+ p->data = NULL;
1790+
1791+ return 0;
1792+}
1793diff -Naur lighttpd-1.4.10.orig/src/plugin.c lighttpd-1.4.10/src/plugin.c
1794--- lighttpd-1.4.10.orig/src/plugin.c 2006-02-08 04:00:54.000000000 -0800
1795+++ lighttpd-1.4.10/src/plugin.c 2006-02-16 22:25:16.514345356 -0800
1796@@ -40,6 +40,8 @@
1797 PLUGIN_FUNC_HANDLE_SIGHUP,
1798 PLUGIN_FUNC_HANDLE_SUBREQUEST,
1799 PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
1800+ PLUGIN_FUNC_HANDLE_RESPONSE_START,
1801+ PLUGIN_FUNC_HANDLE_RESPONSE_FILTER,
1802 PLUGIN_FUNC_HANDLE_JOBLIST,
1803 PLUGIN_FUNC_HANDLE_DOCROOT,
1804 PLUGIN_FUNC_HANDLE_PHYSICAL,
1805@@ -266,6 +268,8 @@
1806 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
1807 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
1808 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
1809+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
1810+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, handle_response_filter)
1811 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
1812 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
1813 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
1814@@ -395,6 +399,8 @@
1815 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
1816 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
1817 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
1818+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start);
1819+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, handle_response_filter);
1820 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
1821 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
1822 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
1823diff -Naur lighttpd-1.4.10.orig/src/plugin.h lighttpd-1.4.10/src/plugin.h
1824--- lighttpd-1.4.10.orig/src/plugin.h 2005-08-15 02:28:56.000000000 -0700
1825+++ lighttpd-1.4.10/src/plugin.h 2006-02-16 22:25:16.514345356 -0800
1826@@ -54,6 +54,8 @@
1827 * has to be found
1828 */
1829 handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
1830+ handler_t (* handle_response_start) (server *srv, connection *con, void *p_d); /* before response headers are written */
1831+ handler_t (* handle_response_filter) (server *srv, connection *con, void *p_d); /* response content filter */
1832 handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
1833 void *data;
1834
1835@@ -68,6 +70,8 @@
1836 handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
1837 handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
1838 handler_t plugins_call_handle_subrequest(server *srv, connection *con);
1839+handler_t plugins_call_handle_response_start(server *srv, connection *con);
1840+handler_t plugins_call_handle_response_filter(server *srv, connection *con);
1841 handler_t plugins_call_handle_request_done(server *srv, connection *con);
1842 handler_t plugins_call_handle_docroot(server *srv, connection *con);
1843 handler_t plugins_call_handle_physical(server *srv, connection *con);
1844diff -Naur lighttpd-1.4.10.orig/src/response.c lighttpd-1.4.10/src/response.c
1845--- lighttpd-1.4.10.orig/src/response.c 2006-02-08 04:01:01.000000000 -0800
1846+++ lighttpd-1.4.10/src/response.c 2006-02-16 22:25:16.515345187 -0800
1847@@ -31,7 +31,7 @@
1848 int have_date = 0;
1849 int have_server = 0;
1850
1851- b = chunkqueue_get_prepend_buffer(con->write_queue);
1852+ b = chunkqueue_get_prepend_buffer(con->output_queue);
1853
1854 if (con->request.http_version == HTTP_VERSION_1_1) {
1855 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
1856diff -Naur lighttpd-1.4.10.orig/src/server.c lighttpd-1.4.10/src/server.c
1857--- lighttpd-1.4.10.orig/src/server.c 2006-02-01 03:50:02.000000000 -0800
1858+++ lighttpd-1.4.10/src/server.c 2006-02-16 22:25:16.516345019 -0800
1859@@ -173,6 +173,9 @@
1860 srv->joblist = calloc(1, sizeof(*srv->joblist));
1861 assert(srv->joblist);
1862
1863+ srv->joblist_prev = calloc(1, sizeof(*srv->joblist));
1864+ assert(srv->joblist_prev);
1865+
1866 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
1867 assert(srv->fdwaitqueue);
1868
1869@@ -259,6 +262,7 @@
1870 #undef CLEAN
1871
1872 joblist_free(srv, srv->joblist);
1873+ joblist_free(srv, srv->joblist_prev);
1874 fdwaitqueue_free(srv, srv->fdwaitqueue);
1875
1876 if (srv->stat_cache) {
1877@@ -1016,6 +1020,7 @@
1878 /* main-loop */
1879 while (!srv_shutdown) {
1880 int n;
1881+ int timeout;
1882 size_t ndx;
1883 time_t min_ts;
1884
1885@@ -1243,7 +1248,12 @@
1886 }
1887 }
1888
1889- if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
1890+ if(srv->joblist->used > 0) {
1891+ timeout = 500;
1892+ } else {
1893+ timeout = 1000;
1894+ }
1895+ if ((n = fdevent_poll(srv->ev, timeout)) > 0) {
1896 /* n is the number of events */
1897 int revents;
1898 int fd_ndx;
1899@@ -1291,25 +1301,29 @@
1900 strerror(errno));
1901 }
1902
1903- for (ndx = 0; ndx < srv->joblist->used; ndx++) {
1904- connection *con = srv->joblist->ptr[ndx];
1905- handler_t r;
1906-
1907- connection_state_machine(srv, con);
1908-
1909- switch(r = plugins_call_handle_joblist(srv, con)) {
1910- case HANDLER_FINISHED:
1911- case HANDLER_GO_ON:
1912- break;
1913- default:
1914- log_error_write(srv, __FILE__, __LINE__, "d", r);
1915- break;
1916+ if(srv->joblist->used > 0) {
1917+ connections *joblist = srv->joblist;
1918+ /* switch joblist queues. */
1919+ srv->joblist = srv->joblist_prev;
1920+ srv->joblist_prev = joblist;
1921+ for (ndx = 0; ndx < joblist->used; ndx++) {
1922+ connection *con = joblist->ptr[ndx];
1923+ handler_t r;
1924+
1925+ con->in_joblist = 0;
1926+ connection_state_machine(srv, con);
1927+
1928+ switch(r = plugins_call_handle_joblist(srv, con)) {
1929+ case HANDLER_FINISHED:
1930+ case HANDLER_GO_ON:
1931+ break;
1932+ default:
1933+ log_error_write(srv, __FILE__, __LINE__, "d", r);
1934+ break;
1935+ }
1936 }
1937-
1938- con->in_joblist = 0;
1939+ joblist->used = 0;
1940 }
1941-
1942- srv->joblist->used = 0;
1943 }
1944
1945 if (srv->srvconf.pid_file->used &&
This page took 0.305165 seconds and 4 git commands to generate.