Project

General

Profile

Docs ModDeflate » lighttpd-1.4.13.mod_deflate.patch

mod_deflate patch for lighttpd 1.4.13 - qhy, 2006-10-18 16:14

View differences:

./configure.in Thu Oct 19 00:04:16 2006
538 538
AC_OUTPUT
539 539

  
540 540

  
541
do_build="mod_cgi mod_fastcgi 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"
541
do_build="mod_cgi mod_fastcgi 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"
542 542

  
543 543
plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
544 544
features="regex-conditionals"
./src/Makefile.am Thu Oct 19 00:04:16 2006
234 234
mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
235 235
mod_accesslog_la_LIBADD = $(common_libadd)
236 236

  
237
lib_LTLIBRARIES += mod_deflate.la
238
mod_deflate_la_SOURCES = mod_deflate.c 
239
mod_deflate_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
240
mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
241

  
237 242

  
238 243
hdr = server.h buffer.h network.h log.h keyvalue.h \
239 244
      response.h request.h fastcgi.h chunk.h \
./src/Makefile.in Thu Oct 19 00:04:16 2006
16 16

  
17 17

  
18 18

  
19
SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_magnet_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
19
SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_deflate_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_magnet_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
20 20

  
21 21
srcdir = @srcdir@
22 22
top_srcdir = @top_srcdir@
......
142 142
	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
143 143
am_mod_compress_la_OBJECTS = mod_compress.lo
144 144
mod_compress_la_OBJECTS = $(am_mod_compress_la_OBJECTS)
145
mod_deflate_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
146
       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
147
am_mod_deflate_la_OBJECTS = mod_deflate.lo
148
mod_deflate_la_OBJECTS = $(am_mod_deflate_la_OBJECTS)
145 149
mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
146 150
	$(am__DEPENDENCIES_1)
147 151
am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo
......
296 300
	$(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) \
297 301
	$(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) \
298 302
	$(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \
303
	$(mod_deflate_la_SOURCES) \
299 304
	$(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \
300 305
	$(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \
301 306
	$(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) \
......
508 513
	mod_ssi.la mod_secdownload.la mod_expire.la mod_evhost.la \
509 514
	mod_simple_vhost.la mod_fastcgi.la mod_access.la \
510 515
	mod_compress.la mod_auth.la mod_rewrite.la mod_redirect.la \
511
	mod_status.la mod_accesslog.la
516
	mod_status.la mod_accesslog.la mod_deflate.la
512 517
@NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src)
513 518
@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS)
514 519
@NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
......
612 617
mod_accesslog_la_SOURCES = mod_accesslog.c
613 618
mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
614 619
mod_accesslog_la_LIBADD = $(common_libadd)
620
mod_deflate_la_SOURCES = mod_deflate.c 
621
mod_deflate_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
622
mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
615 623
hdr = server.h buffer.h network.h log.h keyvalue.h \
616 624
      response.h request.h fastcgi.h chunk.h \
617 625
      settings.h http_chunk.h http_auth_digest.h \
......
723 731
	$(LINK) -rpath $(libdir) $(mod_cml_la_LDFLAGS) $(mod_cml_la_OBJECTS) $(mod_cml_la_LIBADD) $(LIBS)
724 732
mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES) 
725 733
	$(LINK) -rpath $(libdir) $(mod_compress_la_LDFLAGS) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
734
mod_deflate.la: $(mod_deflate_la_OBJECTS) $(mod_deflate_la_DEPENDENCIES) 
735
	$(LINK) -rpath $(libdir) $(mod_deflate_la_LDFLAGS) $(mod_deflate_la_OBJECTS) $(mod_deflate_la_LIBADD) $(LIBS)
726 736
mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES) 
727 737
	$(LINK) -rpath $(libdir) $(mod_dirlisting_la_LDFLAGS) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
728 738
mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES) 
......
935 945
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo@am__quote@
936 946
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo@am__quote@
937 947
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_compress.Plo@am__quote@
948
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_deflate.Plo@am__quote@
938 949
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_dirlisting.Plo@am__quote@
939 950
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@
940 951
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@
./src/base.h Thu Oct 19 00:04:32 2006
148 148

  
149 149
	http_method_t  http_method;
150 150
	http_version_t http_version;
151
	int true_http_10_client;
151 152

  
152 153
	buffer *request_line;
153 154

  
......
354 355

  
355 356
	int file_started;
356 357
	int file_finished;
358
	int end_chunk; /* used for chunked transfer encoding. */
357 359

  
358
	chunkqueue *write_queue;      /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
360
	chunkqueue *write_queue;  /* a large queue for HTTP response content [ file, mem ] */
361
	chunkqueue *output_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
359 362
	chunkqueue *read_queue;       /* a small queue for low-level read ( HTTP request ) [ mem ] */
360 363
	chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
361 364

  
......
583 586

  
584 587
	connections *conns;
585 588
	connections *joblist;
589
	connections *joblist_prev;
586 590
	connections *fdwaitqueue;
587 591

  
588 592
	stat_cache  *stat_cache;
./src/chunk.c Thu Oct 19 00:04:16 2006
16 16
#include <errno.h>
17 17
#include <string.h>
18 18

  
19
#include "server.h"
19 20
#include "chunk.h"
21
#include "log.h"
20 22

  
21 23
chunkqueue *chunkqueue_init(void) {
22 24
	chunkqueue *cq;
......
241 243
	return 0;
242 244
}
243 245

  
246
int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src) {
247
	if(src == NULL) return 0;
248
	chunkqueue_append_chunk(cq, src->first);
249
	cq->last = src->last;
250
	src->first = NULL;
251
	src->last = NULL;
252

  
253
	return 0;
254
}
255

  
244 256
buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
245 257
	chunk *c;
246 258

  
......
400 412

  
401 413
	return 0;
402 414
}
415

  
416
/**
417
 * the HTTP chunk-API
418
 * 
419
 * 
420
 */
421

  
422
static int chunk_encode_append_len(chunkqueue *cq, size_t len) {
423
	size_t i, olen = len, j;
424
	buffer *b;
425
	
426
	/*b = srv->tmp_chunk_len;*/
427
	/*b = buffer_init();*/
428
	b = chunkqueue_get_append_buffer(cq);
429
	
430
	if (len == 0) {
431
		buffer_copy_string(b, "0");
432
	} else {
433
		for (i = 0; i < 8 && len; i++) {
434
			len >>= 4;
435
		}
436
		
437
		/* i is the number of hex digits we have */
438
		buffer_prepare_copy(b, i + 1);
439
		
440
		for (j = i-1, len = olen; j+1 > 0; j--) {
441
			b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
442
			len >>= 4;
443
		}
444
		b->used = i;
445
		b->ptr[b->used++] = '\0';
446
	}
447
		
448
	buffer_append_string(b, "\r\n");
449
	/*
450
	chunkqueue_append_buffer(cq, b);
451
	buffer_free(b);
452
	*/
453
	
454
	return 0;
455
}
456

  
457

  
458
int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
459
	if (!cq) return -1;
460
	if (len == 0) return 0;
461
	
462
	chunk_encode_append_len(cq, len);
463
	
464
	chunkqueue_append_file(cq, fn, offset, len);
465
	
466
	chunkqueue_append_mem(cq, "\r\n", 2 + 1);
467
	
468
	return 0;
469
}
470

  
471
int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem) {
472
	if (!cq) return -1;
473
	if (mem->used <= 1) return 0;
474
	
475
	chunk_encode_append_len(cq, mem->used - 1);
476
	
477
	chunkqueue_append_buffer(cq, mem);
478
	
479
	chunkqueue_append_mem(cq, "\r\n", 2 + 1);
480
	
481
	return 0;
482
}
483

  
484
int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len) {
485
	if (!cq) return -1;
486
	if (len <= 1) return 0;
487
	
488
	chunk_encode_append_len(cq, len - 1);
489
	
490
	chunkqueue_append_mem(cq, mem, len);
491
	
492
	chunkqueue_append_mem(cq, "\r\n", 2 + 1);
493
	
494
	return 0;
495
}
496

  
497
int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src) {
498
	int len = chunkqueue_length(src);
499
	if (!cq) return -1;
500
	if (len == 0) return 0;
501
	
502
	chunk_encode_append_len(cq, len);
503
	
504
	chunkqueue_append_chunkqueue(cq, src);
505
	
506
	chunkqueue_append_mem(cq, "\r\n", 2 + 1);
507
	
508
	return 0;
509
}
510

  
511
int chunk_encode_end(chunkqueue *cq) {
512
	chunk_encode_append_len(cq, 0);
513
	chunkqueue_append_mem(cq, "\r\n", 2 + 1);
514
	return 0;
515
}
516

  
./src/chunk.h Thu Oct 19 00:04:16 2006
52 52
int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len);
53 53
int chunkqueue_append_buffer(chunkqueue *c, buffer *mem);
54 54
int chunkqueue_append_buffer_weak(chunkqueue *c, buffer *mem);
55
int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src);
55 56
int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem);
56 57

  
57 58
buffer * chunkqueue_get_append_buffer(chunkqueue *c);
......
66 67
void chunkqueue_reset(chunkqueue *c);
67 68

  
68 69
int chunkqueue_is_empty(chunkqueue *c);
70

  
71
int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len);
72
int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem);
73
int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len);
74
int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src);
75
int chunk_encode_end(chunkqueue *cq);
69 76

  
70 77
#endif
./src/connections.c Thu Oct 19 00:04:16 2006
18 18
#include "response.h"
19 19
#include "network.h"
20 20
#include "http_chunk.h"
21
#include "chunk.h"
21 22
#include "stat_cache.h"
22 23
#include "joblist.h"
23 24

  
......
146 147
	return 0;
147 148
}
148 149

  
150
int connection_queue_is_empty(connection *con) {
151
	if(!chunkqueue_is_empty(con->write_queue)) return 0;
152
	if(!chunkqueue_is_empty(con->output_queue)) return 0;
153
	return 1;
154
}
155

  
149 156
#if 0
150 157
static void dump_packet(const unsigned char *data, size_t len) {
151 158
	size_t i, j;
......
402 409
				con->file_finished = 1;
403 410

  
404 411
				chunkqueue_reset(con->write_queue);
412
				chunkqueue_reset(con->output_queue);
405 413
			}
406 414
			break;
407 415
		default:
......
512 520
		/* disable chunked encoding again as we have no body */
513 521
		con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
514 522
		chunkqueue_reset(con->write_queue);
523
		chunkqueue_reset(con->output_queue);
515 524

  
516 525
		con->file_finished = 1;
517 526
		break;
518 527
	}
519 528

  
520 529

  
530
	/* Allow filter plugins to change response headers before they are written. */
531
	switch(plugins_call_handle_response_start(srv, con)) {
532
	case HANDLER_GO_ON:
533
	case HANDLER_FINISHED:
534
		/* response start is finished */
535
		break;
536
	default:
537
		/* something strange happend */
538
		log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed.");
539
		connection_set_state(srv, con, CON_STATE_ERROR);
540
		joblist_append(srv, con);
541
		break;
542
	}
543

  
521 544
	if (con->file_finished) {
522 545
		/* we have all the content and chunked encoding is not used, set a content-length */
523 546

  
......
568 591
		 * without the content
569 592
		 */
570 593
		chunkqueue_reset(con->write_queue);
594
		chunkqueue_reset(con->output_queue);
571 595
		con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
572 596
	}
573 597

  
......
577 601
}
578 602

  
579 603
static int connection_handle_write(server *srv, connection *con) {
580
	switch(network_write_chunkqueue(srv, con, con->write_queue)) {
604
	int finished = 0;
605
	int len;
606

  
607
	/* Allow filter plugins to modify response conent */
608
	switch(plugins_call_handle_response_filter(srv, con)) {
609
	case HANDLER_GO_ON:
610
		finished = con->file_finished;
611
		/* response content not changed */
612
		break;
613
	case HANDLER_COMEBACK:
614
		/* response filter has more work */
615
		finished = 0;
616
		break;
617
	case HANDLER_FINISHED:
618
		/* response filter is finished */
619
		finished = 1;
620
		break;
621
	default:
622
		/* something strange happend */
623
		log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed.");
624
		connection_set_state(srv, con, CON_STATE_ERROR);
625
		joblist_append(srv, con);
626
		finished = 1;
627
		break;
628
	}
629

  
630
	/* move chunks from write_queue to output_queue. */
631
	if (con->request.http_method == HTTP_METHOD_HEAD) {
632
		chunkqueue_reset(con->write_queue);
633
	} else {
634
		len = chunkqueue_length(con->write_queue);
635
		if(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
636
			chunk_encode_append_queue(con->output_queue, con->write_queue);
637
			if(finished && !con->end_chunk) {
638
				con->end_chunk = 1;
639
				chunk_encode_end(con->output_queue);
640
			}
641
		} else {
642
			chunkqueue_append_chunkqueue(con->output_queue, con->write_queue);
643
		}
644
		con->write_queue->bytes_out += len;
645
	}
646
	/* write chunks from output_queue to network */
647
	switch(network_write_chunkqueue(srv, con, con->output_queue)) {
581 648
	case 0:
582
		if (con->file_finished) {
649
		if (finished) {
583 650
			connection_set_state(srv, con, CON_STATE_RESPONSE_END);
584 651
			joblist_append(srv, con);
652
		} else {
653
			/* not finished yet -> WRITE */
654
			con->is_writable = 1;
585 655
		}
586 656
		break;
587 657
	case -1: /* error on our side */
......
651 721

  
652 722
#undef CLEAN
653 723
	con->write_queue = chunkqueue_init();
724
	con->output_queue = chunkqueue_init();
654 725
	con->read_queue = chunkqueue_init();
655 726
	con->request_content_queue = chunkqueue_init();
656 727
	chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs);
......
679 750
		connection_reset(srv, con);
680 751

  
681 752
		chunkqueue_free(con->write_queue);
753
		chunkqueue_free(con->output_queue);
682 754
		chunkqueue_free(con->read_queue);
683 755
		chunkqueue_free(con->request_content_queue);
684 756
		array_free(con->request.headers);
......
733 805
	con->http_status = 0;
734 806
	con->file_finished = 0;
735 807
	con->file_started = 0;
808
	con->end_chunk = 0;
736 809
	con->got_response = 0;
810
	con->use_cache_file = 0;
811
	con->write_cache_file = 0;
737 812

  
738 813
	con->parsed_response = 0;
739 814

  
......
803 878
	array_reset(con->environment);
804 879

  
805 880
	chunkqueue_reset(con->write_queue);
881
	chunkqueue_reset(con->output_queue);
806 882
	chunkqueue_reset(con->request_content_queue);
807 883

  
808 884
	/* the plugins should cleanup themself */
......
1203 1279
	}
1204 1280

  
1205 1281
	if (con->state == CON_STATE_WRITE &&
1206
	    !chunkqueue_is_empty(con->write_queue) &&
1207 1282
	    con->is_writable) {
1208 1283

  
1209 1284
		if (-1 == connection_handle_write(srv, con)) {
......
1606 1681
			}
1607 1682

  
1608 1683
			/* only try to write if we have something in the queue */
1609
			if (!chunkqueue_is_empty(con->write_queue)) {
1610 1684
#if 0
1685
			if (!connection_queue_is_empty(con)) {
1611 1686
				log_error_write(srv, __FILE__, __LINE__, "dsd",
1612 1687
						con->fd,
1613 1688
						"packets to write:",
1614
						con->write_queue->used);
1615
#endif
1689
						con->output_queue->used);
1616 1690
			}
1617
			if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
1691
#endif
1692
			if (con->is_writable) {
1618 1693
				if (-1 == connection_handle_write(srv, con)) {
1619 1694
					log_error_write(srv, __FILE__, __LINE__, "ds",
1620 1695
							con->fd,
......
1724 1799
		 * - if we have data to write
1725 1800
		 * - if the socket is not writable yet
1726 1801
		 */
1727
		if (!chunkqueue_is_empty(con->write_queue) &&
1728
		    (con->is_writable == 0) &&
1729
		    (con->traffic_limit_reached == 0)) {
1802
		if ((con->is_writable == 0) &&
1803
		    (con->traffic_limit_reached == 0) &&
1804
				!connection_queue_is_empty(con)) {
1730 1805
			fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
1731 1806
		} else {
1732 1807
			fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
./src/http_chunk.c Thu Oct 19 00:04:16 2006
58 58

  
59 59
	cq = con->write_queue;
60 60

  
61
	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
62
		http_chunk_append_len(srv, con, len);
63
	}
64 61

  
65 62
	chunkqueue_append_file(cq, fn, offset, len);
66 63

  
67
	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
68
		chunkqueue_append_mem(cq, "\r\n", 2 + 1);
69
	}
70

  
71 64
	return 0;
72 65
}
73 66

  
......
78 71

  
79 72
	cq = con->write_queue;
80 73

  
81
	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
82
		http_chunk_append_len(srv, con, mem->used - 1);
83
	}
84 74

  
85 75
	chunkqueue_append_buffer(cq, mem);
86 76

  
87
	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
88
		chunkqueue_append_mem(cq, "\r\n", 2 + 1);
89
	}
90

  
91 77
	return 0;
92 78
}
93 79

  
......
99 85
	cq = con->write_queue;
100 86

  
101 87
	if (len == 0) {
102
		if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
103
			chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1);
104
		} else {
105
			chunkqueue_append_mem(cq, "", 1);
106
		}
107 88
		return 0;
108 89
	}
109 90

  
110
	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
111
		http_chunk_append_len(srv, con, len - 1);
112
	}
113

  
114 91
	chunkqueue_append_mem(cq, mem, len);
115

  
116
	if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
117
		chunkqueue_append_mem(cq, "\r\n", 2 + 1);
118
	}
119 92

  
120 93
	return 0;
121 94
}
./src/joblist.c Thu Oct 19 00:04:16 2006
7 7

  
8 8
int joblist_append(server *srv, connection *con) {
9 9
	if (con->in_joblist) return 0;
10
	con->in_joblist = 1;
10 11

  
11 12
	if (srv->joblist->size == 0) {
12 13
		srv->joblist->size  = 16;
./src/mod_deflate.c Thu Oct 19 00:08:49 2006
1
/* bug fix on Robert Jakabosky from alphatrade.com's lighttp 1.4.10 mod_deflate path
2
 *
3
 * new module option:
4
 * deflate.nocompress-url = "^/nocompressurl/" # pcre regex which don't compress
5
 *
6
 * Bug fix and new features:
7
 * 1) fix loop bug when content-length is bigger than work-block-size*k
8
 * 2) prevent compress on buggy http 1.0 client with Accept Encoding: gzip, deflate
9
 * 3) fix bug with chunk transfer encoding (under mod_fastcgi+php environment)
10
 * 
11
 * deflate.sync-flush = "enable" is buggy on chunk encoding transfer. Use it carefully,
12
 */
13
#include <sys/types.h>
14
#include <sys/stat.h>
15

  
16
#include <fcntl.h>
17
#include <unistd.h>
18
#include <ctype.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#include <errno.h>
22
#include <time.h>
23
#include <assert.h>
24

  
25
#if defined(HAVE_PCRE_H)
26
#include <pcre.h>
27
#endif
28

  
29
#include "base.h"
30
#include "log.h"
31
#include "buffer.h"
32
#include "response.h"
33
#include "joblist.h"
34
#include "stat_cache.h"
35

  
36
#include "plugin.h"
37

  
38
#include "crc32.h"
39
#include "etag.h"
40
#include "inet_ntop_cache.h"
41

  
42
#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
43
# define USE_ZLIB
44
# include <zlib.h>
45
#else
46
# define Z_DEFAULT_COMPRESSION 1
47
#endif
48

  
49
#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
50
# define USE_BZ2LIB
51
/* we don't need stdio interface */
52
# define BZ_NO_STDIO
53
# include <bzlib.h>
54
#endif
55

  
56
#include "sys-mmap.h"
57

  
58
/* request: accept-encoding */
59
#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
60
#define HTTP_ACCEPT_ENCODING_GZIP     BV(1)
61
#define HTTP_ACCEPT_ENCODING_DEFLATE  BV(2)
62
#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3)
63
#define HTTP_ACCEPT_ENCODING_BZIP2    BV(4)
64

  
65
#define KByte * 1024
66
#define MByte * 1024 KByte
67
#define GByte * 1024 MByte
68

  
69
typedef struct {
70
	unsigned short	debug;
71
	unsigned short	enabled;
72
	unsigned short	bzip2;
73
	unsigned short	sync_flush;
74
	unsigned short	output_buffer_size;
75
	unsigned short	min_compress_size;
76
	unsigned short	work_block_size;
77
	short		mem_level;
78
	short		compression_level;
79
	short		window_size;
80
	array		*mimetypes;
81
	buffer 		*nocompress_url;
82
#if defined(HAVE_PCRE_H)
83
	pcre	*nocompress_regex;
84
#endif
85
} plugin_config;
86

  
87
typedef struct {
88
	PLUGIN_DATA;
89
	buffer *tmp_buf;
90
	
91
	plugin_config **config_storage;
92
	plugin_config conf; 
93
} plugin_data;
94

  
95
typedef struct {
96
	int bytes_in;
97
	int bytes_out;
98
	chunkqueue *in_queue;
99
	buffer *output;
100
	/* compression type & state */
101
	int compression_type;
102
	int stream_open;
103
#ifdef USE_ZLIB
104
	unsigned long crc;
105
	z_stream z;
106
	unsigned short gzip_header;
107
#endif
108
#ifdef USE_BZ2LIB
109
	bz_stream bz;
110
#endif
111
	plugin_data *plugin_data;
112
} handler_ctx;
113

  
114
static handler_ctx *handler_ctx_init() {
115
	handler_ctx *hctx;
116

  
117
	hctx = calloc(1, sizeof(*hctx));
118
	hctx->in_queue = chunkqueue_init();
119

  
120
	return hctx;
121
}
122

  
123
static void handler_ctx_free(handler_ctx *hctx) {
124
	chunkqueue_free(hctx->in_queue);
125
	free(hctx);
126
}
127

  
128
INIT_FUNC(mod_deflate_init) {
129
	plugin_data *p;
130
	
131
	p = calloc(1, sizeof(*p));
132

  
133
	p->tmp_buf = buffer_init();
134
	
135
	return p;
136
}
137

  
138
FREE_FUNC(mod_deflate_free) {
139
	plugin_data *p = p_d;
140
	
141
	UNUSED(srv);
142

  
143
	if (!p) return HANDLER_GO_ON;
144
	
145
	if (p->config_storage) {
146
		size_t i;
147
		for (i = 0; i < srv->config_context->used; i++) {
148
			plugin_config *s = p->config_storage[i];
149

  
150
			if (!s) continue;
151
			
152
			array_free(s->mimetypes);
153
			buffer_free(s->nocompress_url);
154
#if defined(HAVE_PCRE_H)
155
		       	if (s->nocompress_regex) pcre_free(s->nocompress_regex);
156
#endif
157
			free(s);
158
		}
159
		free(p->config_storage);
160
	}
161

  
162
	buffer_free(p->tmp_buf);
163
	
164
	free(p);
165
	
166
	return HANDLER_GO_ON;
167
}
168

  
169
SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
170
	plugin_data *p = p_d;
171
	size_t i = 0;
172
	
173
	config_values_t cv[] = { 
174
		{ "deflate.output-buffer-size",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
175
		{ "deflate.mimetypes",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
176
		{ "deflate.compression-level",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
177
		{ "deflate.mem-level",             NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
178
		{ "deflate.window-size",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
179
		{ "deflate.min-compress-size",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
180
		{ "deflate.work-block-size",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
181
		{ "deflate.enabled",               NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
182
		{ "deflate.debug",                 NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
183
		{ "deflate.bzip2",                 NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
184
		{ "deflate.sync-flush",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
185
		{ "deflate.nocompress-url",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
186
		{ NULL,                            NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
187
	};
188
	
189
	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
190
	
191
	for (i = 0; i < srv->config_context->used; i++) {
192
		plugin_config *s;
193
#if defined(HAVE_PCRE_H)
194
		const char *errptr;
195
		int erroff;
196
#endif
197
		
198
		s = calloc(1, sizeof(plugin_config));
199
		s->enabled = 1;
200
		s->bzip2 = 1;
201
		s->sync_flush = 0;
202
		s->debug = 0;
203
		s->output_buffer_size = 0;
204
		s->mem_level = 9;
205
		s->window_size = 15;
206
		s->min_compress_size = 0;
207
		s->work_block_size = 2048;
208
		s->compression_level = Z_DEFAULT_COMPRESSION;
209
		s->mimetypes = array_init();
210
		s->nocompress_url = buffer_init();
211
#if defined(HAVE_PCRE_H)
212
		s->nocompress_regex = NULL;
213
#endif
214

  
215
		cv[0].destination = &(s->output_buffer_size);
216
		cv[1].destination = s->mimetypes;
217
		cv[2].destination = &(s->compression_level);
218
		cv[3].destination = &(s->mem_level);
219
		cv[4].destination = &(s->window_size);
220
		cv[5].destination = &(s->min_compress_size);
221
		cv[6].destination = &(s->work_block_size);
222
		cv[7].destination = &(s->enabled);
223
		cv[8].destination = &(s->debug);
224
		cv[9].destination = &(s->bzip2);
225
		cv[10].destination = &(s->sync_flush);
226
		cv[11].destination = s->nocompress_url;
227
		
228
		p->config_storage[i] = s;
229
	
230
		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
231
			return HANDLER_ERROR;
232
		}
233

  
234
#if defined(HAVE_PCRE_H)		
235
		if (!buffer_is_empty(s->nocompress_url)) {
236
			if (NULL == (s->nocompress_regex = pcre_compile(s->nocompress_url->ptr,
237
								      0, &errptr, &erroff, NULL))) {
238
				
239
				log_error_write(srv, __FILE__, __LINE__, "sbss", 
240
						"compiling regex for nocompress-url failed:", 
241
						s->nocompress_url, "pos:", erroff);
242
				return HANDLER_ERROR;
243
			}
244
		}
245
#endif
246
		if((s->compression_level < 1 || s->compression_level > 9) &&
247
				s->compression_level != Z_DEFAULT_COMPRESSION) {
248
			log_error_write(srv, __FILE__, __LINE__, "sd", 
249
				"compression-level must be between 1 and 9:", s->compression_level);
250
			return HANDLER_ERROR;
251
		}
252

  
253
		if(s->mem_level < 1 || s->mem_level > 9) {
254
			log_error_write(srv, __FILE__, __LINE__, "sd", 
255
				"mem-level must be between 1 and 9:", s->mem_level);
256
			return HANDLER_ERROR;
257
		}
258

  
259
		if(s->window_size < 1 || s->window_size > 15) {
260
			log_error_write(srv, __FILE__, __LINE__, "sd", 
261
				"window-size must be between 1 and 15:", s->window_size);
262
			return HANDLER_ERROR;
263
		}
264
		s->window_size = 0 - s->window_size;
265

  
266
		if(s->sync_flush) {
267
			s->output_buffer_size = 0;
268
		}
269
	}
270
	
271
	return HANDLER_GO_ON;
272
	
273
}
274

  
275
#ifdef USE_ZLIB
276
/* Copied gzip_header from apache 2.2's mod_deflate.c */
277
/* RFC 1952 Section 2.3 defines the gzip header:
278
 *
279
 * +---+---+---+---+---+---+---+---+---+---+
280
 * |ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
281
 * +---+---+---+---+---+---+---+---+---+---+
282
 */
283
static const char gzip_header[10] =
284
{ '\037', '\213', Z_DEFLATED, 0,
285
  0, 0, 0, 0, /* mtime */
286
  0, 0x03 /* Unix OS_CODE */
287
};
288
static int stream_deflate_init(server *srv, connection *con, handler_ctx *hctx) {
289
	plugin_data *p = hctx->plugin_data;
290
	z_stream *z;
291

  
292
	UNUSED(srv);
293
	UNUSED(con);
294

  
295
	z = &(hctx->z);
296
	z->zalloc = Z_NULL;
297
	z->zfree = Z_NULL;
298
	z->opaque = Z_NULL;
299
	z->total_in = 0;
300
	z->total_out = 0;
301
	z->next_out = NULL;
302
	z->avail_out = 0;
303
	
304
	if(p->conf.debug) {
305
		log_error_write(srv, __FILE__, __LINE__, "sd", 
306
			"output-buffer-size:", p->conf.output_buffer_size);
307
		log_error_write(srv, __FILE__, __LINE__, "sd", 
308
			"compression-level:", p->conf.compression_level);
309
		log_error_write(srv, __FILE__, __LINE__, "sd", 
310
			"mem-level:", p->conf.mem_level);
311
		log_error_write(srv, __FILE__, __LINE__, "sd", 
312
			"window-size:", p->conf.window_size);
313
		log_error_write(srv, __FILE__, __LINE__, "sd", 
314
			"min-compress-size:", p->conf.min_compress_size);
315
		log_error_write(srv, __FILE__, __LINE__, "sd", 
316
			"work-block-size:", p->conf.work_block_size);
317
	}
318
	if (Z_OK != deflateInit2(z, 
319
				 p->conf.compression_level,
320
				 Z_DEFLATED, 
321
				 p->conf.window_size,  /* supress zlib-header */
322
				 p->conf.mem_level,
323
				 Z_DEFAULT_STRATEGY)) {
324
		return -1;
325
	}
326
	hctx->stream_open = 1;
327
		
328
	return 0;
329
}
330

  
331
static int stream_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
332
	plugin_data *p = hctx->plugin_data;
333
	z_stream *z;
334
	int len;
335
	int in = 0, out = 0;
336

  
337
	UNUSED(srv);
338
	z = &(hctx->z);
339

  
340
	if(z->next_out == NULL) {
341
		z->next_out = (unsigned char *)hctx->output->ptr;
342
		z->avail_out = hctx->output->size;
343
	}
344
	
345
	if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP) {
346
		if(hctx->gzip_header == 0) {
347
			hctx->gzip_header = 1;
348
			/* copy gzip header into output buffer */
349
			buffer_copy_memory(hctx->output, gzip_header, sizeof(gzip_header));
350
			if(p->conf.debug) {
351
				log_error_write(srv, __FILE__, __LINE__, "sd",
352
						"gzip_header len=", sizeof(gzip_header));
353
			}
354
			/* initialize crc32 */
355
			hctx->crc = crc32(0L, Z_NULL, 0);
356
			z->next_out = (unsigned char *)(hctx->output->ptr + sizeof(gzip_header));
357
			z->avail_out = hctx->output->size - sizeof(gzip_header);
358
		}
359
		hctx->crc = crc32(hctx->crc, start, st_size);
360
	}
361

  
362
	z->next_in = start;
363
	z->avail_in = st_size;
364
	hctx->bytes_in += st_size;
365
		
366
	/* compress data */
367
	in = z->avail_in;
368
	do {
369
		if (Z_OK != deflate(z, Z_NO_FLUSH)) {
370
			deflateEnd(z);
371
			hctx->stream_open = 0;
372
			return -1;
373
		}
374

  
375
		if(z->avail_out == 0 || z->avail_in > 0) {
376
			len = hctx->output->size - z->avail_out;
377
			hctx->bytes_out += len;
378
			out += len;
379
			chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
380
			z->next_out = (unsigned char *)hctx->output->ptr;
381
			z->avail_out = hctx->output->size;
382
		}
383
	} while (z->avail_in > 0);
384

  
385
	if(p->conf.debug) {
386
		log_error_write(srv, __FILE__, __LINE__, "sdsd",
387
				"compress: in=", in, ", out=", out);
388
	}
389
	return 0;
390
}
391

  
392
static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
393
	plugin_data *p = hctx->plugin_data;
394
	z_stream *z;
395
	int len;
396
	int rc = 0;
397
	int done;
398
	int flush = 1;
399
	int in = 0, out = 0;
400

  
401
	UNUSED(srv);
402

  
403
	z = &(hctx->z);
404

  
405
	if(z->next_out == NULL) {
406
		z->next_out = (unsigned char *)hctx->output->ptr;
407
		z->avail_out = hctx->output->size;
408
	}
409
	/* compress data */
410
	in = z->avail_in;
411
	do {
412
		done = 1;
413
		if(end) {
414
			rc = deflate(z, Z_FINISH);
415
			if (rc == Z_OK) {
416
				done = 0;
417
			} else if (rc != Z_STREAM_END) {
418
				deflateEnd(z);
419
				hctx->stream_open = 0;
420
				return -1;
421
			}
422
		} else {
423
			if(p->conf.sync_flush) {
424
				rc = deflate(z, Z_SYNC_FLUSH);
425
			} else if(z->avail_in > 0) {
426
				if(p->conf.output_buffer_size > 0) flush = 0;
427
				rc = deflate(z, Z_NO_FLUSH);
428
			} else {
429
				if(p->conf.output_buffer_size > 0) flush = 0;
430
				rc = Z_OK;
431
			}
432
			if (rc != Z_OK) {
433
				deflateEnd(z);
434
				hctx->stream_open = 0;
435
				return -1;
436
			}
437
		}
438

  
439
		len = hctx->output->size - z->avail_out;
440
		if(z->avail_out == 0 || (flush && len > 0)) {
441
			hctx->bytes_out += len;
442
			out += len;
443
			chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
444
			z->next_out = (unsigned char *)hctx->output->ptr;
445
			z->avail_out = hctx->output->size;
446
		}
447
	} while (z->avail_in != 0 || !done);
448

  
449

  
450
	if(p->conf.debug) {
451
		log_error_write(srv, __FILE__, __LINE__, "sdsd",
452
				"flush: in=", in, ", out=", out);
453
	}
454
	if(p->conf.sync_flush) {
455
		z->next_out = NULL;
456
		z->avail_out = 0;
457
	}
458
	return 0;
459
}
460

  
461
static int stream_deflate_end(server *srv, connection *con, handler_ctx *hctx) {
462
	plugin_data *p = hctx->plugin_data;
463
	z_stream *z;
464
	int rc;
465

  
466
	UNUSED(srv);
467

  
468
	z = &(hctx->z);
469
	if(!hctx->stream_open) return 0;
470
	hctx->stream_open = 0;
471

  
472
	if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP && hctx->bytes_out > 0 &&
473
			(unsigned int )hctx->bytes_out >= sizeof(gzip_header)) {
474
		/* write gzip footer */
475
		unsigned char c[8];
476

  
477
		c[0] = (hctx->crc >>  0) & 0xff;
478
		c[1] = (hctx->crc >>  8) & 0xff;
479
		c[2] = (hctx->crc >> 16) & 0xff;
480
		c[3] = (hctx->crc >> 24) & 0xff;
481
		c[4] = (z->total_in >>  0) & 0xff;
482
		c[5] = (z->total_in >>  8) & 0xff;
483
		c[6] = (z->total_in >> 16) & 0xff;
484
		c[7] = (z->total_in >> 24) & 0xff;
485
		/* append footer to write_queue */
486
		chunkqueue_append_mem(con->write_queue, (char *)c, 9);
487
		hctx->bytes_out += 8;
488
		if(p->conf.debug) {
489
			log_error_write(srv, __FILE__, __LINE__, "sd",
490
					"gzip_footer len=", 8);
491
		}
492
	}
493

  
494
	if ((rc = deflateEnd(z)) != Z_OK) {
495
		if(rc == Z_DATA_ERROR) return 0;
496
		if(z->msg != NULL) {
497
			log_error_write(srv, __FILE__, __LINE__, "sdss",
498
					"deflateEnd error ret=", rc, ", msg=", z->msg);
499
		} else {
500
			log_error_write(srv, __FILE__, __LINE__, "sd",
501
					"deflateEnd error ret=", rc);
502
		}
503
		return -1;
504
	}
505
	return 0;
506
}
507

  
508
#endif
509

  
510
#ifdef USE_BZ2LIB
511
static int stream_bzip2_init(server *srv, connection *con, handler_ctx *hctx) {
512
	plugin_data *p = hctx->plugin_data;
513
	bz_stream *bz;
514

  
515
	UNUSED(srv);
516
	UNUSED(con);
517

  
518
	bz = &(hctx->bz);
519
	bz->bzalloc = NULL;
520
	bz->bzfree = NULL;
521
	bz->opaque = NULL;
522
	bz->total_in_lo32 = 0;
523
	bz->total_in_hi32 = 0;
524
	bz->total_out_lo32 = 0;
525
	bz->total_out_hi32 = 0;
526
	
527
	if(p->conf.debug) {
528
		log_error_write(srv, __FILE__, __LINE__, "sd", 
529
			"output-buffer-size:", p->conf.output_buffer_size);
530
		log_error_write(srv, __FILE__, __LINE__, "sd", 
531
			"compression-level:", p->conf.compression_level);
532
		log_error_write(srv, __FILE__, __LINE__, "sd", 
533
			"mem-level:", p->conf.mem_level);
534
		log_error_write(srv, __FILE__, __LINE__, "sd", 
535
			"window-size:", p->conf.window_size);
536
		log_error_write(srv, __FILE__, __LINE__, "sd", 
537
			"min-compress-size:", p->conf.min_compress_size);
538
		log_error_write(srv, __FILE__, __LINE__, "sd", 
539
			"work-block-size:", p->conf.work_block_size);
540
	}
541
	if (BZ_OK != BZ2_bzCompressInit(bz, 
542
					p->conf.compression_level, /* blocksize = 900k */
543
					0, /* no output */
544
					30)) { /* workFactor: default */
545
		return -1;
546
	}
547
	hctx->stream_open = 1;
548
		
549
	return 0;
550
}
551

  
552
static int stream_bzip2_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
553
	plugin_data *p = hctx->plugin_data;
554
	bz_stream *bz;
555
	int len;
556
	int rc;
557
	int in = 0, out = 0;
558

  
559
	UNUSED(srv);
560

  
561
	bz = &(hctx->bz);
562

  
563
	if(bz->next_out == NULL) {
564
		bz->next_out = hctx->output->ptr;
565
		bz->avail_out = hctx->output->size;
566
	}
567
	
568
	bz->next_in = (char *)start;
569
	bz->avail_in = st_size;
570
	hctx->bytes_in += st_size;
571
		
572
	/* compress data */
573
	in = bz->avail_in;
574
	do {
575
		rc = BZ2_bzCompress(bz, BZ_RUN);
576
		if (rc != BZ_RUN_OK) {
577
			BZ2_bzCompressEnd(bz);
578
			hctx->stream_open = 0;
579
			return -1;
580
		}
581

  
582
		if(bz->avail_out == 0 || bz->avail_in > 0) {
583
			len = hctx->output->size - bz->avail_out;
584
			hctx->bytes_out += len;
585
			out += len;
586
			chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
587
			bz->next_out = hctx->output->ptr;
588
			bz->avail_out = hctx->output->size;
589
		}
590
	} while (bz->avail_in > 0);
591
	if(p->conf.debug) {
592
		log_error_write(srv, __FILE__, __LINE__, "sdsd",
593
				"compress: in=", in, ", out=", out);
594
	}
595
	return 0;
596
}
597

  
598
static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
599
	plugin_data *p = hctx->plugin_data;
600
	bz_stream *bz;
601
	int len;
602
	int rc;
603
	int done;
604
	int flush = 1;
605
	int in = 0, out = 0;
606

  
607
	UNUSED(srv);
608

  
609
	bz = &(hctx->bz);
610

  
611
	if(bz->next_out == NULL) {
612
		bz->next_out = hctx->output->ptr;
613
		bz->avail_out = hctx->output->size;
614
	}
615
	/* compress data */
616
	in = bz->avail_in;
617
	do {
618
		done = 1;
619
		if(end) {
620
			rc = BZ2_bzCompress(bz, BZ_FINISH);
621
			if (rc == BZ_FINISH_OK) {
622
				done = 0;
623
			} else if (rc != BZ_STREAM_END) {
624
				BZ2_bzCompressEnd(bz);
625
				hctx->stream_open = 0;
626
				return -1;
627
			}
628
		} else if(bz->avail_in > 0) {
629
			rc = BZ2_bzCompress(bz, BZ_RUN);
630
			if (rc != BZ_RUN_OK) {
631
				BZ2_bzCompressEnd(bz);
632
				hctx->stream_open = 0;
633
				return -1;
634
			}
635
			if(p->conf.output_buffer_size > 0) flush = 0;
636
		}
637

  
638
		len = hctx->output->size - bz->avail_out;
639
		if(bz->avail_out == 0 || (flush && len > 0)) {
640
			hctx->bytes_out += len;
641
			out += len;
642
			chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1);
643
			bz->next_out = hctx->output->ptr;
644
			bz->avail_out = hctx->output->size;
645
		}
646
	} while (bz->avail_in != 0 || !done);
647
	if(p->conf.debug) {
648
		log_error_write(srv, __FILE__, __LINE__, "sdsd",
649
				"flush: in=", in, ", out=", out);
650
	}
651
	if(p->conf.sync_flush) {
652
		bz->next_out = NULL;
653
		bz->avail_out = 0;
654
	}
655
	return 0;
656
}
657

  
658
static int stream_bzip2_end(server *srv, connection *con, handler_ctx *hctx) {
659
	plugin_data *p = hctx->plugin_data;
660
	bz_stream *bz;
661
	int rc;
662

  
663
	UNUSED(p);
664
	UNUSED(con);
665

  
666
	bz = &(hctx->bz);
667
	if(!hctx->stream_open) return 0;
668
	hctx->stream_open = 0;
669

  
670
	if ((rc = BZ2_bzCompressEnd(bz)) != BZ_OK) {
671
		if(rc == BZ_DATA_ERROR) return 0;
672
		log_error_write(srv, __FILE__, __LINE__, "sd",
673
				"BZ2_bzCompressEnd error ret=", rc);
674
		return -1;
675
	}
676
	return 0;
677
}
678

  
679
#endif
680

  
681
static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
682
	int ret = -1;
683
	if(st_size == 0) return 0;
684
	switch(hctx->compression_type) {
685
#ifdef USE_ZLIB
686
	case HTTP_ACCEPT_ENCODING_GZIP: 
687
	case HTTP_ACCEPT_ENCODING_DEFLATE: 
688
		ret = stream_deflate_compress(srv, con, hctx, start, st_size);
689
		break;
690
#endif
691
#ifdef USE_BZ2LIB
692
	case HTTP_ACCEPT_ENCODING_BZIP2: 
693
		ret = stream_bzip2_compress(srv, con, hctx, start, st_size);
694
		break;
695
#endif
696
	default:
697
		ret = -1;
698
		break;
699
	}
700

  
701
	return ret;
702
}
703

  
704
static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
705
	int ret = -1;
706
	if(hctx->bytes_in == 0) return 0;
707
	switch(hctx->compression_type) {
708
#ifdef USE_ZLIB
709
	case HTTP_ACCEPT_ENCODING_GZIP: 
710
	case HTTP_ACCEPT_ENCODING_DEFLATE: 
711
		ret = stream_deflate_flush(srv, con, hctx, end);
712
		break;
713
#endif
714
#ifdef USE_BZ2LIB
715
	case HTTP_ACCEPT_ENCODING_BZIP2: 
716
		ret = stream_bzip2_flush(srv, con, hctx, end);
717
		break;
718
#endif
719
	default:
720
		ret = -1;
721
		break;
722
	}
723

  
724
	return ret;
725
}
726

  
727
static int mod_deflate_stream_end(server *srv, connection *con, handler_ctx *hctx) {
728
	int ret = -1;
729
	switch(hctx->compression_type) {
730
#ifdef USE_ZLIB
731
	case HTTP_ACCEPT_ENCODING_GZIP: 
732
	case HTTP_ACCEPT_ENCODING_DEFLATE: 
733
		ret = stream_deflate_end(srv, con, hctx);
734
		break;
735
#endif
736
#ifdef USE_BZ2LIB
737
	case HTTP_ACCEPT_ENCODING_BZIP2: 
738
		ret = stream_bzip2_end(srv, con, hctx);
739
		break;
740
#endif
741
	default:
742
		ret = -1;
743
		break;
744
	}
745

  
746
	return ret;
747
}
748

  
749
static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hctx, chunk *c, off_t st_size) {
750
	plugin_data *p = hctx->plugin_data;
751
	off_t abs_offset;
752
	off_t toSend;
753
	stat_cache_entry *sce = NULL;
754
	off_t we_want_to_mmap = 2 MByte; 
755
	off_t we_want_to_send = st_size;
756
	char *start = NULL;
757

  
758
	if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
759
		log_error_write(srv, __FILE__, __LINE__, "sb",
760
				strerror(errno), c->file.name);
761
		return -1;
762
	}
763

  
764
	abs_offset = c->file.start + c->offset;
765
	
766
	if (abs_offset > sce->st.st_size) {
767
		log_error_write(srv, __FILE__, __LINE__, "sb", 
768
				"file was shrinked:", c->file.name);
769
		
770
		return -1;
771
	}
772

  
773
	we_want_to_send = st_size;
774
	/* mmap the buffer 
775
	 * - first mmap 
776
	 * - new mmap as the we are at the end of the last one */
777
	if (c->file.mmap.start == MAP_FAILED ||
778
	    abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
779

  
780
		/* Optimizations for the future:
781
		 *
782
		 * adaptive mem-mapping
783
		 *   the problem:
784
		 *     we mmap() the whole file. If someone has alot large files and 32bit
785
		 *     machine the virtual address area will be unrun and we will have a failing 
786
		 *     mmap() call.
787
		 *   solution:
788
		 *     only mmap 16M in one chunk and move the window as soon as we have finished
789
		 *     the first 8M
790
		 *
791
		 * read-ahead buffering
792
		 *   the problem:
793
		 *     sending out several large files in parallel trashes the read-ahead of the
794
		 *     kernel leading to long wait-for-seek times.
795
		 *   solutions: (increasing complexity)
796
		 *     1. use madvise
797
		 *     2. use a internal read-ahead buffer in the chunk-structure
798
		 *     3. use non-blocking IO for file-transfers
799
		 *   */
800

  
801
		/* all mmap()ed areas are 512kb expect the last which might be smaller */
802
		size_t to_mmap;
803

  
804
		/* this is a remap, move the mmap-offset */
805
		if (c->file.mmap.start != MAP_FAILED) {
806
			munmap(c->file.mmap.start, c->file.mmap.length);
807
			c->file.mmap.offset += we_want_to_mmap;
808
		} else {
809
			/* in case the range-offset is after the first mmap()ed area we skip the area */
810
			c->file.mmap.offset = 0;
811

  
812
			while (c->file.mmap.offset + we_want_to_mmap < c->file.start) {
813
				c->file.mmap.offset += we_want_to_mmap;
814
			}
815
		}
816

  
817
		/* length is rel, c->offset too, assume there is no limit at the mmap-boundaries */
818
		to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset;
819
		if(to_mmap > we_want_to_mmap) to_mmap = we_want_to_mmap;
820
		/* we have more to send than we can mmap() at once */
821
		if(we_want_to_send > to_mmap) we_want_to_send = to_mmap;
822

  
823
		if (-1 == c->file.fd) {  /* open the file if not already open */
824
			if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
825
				log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
826
		
827
				return -1;
828
			}
829
#ifdef FD_CLOEXEC
830
			fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
831
#endif
832
		}
833

  
834
		if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
835
			/* close it here, otherwise we'd have to set FD_CLOEXEC */
836

  
837
			log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", 
838
					strerror(errno), c->file.name, c->file.fd);
839

  
840
			return -1;
841
		}
842

  
843
		c->file.mmap.length = to_mmap;
844
#ifdef LOCAL_BUFFERING
845
		buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
846
#else
847
#ifdef HAVE_MADVISE
848
		/* don't advise files < 64Kb */
849
		if (c->file.mmap.length > (64 KByte) && 
850
		    0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) {
851
			log_error_write(srv, __FILE__, __LINE__, "ssbd", "madvise failed:", 
852
					strerror(errno), c->file.name, c->file.fd);
853
		}
854
#endif
855
#endif
856

  
857
		/* chunk_reset() or chunk_free() will cleanup for us */
858
	}
859

  
860
	/* to_send = abs_mmap_end - abs_offset */
861
	toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
862
	if(toSend > we_want_to_send) toSend = we_want_to_send;
863

  
864
	if (toSend < 0) {
865
		log_error_write(srv, __FILE__, __LINE__, "soooo", 
866
				"toSend is negative:",
867
				toSend,
868
				c->file.mmap.length,
869
				abs_offset,
870
				c->file.mmap.offset); 
871
		assert(toSend < 0);
872
	}
873

  
874
#ifdef LOCAL_BUFFERING
875
	start = c->mem->ptr;
876
#else
877
	start = c->file.mmap.start;
878
#endif
879

  
880
	if(p->conf.debug) {
881
		log_error_write(srv, __FILE__, __LINE__, "sdsd",
882
				"compress file chunk: offset=", (int)c->offset,
883
				", toSend=", (int)toSend);
884
	}
885
	if (mod_deflate_compress(srv, con, hctx,
886
				(unsigned char *)start + (abs_offset - c->file.mmap.offset), toSend) < 0) {
887
		log_error_write(srv, __FILE__, __LINE__, "s", 
888
				"compress failed.");
889
		return -1;
890
	}
891

  
892
	c->offset += toSend;
893
	if (c->offset == c->file.length) {
894
		/* we don't need the mmaping anymore */
895
		if (c->file.mmap.start != MAP_FAILED) {
896
			munmap(c->file.mmap.start, c->file.mmap.length);
897
			c->file.mmap.start = MAP_FAILED;
898
		}
899
	}
900

  
901
	return toSend;
902
}
903

  
904
static int deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) {
905
	plugin_data *p = hctx->plugin_data;
906
	int rc;
907

  
908
	rc = mod_deflate_stream_end(srv, con, hctx);
909
	if(rc < 0) {
910
		log_error_write(srv, __FILE__, __LINE__, "s", "error closing stream");
911
	}
912

  
913
	if (hctx->bytes_in < hctx->bytes_out) {
914
		log_error_write(srv, __FILE__, __LINE__, "sbsdsd",
915
				"uri ", con->uri.path_raw, " in=", hctx->bytes_in, " smaller than out=", hctx->bytes_out);
916
	}
917

  
918
	if(p->conf.debug) {
919
		log_error_write(srv, __FILE__, __LINE__, "sdsd",
920
				" in:", hctx->bytes_in,
921
				" out:", hctx->bytes_out);
922
	}
923

  
924
	/* cleanup compression state */
925
	if(hctx->output != p->tmp_buf) {
926
		buffer_free(hctx->output);
927
	}
928
	handler_ctx_free(hctx);
929
	con->plugin_ctx[p->id] = NULL;
930

  
931
	return 0;
932
}
933

  
934
static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx, int end) { 
935
	plugin_data *p = hctx->plugin_data;
936
	chunk *c;
937
	size_t chunks_written = 0;
... This diff was truncated because it exceeds the maximum size that can be displayed.
(3-3/11)