From: Marcin Krol Date: Tue, 7 Apr 2015 18:12:29 +0000 (+0000) Subject: - from PLD X-Git-Url: https://git.tld-linux.org/?p=packages%2Flighttpd.git;a=commitdiff_plain;h=569e9ab04d516cfbb5f997b9614e20e31e3f8b56 - from PLD --- 569e9ab04d516cfbb5f997b9614e20e31e3f8b56 diff --git a/TODO b/TODO new file mode 100644 index 0000000..ec6495d --- /dev/null +++ b/TODO @@ -0,0 +1,29 @@ +# TODO: +- test mysql (failed at this time) +- mysql issue: http://www.freebsd.org/cgi/query-pr.cgi?pr=76866 +- fam over gamin is possible, just configure doesn't check other than gamin +- feature stat-cache-fam (doesn't work) +- lighttpd writes early startup messages to stderr, and if started from + rc-scripts the stderr is closed which causes lighttpd to abort(): + 2006-07-20 21:05:52: (server.c.1233) WARNING: unknown config-key: url.rewrite-final (ignored) + +# NOTES: +- disable largefile, if you have 2.4 kernel to get sendfile() support, and don't need > 2GB file requests, + see http://article.gmane.org/gmane.comp.web.lighttpd:722 + + +01:08:45 stbuehler> glen: http://redmine.lighttpd.net/projects/lighttpd/repository/revisions/2505 +01:09:57 glen> stbuehler: ah sorry, i didn't notice as you didn't reply (hilite) me here.. +01:13:52 glen> stbuehler: btw, what you think of this patch: + http://cvs.pld-linux.org/cgi-bin/cvsweb.cgi/packages/lighttpd/lighttpd-mod_evasive-status_code.patch +01:17:52 stbuehler> the buffer_prepare_copy isn't really needed imho (and 255 seems to much for a long anyway) +01:18:11 stbuehler> and wasn't there a srv->tmp_buf for such things? +01:18:58 glen> ok i see it changes default 403 -> 503, that's probably bad too? +01:19:26 stbuehler> apart from that it looks good to me, although it changes the default status code to 503; and perhaps retry-after should + only be returned if it is not zero (i don't know what the rfc says) +01:19:51 >> OpenURL 9 +01:19:51 Tobsn> http://government.zdnet.com/?p=4792 +01:20:25 stbuehler> i think 503 is a sane default and better than 403, so it should be ok to change the default +01:21:54 stbuehler> gn8 + + diff --git a/branch.sh b/branch.sh new file mode 100644 index 0000000..4a0e8f8 --- /dev/null +++ b/branch.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e +svn=svn://svn.lighttpd.net/lighttpd +p=lighttpd +v=1.5 + +svn co $svn/trunk $p-$v +r=$(svnversion $p-$v) +t=$p-r$r.tar.bz2 +tar -cjf $t --exclude-vcs $p-$v +../dropin $t & diff --git a/env-documentroot.patch b/env-documentroot.patch new file mode 100644 index 0000000..eea738e --- /dev/null +++ b/env-documentroot.patch @@ -0,0 +1,69 @@ +revert: + +- * [*cgi] Use physical base dir (alias, userdir) as DOCUMENT_ROOT in cgi environments (fixes #2216) + +Index: src/mod_fastcgi.c +=================================================================== +--- src/mod_fastcgi.c (revision 2794) ++++ src/mod_fastcgi.c (revision 2793) +@@ -1968,7 +1968,7 @@ + if (!buffer_is_empty(host->docroot)) { + buffer_copy_string_buffer(p->path, host->docroot); + } else { +- buffer_copy_string_buffer(p->path, con->physical.basedir); ++ buffer_copy_string_buffer(p->path, con->physical.doc_root); + } + buffer_append_string_buffer(p->path, con->request.pathinfo); + FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con) +@@ -2008,7 +2008,7 @@ + } + + FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con) +- FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con) ++ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)),con) + } + + if (host->strip_request_uri->used > 1) { +@@ -3273,7 +3273,6 @@ + */ + + buffer_copy_string_buffer(con->physical.doc_root, host->docroot); +- buffer_copy_string_buffer(con->physical.basedir, host->docroot); + + buffer_copy_string_buffer(con->physical.path, host->docroot); + buffer_append_string_buffer(con->physical.path, con->uri.path); +Index: src/mod_scgi.c +=================================================================== +--- src/mod_scgi.c (revision 2794) ++++ src/mod_scgi.c (revision 2793) +@@ -1558,7 +1558,7 @@ + if (!buffer_is_empty(host->docroot)) { + buffer_copy_string_buffer(p->path, host->docroot); + } else { +- buffer_copy_string_buffer(p->path, con->physical.basedir); ++ buffer_copy_string_buffer(p->path, con->physical.doc_root); + } + buffer_append_string_buffer(p->path, con->request.pathinfo); + scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)); +@@ -1589,7 +1589,7 @@ + buffer_copy_string_buffer(p->path, con->physical.path); + + scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)); +- scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)); ++ scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)); + } + scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); + if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) { +Index: src/mod_cgi.c +=================================================================== +--- src/mod_cgi.c (revision 2794) ++++ src/mod_cgi.c (revision 2793) +@@ -928,7 +928,7 @@ + cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)); + cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); + cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); +- cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)); ++ cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)); + + /* for valgrind */ + if (NULL != (s = getenv("LD_PRELOAD"))) { diff --git a/lighttpd-branch.diff b/lighttpd-branch.diff new file mode 100644 index 0000000..76f06ce --- /dev/null +++ b/lighttpd-branch.diff @@ -0,0 +1,1957 @@ +# Revision 2815 +Index: src/http_auth_digest.c +=================================================================== +--- src/http_auth_digest.c (.../tags/lighttpd-1.4.29) ++++ src/http_auth_digest.c (.../branches/lighttpd-1.4.x) +@@ -1,26 +0,0 @@ +-#include "buffer.h" +- +-#include "http_auth_digest.h" +- +-#include +- +-#ifndef USE_OPENSSL +-# include "md5.h" +- +-typedef li_MD5_CTX MD5_CTX; +-#define MD5_Init li_MD5_Init +-#define MD5_Update li_MD5_Update +-#define MD5_Final li_MD5_Final +- +-#endif +- +-void CvtHex(IN HASH Bin, OUT HASHHEX Hex) { +- unsigned short i; +- +- for (i = 0; i < HASHLEN; i++) { +- Hex[i*2] = int2hex((Bin[i] >> 4) & 0xf); +- Hex[i*2+1] = int2hex(Bin[i] & 0xf); +- } +- Hex[HASHHEXLEN] = '\0'; +-} +- +Index: src/http_auth_digest.h +=================================================================== +--- src/http_auth_digest.h (.../tags/lighttpd-1.4.29) ++++ src/http_auth_digest.h (.../branches/lighttpd-1.4.x) +@@ -1,24 +0,0 @@ +-#ifndef _DIGCALC_H_ +-#define _DIGCALC_H_ +- +-#ifdef HAVE_CONFIG_H +-# include "config.h" +-#endif +- +-#define HASHLEN 16 +-typedef unsigned char HASH[HASHLEN]; +-#define HASHHEXLEN 32 +-typedef char HASHHEX[HASHHEXLEN+1]; +-#ifdef USE_OPENSSL +-#define IN const +-#else +-#define IN +-#endif +-#define OUT +- +-void CvtHex( +- IN HASH Bin, +- OUT HASHHEX Hex +- ); +- +-#endif +Index: src/network_write.c +=================================================================== +--- src/network_write.c (.../tags/lighttpd-1.4.29) ++++ src/network_write.c (.../branches/lighttpd-1.4.x) +@@ -24,17 +24,16 @@ + # include + #endif + +-int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) { ++int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { + chunk *c; +- size_t chunks_written = 0; + +- for(c = cq->first; c; c = c->next) { ++ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { + int chunk_finished = 0; + + switch(c->type) { + case MEM_CHUNK: { + char * offset; +- size_t toSend; ++ off_t toSend; + ssize_t r; + + if (c->mem->used == 0) { +@@ -44,6 +43,8 @@ + + offset = c->mem->ptr + c->offset; + toSend = c->mem->used - 1 - c->offset; ++ if (toSend > max_bytes) toSend = max_bytes; ++ + #ifdef __WIN32 + if ((r = send(fd, offset, toSend, 0)) < 0) { + /* no error handling for windows... */ +@@ -72,6 +73,7 @@ + + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + + if (c->offset == (off_t)c->mem->used - 1) { + chunk_finished = 1; +@@ -85,7 +87,7 @@ + #endif + ssize_t r; + off_t offset; +- size_t toSend; ++ off_t toSend; + stat_cache_entry *sce = NULL; + int ifd; + +@@ -98,6 +100,8 @@ + offset = c->file.start + c->offset; + toSend = c->file.length - c->offset; + ++ if (toSend > max_bytes) toSend = max_bytes; ++ + if (offset > sce->st.st_size) { + log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); + +@@ -181,6 +185,7 @@ + + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + + if (c->offset == c->file.length) { + chunk_finished = 1; +@@ -200,11 +205,9 @@ + + break; + } +- +- chunks_written++; + } + +- return chunks_written; ++ return 0; + } + + #if 0 +Index: src/mod_secure_download.c +=================================================================== +--- src/mod_secure_download.c (.../tags/lighttpd-1.4.29) ++++ src/mod_secure_download.c (.../branches/lighttpd-1.4.x) +@@ -8,18 +8,8 @@ + #include + #include + +-#ifdef USE_OPENSSL +-# include +-#else +-# include "md5.h" ++#include "md5.h" + +-typedef li_MD5_CTX MD5_CTX; +-#define MD5_Init li_MD5_Init +-#define MD5_Update li_MD5_Update +-#define MD5_Final li_MD5_Final +- +-#endif +- + #define HASHLEN 16 + typedef unsigned char HASH[HASHLEN]; + #define HASHHEXLEN 32 +@@ -200,7 +190,7 @@ + + URIHANDLER_FUNC(mod_secdownload_uri_handler) { + plugin_data *p = p_d; +- MD5_CTX Md5Ctx; ++ li_MD5_CTX Md5Ctx; + HASH HA1; + const char *rel_uri, *ts_str, *md5_str; + time_t ts = 0; +@@ -266,9 +256,9 @@ + buffer_append_string(p->md5, rel_uri); + buffer_append_string_len(p->md5, ts_str, 8); + +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1); +- MD5_Final(HA1, &Md5Ctx); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1); ++ li_MD5_Final(HA1, &Md5Ctx); + + buffer_copy_string_hex(p->md5, (char *)HA1, 16); + +Index: src/base.h +=================================================================== +--- src/base.h (.../tags/lighttpd-1.4.29) ++++ src/base.h (.../branches/lighttpd-1.4.x) +@@ -277,6 +277,7 @@ + buffer *ssl_cipher_list; + buffer *ssl_dh_file; + buffer *ssl_ec_curve; ++ unsigned short ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */ + unsigned short ssl_use_sslv2; + unsigned short ssl_use_sslv3; + unsigned short ssl_verifyclient; +@@ -284,6 +285,7 @@ + unsigned short ssl_verifyclient_depth; + buffer *ssl_verifyclient_username; + unsigned short ssl_verifyclient_export_cert; ++ unsigned short ssl_disable_client_renegotiation; + + unsigned short use_ipv6, set_v6only; /* set_v6only is only a temporary option */ + unsigned short defer_accept; +@@ -437,6 +439,7 @@ + # ifndef OPENSSL_NO_TLSEXT + buffer *tlsext_server_name; + # endif ++ unsigned int renegotiations; /* count of SSL_CB_HANDSHAKE_START */ + #endif + /* etag handling */ + etag_flags_t etag_flags; +@@ -647,11 +650,9 @@ + + fdevent_handler_t event_handler; + +- int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq); +- int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq); ++ int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes); + #ifdef USE_OPENSSL +- int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq); +- int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq); ++ int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes); + #endif + + uid_t uid; +Index: src/connections.c +=================================================================== +--- src/connections.c (.../tags/lighttpd-1.4.29) ++++ src/connections.c (.../branches/lighttpd-1.4.x) +@@ -223,6 +223,12 @@ + + len = SSL_read(con->ssl, b->ptr + read_offset, toread); + ++ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { ++ connection_set_state(srv, con, CON_STATE_ERROR); ++ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client"); ++ return -1; ++ } ++ + if (len > 0) { + if (b->used > 0) b->used--; + b->used += len; +@@ -445,6 +451,7 @@ + default: + switch(con->http_status) { + case 400: /* bad request */ ++ case 401: /* authorization required */ + case 414: /* overload request header */ + case 505: /* unknown protocol */ + case 207: /* this was webdav */ +@@ -617,8 +624,9 @@ + } + + static int connection_handle_write(server *srv, connection *con) { +- switch(network_write_chunkqueue(srv, con, con->write_queue)) { ++ switch(network_write_chunkqueue(srv, con, con->write_queue, MAX_WRITE_LIMIT)) { + case 0: ++ con->write_request_ts = srv->cur_ts; + if (con->file_finished) { + connection_set_state(srv, con, CON_STATE_RESPONSE_END); + joblist_append(srv, con); +@@ -635,6 +643,7 @@ + joblist_append(srv, con); + break; + case 1: ++ con->write_request_ts = srv->cur_ts; + con->is_writable = 0; + + /* not finished yet -> WRITE */ +@@ -1251,8 +1260,6 @@ + log_error_write(srv, __FILE__, __LINE__, "ds", + con->fd, + "handle write failed."); +- } else if (con->state == CON_STATE_WRITE) { +- con->write_request_ts = srv->cur_ts; + } + } + +@@ -1352,6 +1359,7 @@ + return NULL; + } + ++ con->renegotiations = 0; + #ifndef OPENSSL_NO_TLSEXT + SSL_set_app_data(con->ssl, con); + #endif +@@ -1667,8 +1675,6 @@ + con->fd, + "handle write failed."); + connection_set_state(srv, con, CON_STATE_ERROR); +- } else if (con->state == CON_STATE_WRITE) { +- con->write_request_ts = srv->cur_ts; + } + } + +Index: src/mod_staticfile.c +=================================================================== +--- src/mod_staticfile.c (.../tags/lighttpd-1.4.29) ++++ src/mod_staticfile.c (.../branches/lighttpd-1.4.x) +@@ -26,6 +26,7 @@ + typedef struct { + array *exclude_ext; + unsigned short etags_used; ++ unsigned short disable_pathinfo; + } plugin_config; + + typedef struct { +@@ -84,6 +85,7 @@ + config_values_t cv[] = { + { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ + { "static-file.etags", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ ++ { "static-file.disable-pathinfo", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } + }; + +@@ -97,9 +99,11 @@ + s = calloc(1, sizeof(plugin_config)); + s->exclude_ext = array_init(); + s->etags_used = 1; ++ s->disable_pathinfo = 0; + + cv[0].destination = s->exclude_ext; + cv[1].destination = &(s->etags_used); ++ cv[2].destination = &(s->disable_pathinfo); + + p->config_storage[i] = s; + +@@ -119,6 +123,7 @@ + + PATCH(exclude_ext); + PATCH(etags_used); ++ PATCH(disable_pathinfo); + + /* skip the first, the global context */ + for (i = 1; i < srv->config_context->used; i++) { +@@ -136,7 +141,9 @@ + PATCH(exclude_ext); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.etags"))) { + PATCH(etags_used); +- } ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.disable-pathinfo"))) { ++ PATCH(disable_pathinfo); ++ } + } + } + +@@ -350,7 +357,6 @@ + URIHANDLER_FUNC(mod_staticfile_subrequest) { + plugin_data *p = p_d; + size_t k; +- int s_len; + stat_cache_entry *sce = NULL; + buffer *mtime = NULL; + data_string *ds; +@@ -376,7 +382,12 @@ + + mod_staticfile_patch_connection(srv, con, p); + +- s_len = con->uri.path->used - 1; ++ if (p->conf.disable_pathinfo && 0 != con->request.pathinfo->used) { ++ if (con->conf.log_request_handling) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, pathinfo forbidden"); ++ } ++ return HANDLER_GO_ON; ++ } + + /* ignore certain extensions */ + for (k = 0; k < p->conf.exclude_ext->used; k++) { +Index: src/network.c +=================================================================== +--- src/network.c (.../tags/lighttpd-1.4.29) ++++ src/network.c (.../branches/lighttpd-1.4.x) +@@ -27,6 +27,19 @@ + # include + #endif + ++#ifdef USE_OPENSSL ++static void ssl_info_callback(const SSL *ssl, int where, int ret) { ++ UNUSED(ret); ++ ++ if (0 != (where & SSL_CB_HANDSHAKE_START)) { ++ connection *con = SSL_get_app_data(ssl); ++ ++con->renegotiations; ++ } else if (0 != (where & SSL_CB_HANDSHAKE_DONE)) { ++ ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; ++ } ++} ++#endif ++ + static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) { + server_socket *srv_socket = (server_socket *)context; + connection *con; +@@ -480,9 +493,11 @@ + network_backend_t backend; + + #if OPENSSL_VERSION_NUMBER >= 0x0090800fL ++#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh; + int nid; + #endif ++#endif + + #ifdef USE_OPENSSL + DH *dh; +@@ -553,6 +568,11 @@ + /* load SSL certificates */ + for (i = 0; i < srv->config_context->used; i++) { + specific_config *s = srv->config_storage[i]; ++#ifndef SSL_OP_NO_COMPRESSION ++# define SSL_OP_NO_COMPRESSION 0 ++#endif ++ long ssloptions = ++ SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION; + + if (buffer_is_empty(s->ssl_pemfile)) continue; + +@@ -586,6 +606,9 @@ + return -1; + } + ++ SSL_CTX_set_options(s->ssl_ctx, ssloptions); ++ SSL_CTX_set_info_callback(s->ssl_ctx, ssl_info_callback); ++ + if (!s->ssl_use_sslv2) { + /* disable SSLv2 */ + if (!(SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2))) { +@@ -611,6 +634,10 @@ + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } ++ ++ if (s->ssl_honor_cipher_order) { ++ SSL_CTX_set_options(s->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); ++ } + } + + /* Support for Diffie-Hellman key exchange */ +@@ -847,7 +874,7 @@ + return 0; + } + +-int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) { ++int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq, off_t max_bytes) { + int ret = -1; + off_t written = 0; + #ifdef TCP_CORK +@@ -855,16 +882,34 @@ + #endif + server_socket *srv_socket = con->srv_socket; + +- if (con->conf.global_kbytes_per_second && +- *(con->conf.global_bytes_per_second_cnt_ptr) > con->conf.global_kbytes_per_second * 1024) { +- /* we reached the global traffic limit */ ++ if (con->conf.global_kbytes_per_second) { ++ off_t limit = con->conf.global_kbytes_per_second * 1024 - *(con->conf.global_bytes_per_second_cnt_ptr); ++ if (limit <= 0) { ++ /* we reached the global traffic limit */ + +- con->traffic_limit_reached = 1; +- joblist_append(srv, con); ++ con->traffic_limit_reached = 1; ++ joblist_append(srv, con); + +- return 1; ++ return 1; ++ } else { ++ if (max_bytes > limit) max_bytes = limit; ++ } + } + ++ if (con->conf.kbytes_per_second) { ++ off_t limit = con->conf.kbytes_per_second * 1024 - con->bytes_written_cur_second; ++ if (limit <= 0) { ++ /* we reached the traffic limit */ ++ ++ con->traffic_limit_reached = 1; ++ joblist_append(srv, con); ++ ++ return 1; ++ } else { ++ if (max_bytes > limit) max_bytes = limit; ++ } ++ } ++ + written = cq->bytes_out; + + #ifdef TCP_CORK +@@ -879,10 +924,10 @@ + + if (srv_socket->is_ssl) { + #ifdef USE_OPENSSL +- ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq); ++ ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq, max_bytes); + #endif + } else { +- ret = srv->network_backend_write(srv, con, con->fd, cq); ++ ret = srv->network_backend_write(srv, con, con->fd, cq, max_bytes); + } + + if (ret >= 0) { +@@ -903,12 +948,5 @@ + + *(con->conf.global_bytes_per_second_cnt_ptr) += written; + +- if (con->conf.kbytes_per_second && +- (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) { +- /* we reached the traffic limit */ +- +- con->traffic_limit_reached = 1; +- joblist_append(srv, con); +- } + return ret; + } +Index: src/network.h +=================================================================== +--- src/network.h (.../tags/lighttpd-1.4.29) ++++ src/network.h (.../branches/lighttpd-1.4.x) +@@ -3,7 +3,7 @@ + + #include "server.h" + +-int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c); ++int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c, off_t max_bytes); + + int network_init(server *srv); + int network_close(server *srv); +Index: src/configfile.c +=================================================================== +--- src/configfile.c (.../tags/lighttpd-1.4.29) ++++ src/configfile.c (.../branches/lighttpd-1.4.x) +@@ -105,6 +105,8 @@ + { "ssl.use-sslv3", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 62 */ + { "ssl.dh-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 63 */ + { "ssl.ec-curve", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 64 */ ++ { "ssl.disable-client-renegotiation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },/* 65 */ ++ { "ssl.honor-cipher-order", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 66 */ + + { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET }, + { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET }, +@@ -176,6 +178,7 @@ + s->max_write_idle = 360; + s->use_xattr = 0; + s->is_ssl = 0; ++ s->ssl_honor_cipher_order = 1; + s->ssl_use_sslv2 = 0; + s->ssl_use_sslv3 = 1; + s->use_ipv6 = 0; +@@ -199,6 +202,7 @@ + s->ssl_verifyclient_username = buffer_init(); + s->ssl_verifyclient_depth = 9; + s->ssl_verifyclient_export_cert = 0; ++ s->ssl_disable_client_renegotiation = 1; + + cv[2].destination = s->errorfile_prefix; + +@@ -245,6 +249,8 @@ + cv[62].destination = &(s->ssl_use_sslv3); + cv[63].destination = s->ssl_dh_file; + cv[64].destination = s->ssl_ec_curve; ++ cv[66].destination = &(s->ssl_honor_cipher_order); ++ + cv[49].destination = &(s->etag_use_inode); + cv[50].destination = &(s->etag_use_mtime); + cv[51].destination = &(s->etag_use_size); +@@ -255,6 +261,7 @@ + cv[58].destination = &(s->ssl_verifyclient_depth); + cv[59].destination = s->ssl_verifyclient_username; + cv[60].destination = &(s->ssl_verifyclient_export_cert); ++ cv[65].destination = &(s->ssl_disable_client_renegotiation); + + srv->config_storage[i] = s; + +@@ -335,6 +342,7 @@ + PATCH(ssl_cipher_list); + PATCH(ssl_dh_file); + PATCH(ssl_ec_curve); ++ PATCH(ssl_honor_cipher_order); + PATCH(ssl_use_sslv2); + PATCH(ssl_use_sslv3); + PATCH(etag_use_inode); +@@ -346,6 +354,7 @@ + PATCH(ssl_verifyclient_depth); + PATCH(ssl_verifyclient_username); + PATCH(ssl_verifyclient_export_cert); ++ PATCH(ssl_disable_client_renegotiation); + + return 0; + } +@@ -400,6 +409,8 @@ + #endif + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) { + PATCH(ssl_ca_file); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.honor-cipher-order"))) { ++ PATCH(ssl_honor_cipher_order); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv2"))) { + PATCH(ssl_use_sslv2); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv3"))) { +@@ -454,6 +465,8 @@ + PATCH(ssl_verifyclient_username); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) { + PATCH(ssl_verifyclient_export_cert); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.disable-client-renegotiation"))) { ++ PATCH(ssl_disable_client_renegotiation); + } + } + } +Index: src/mod_scgi.c +=================================================================== +--- src/mod_scgi.c (.../tags/lighttpd-1.4.29) ++++ src/mod_scgi.c (.../branches/lighttpd-1.4.x) +@@ -2296,7 +2296,7 @@ + + /* fall through */ + case FCGI_STATE_WRITE: +- ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); ++ ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT); + + chunkqueue_remove_finished_chunks(hctx->wb); + +Index: src/request.c +=================================================================== +--- src/request.c (.../tags/lighttpd-1.4.29) ++++ src/request.c (.../branches/lighttpd-1.4.x) +@@ -49,7 +49,7 @@ + if (++colon_cnt > 7) { + return -1; + } +- } else if (!light_isxdigit(*c)) { ++ } else if (!light_isxdigit(*c) && '.' != *c) { + return -1; + } + } +Index: src/network_backends.h +=================================================================== +--- src/network_backends.h (.../tags/lighttpd-1.4.29) ++++ src/network_backends.h (.../branches/lighttpd-1.4.x) +@@ -47,18 +47,18 @@ + #include "base.h" + + /* return values: +- * >= 0 : chunks completed ++ * >= 0 : no error + * -1 : error (on our side) + * -2 : remote close + */ + +-int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq); +-int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq); +-int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq); +-int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq); +-int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq); ++int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes); ++int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes); ++int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes); ++int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes); ++int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes); + #ifdef USE_OPENSSL +-int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq); ++int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes); + #endif + + #endif +Index: src/SConscript +=================================================================== +--- src/SConscript (.../tags/lighttpd-1.4.29) ++++ src/SConscript (.../branches/lighttpd-1.4.x) +@@ -12,7 +12,8 @@ + data_integer.c md5.c data_fastcgi.c \ + fdevent_select.c fdevent_libev.c \ + fdevent_poll.c fdevent_linux_sysepoll.c \ +- fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \ ++ fdevent_solaris_devpoll.c fdevent_solaris_port.c \ ++ fdevent_freebsd_kqueue.c \ + data_config.c bitset.c \ + inet_ntop_cache.c crc32.c \ + connections-glue.c \ +@@ -62,7 +63,7 @@ + 'mod_redirect' : { 'src' : [ 'mod_redirect.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_rewrite' : { 'src' : [ 'mod_rewrite.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_auth' : { +- 'src' : [ 'mod_auth.c', 'http_auth_digest.c', 'http_auth.c' ], ++ 'src' : [ 'mod_auth.c', 'http_auth.c' ], + 'lib' : [ env['LIBCRYPT'], env['LIBLDAP'], env['LIBLBER'] ] }, + 'mod_webdav' : { 'src' : [ 'mod_webdav.c' ], 'lib' : [ env['LIBXML2'], env['LIBSQLITE3'], env['LIBUUID'] ] }, + 'mod_mysql_vhost' : { 'src' : [ 'mod_mysql_vhost.c' ], 'lib' : [ env['LIBMYSQL'] ] }, +Index: src/mod_cml_funcs.c +=================================================================== +--- src/mod_cml_funcs.c (.../tags/lighttpd-1.4.29) ++++ src/mod_cml_funcs.c (.../branches/lighttpd-1.4.x) +@@ -17,18 +17,8 @@ + #include + #include + +-#ifdef USE_OPENSSL +-# include +-#else +-# include "md5.h" ++#include "md5.h" + +-typedef li_MD5_CTX MD5_CTX; +-#define MD5_Init li_MD5_Init +-#define MD5_Update li_MD5_Update +-#define MD5_Final li_MD5_Final +- +-#endif +- + #define HASHLEN 16 + typedef unsigned char HASH[HASHLEN]; + #define HASHHEXLEN 32 +@@ -43,7 +33,7 @@ + #ifdef HAVE_LUA_H + + int f_crypto_md5(lua_State *L) { +- MD5_CTX Md5Ctx; ++ li_MD5_CTX Md5Ctx; + HASH HA1; + buffer b; + char hex[33]; +@@ -63,9 +53,9 @@ + lua_error(L); + } + +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1)); +- MD5_Final(HA1, &Md5Ctx); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1)); ++ li_MD5_Final(HA1, &Md5Ctx); + + buffer_copy_string_hex(&b, (char *)HA1, 16); + +Index: src/mod_userdir.c +=================================================================== +--- src/mod_userdir.c (.../tags/lighttpd-1.4.29) ++++ src/mod_userdir.c (.../branches/lighttpd-1.4.x) +@@ -166,7 +166,6 @@ + + URIHANDLER_FUNC(mod_userdir_docroot_handler) { + plugin_data *p = p_d; +- int uri_len; + size_t k; + char *rel_url; + #ifdef HAVE_PWD_H +@@ -182,8 +181,6 @@ + */ + if (p->conf.path->used == 0) return HANDLER_GO_ON; + +- uri_len = con->uri.path->used - 1; +- + /* /~user/foo.html -> /home/user/public_html/foo.html */ + + if (con->uri.path->ptr[0] != '/' || +Index: src/mod_proxy.c +=================================================================== +--- src/mod_proxy.c (.../tags/lighttpd-1.4.29) ++++ src/mod_proxy.c (.../branches/lighttpd-1.4.x) +@@ -825,7 +825,7 @@ + + /* fall through */ + case PROXY_STATE_WRITE:; +- ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); ++ ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT); + + chunkqueue_remove_finished_chunks(hctx->wb); + +Index: src/Makefile.am +=================================================================== +--- src/Makefile.am (.../tags/lighttpd-1.4.29) ++++ src/Makefile.am (.../branches/lighttpd-1.4.x) +@@ -241,7 +241,7 @@ + mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd) + + lib_LTLIBRARIES += mod_auth.la +-mod_auth_la_SOURCES = mod_auth.c http_auth_digest.c http_auth.c ++mod_auth_la_SOURCES = mod_auth.c http_auth.c + mod_auth_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined + mod_auth_la_LIBADD = $(CRYPT_LIB) $(LDAP_LIB) $(LBER_LIB) $(common_libadd) + +@@ -268,7 +268,7 @@ + + hdr = server.h buffer.h network.h log.h keyvalue.h \ + response.h request.h fastcgi.h chunk.h \ +- settings.h http_chunk.h http_auth_digest.h \ ++ settings.h http_chunk.h \ + md5.h http_auth.h stream.h \ + fdevent.h connections.h base.h stat_cache.h \ + plugin.h mod_auth.h \ +Index: src/network_writev.c +=================================================================== +--- src/network_writev.c (.../tags/lighttpd-1.4.29) ++++ src/network_writev.c (.../branches/lighttpd-1.4.x) +@@ -30,17 +30,16 @@ + #define LOCAL_BUFFERING 1 + #endif + +-int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) { ++int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { + chunk *c; +- size_t chunks_written = 0; + +- for(c = cq->first; c; c = c->next) { ++ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { + int chunk_finished = 0; + + switch(c->type) { + case MEM_CHUNK: { + char * offset; +- size_t toSend; ++ off_t toSend; + ssize_t r; + + size_t num_chunks, i; +@@ -65,12 +64,10 @@ + #error "sysconf() doesnt return _SC_IOV_MAX ..., check the output of 'man writev' for the EINVAL error and send the output to jan@kneschke.de" + #endif + +- /* we can't send more then SSIZE_MAX bytes in one chunk */ +- + /* build writev list + * + * 1. limit: num_chunks < max_chunks +- * 2. limit: num_bytes < SSIZE_MAX ++ * 2. limit: num_bytes < max_bytes + */ + for (num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < max_chunks; num_chunks++, tc = tc->next); + +@@ -87,9 +84,9 @@ + chunks[i].iov_base = offset; + + /* protect the return value of writev() */ +- if (toSend > SSIZE_MAX || +- num_bytes + toSend > SSIZE_MAX) { +- chunks[i].iov_len = SSIZE_MAX - num_bytes; ++ if (toSend > max_bytes || ++ (off_t) num_bytes + toSend > max_bytes) { ++ chunks[i].iov_len = max_bytes - num_bytes; + + num_chunks = i + 1; + break; +@@ -121,6 +118,7 @@ + } + + cq->bytes_out += r; ++ max_bytes -= r; + + /* check which chunks have been written */ + +@@ -132,11 +130,10 @@ + + if (chunk_finished) { + /* skip the chunks from further touches */ +- chunks_written++; + c = c->next; + } else { + /* chunks_written + c = c->next is done in the for()*/ +- chunk_finished++; ++ chunk_finished = 1; + } + } else { + /* partially written */ +@@ -284,6 +281,8 @@ + assert(toSend < 0); + } + ++ if (toSend > max_bytes) toSend = max_bytes; ++ + #ifdef LOCAL_BUFFERING + start = c->mem->ptr; + #else +@@ -309,6 +308,7 @@ + + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + + if (c->offset == c->file.length) { + chunk_finished = 1; +@@ -334,11 +334,9 @@ + + break; + } +- +- chunks_written++; + } + +- return chunks_written; ++ return 0; + } + + #endif +Index: src/network_freebsd_sendfile.c +=================================================================== +--- src/network_freebsd_sendfile.c (.../tags/lighttpd-1.4.29) ++++ src/network_freebsd_sendfile.c (.../branches/lighttpd-1.4.x) +@@ -31,17 +31,16 @@ + # endif + #endif + +-int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) { ++int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { + chunk *c; +- size_t chunks_written = 0; + +- for(c = cq->first; c; c = c->next, chunks_written++) { ++ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { + int chunk_finished = 0; + + switch(c->type) { + case MEM_CHUNK: { + char * offset; +- size_t toSend; ++ off_t toSend; + ssize_t r; + + size_t num_chunks, i; +@@ -49,12 +48,10 @@ + chunk *tc; + size_t num_bytes = 0; + +- /* we can't send more then SSIZE_MAX bytes in one chunk */ +- + /* build writev list + * + * 1. limit: num_chunks < UIO_MAXIOV +- * 2. limit: num_bytes < SSIZE_MAX ++ * 2. limit: num_bytes < max_bytes + */ + for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next); + +@@ -69,9 +66,9 @@ + chunks[i].iov_base = offset; + + /* protect the return value of writev() */ +- if (toSend > SSIZE_MAX || +- num_bytes + toSend > SSIZE_MAX) { +- chunks[i].iov_len = SSIZE_MAX - num_bytes; ++ if (toSend > max_bytes || ++ (off_t) num_bytes + toSend > max_bytes) { ++ chunks[i].iov_len = max_bytes - num_bytes; + + num_chunks = i + 1; + break; +@@ -105,6 +102,7 @@ + + /* check which chunks have been written */ + cq->bytes_out += r; ++ max_bytes -= r; + + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { + if (r >= (ssize_t)chunks[i].iov_len) { +@@ -114,11 +112,10 @@ + + if (chunk_finished) { + /* skip the chunks from further touches */ +- chunks_written++; + c = c->next; + } else { + /* chunks_written + c = c->next is done in the for()*/ +- chunk_finished++; ++ chunk_finished = 1; + } + } else { + /* partially written */ +@@ -134,7 +131,7 @@ + } + case FILE_CHUNK: { + off_t offset, r; +- size_t toSend; ++ off_t toSend; + stat_cache_entry *sce = NULL; + + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { +@@ -144,9 +141,8 @@ + } + + offset = c->file.start + c->offset; +- /* limit the toSend to 2^31-1 bytes in a chunk */ +- toSend = c->file.length - c->offset > ((1 << 30) - 1) ? +- ((1 << 30) - 1) : c->file.length - c->offset; ++ toSend = c->file.length - c->offset; ++ if (toSend > max_bytes) toSend = max_bytes; + + if (-1 == c->file.fd) { + if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { +@@ -197,6 +193,7 @@ + + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + + if (c->offset == c->file.length) { + chunk_finished = 1; +@@ -218,7 +215,7 @@ + } + } + +- return chunks_written; ++ return 0; + } + + #endif +Index: src/network_openssl.c +=================================================================== +--- src/network_openssl.c (.../tags/lighttpd-1.4.29) ++++ src/network_openssl.c (.../branches/lighttpd-1.4.x) +@@ -27,10 +27,9 @@ + # include + # include + +-int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) { ++int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) { + int ssl_r; + chunk *c; +- size_t chunks_written = 0; + + /* this is a 64k sendbuffer + * +@@ -59,13 +58,13 @@ + SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); + } + +- for(c = cq->first; c; c = c->next) { ++ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { + int chunk_finished = 0; + + switch(c->type) { + case MEM_CHUNK: { + char * offset; +- size_t toSend; ++ off_t toSend; + ssize_t r; + + if (c->mem->used == 0 || c->mem->used == 1) { +@@ -75,6 +74,7 @@ + + offset = c->mem->ptr + c->offset; + toSend = c->mem->used - 1 - c->offset; ++ if (toSend > max_bytes) toSend = max_bytes; + + /** + * SSL_write man-page +@@ -87,7 +87,14 @@ + */ + + ERR_clear_error(); +- if ((r = SSL_write(ssl, offset, toSend)) <= 0) { ++ r = SSL_write(ssl, offset, toSend); ++ ++ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client"); ++ return -1; ++ } ++ ++ if (r <= 0) { + unsigned long err; + + switch ((ssl_r = SSL_get_error(ssl, r))) { +@@ -139,6 +146,7 @@ + } else { + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + } + + if (c->offset == (off_t)c->mem->used - 1) { +@@ -168,6 +176,7 @@ + do { + off_t offset = c->file.start + c->offset; + off_t toSend = c->file.length - c->offset; ++ if (toSend > max_bytes) toSend = max_bytes; + + if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; + +@@ -190,7 +199,14 @@ + close(ifd); + + ERR_clear_error(); +- if ((r = SSL_write(ssl, s, toSend)) <= 0) { ++ r = SSL_write(ssl, s, toSend); ++ ++ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client"); ++ return -1; ++ } ++ ++ if (r <= 0) { + unsigned long err; + + switch ((ssl_r = SSL_get_error(ssl, r))) { +@@ -243,12 +259,13 @@ + } else { + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + } + + if (c->offset == c->file.length) { + chunk_finished = 1; + } +- } while(!chunk_finished && !write_wait); ++ } while (!chunk_finished && !write_wait && max_bytes > 0); + + break; + } +@@ -263,11 +280,9 @@ + + break; + } +- +- chunks_written++; + } + +- return chunks_written; ++ return 0; + } + #endif + +Index: src/http_auth.c +=================================================================== +--- src/http_auth.c (.../tags/lighttpd-1.4.29) ++++ src/http_auth.c (.../branches/lighttpd-1.4.x) +@@ -1,7 +1,6 @@ + #include "server.h" + #include "log.h" + #include "http_auth.h" +-#include "http_auth_digest.h" + #include "inet_ntop_cache.h" + #include "stream.h" + +@@ -28,18 +27,23 @@ + #include + #include + +-#ifdef USE_OPENSSL +-# include +-#else +-# include "md5.h" ++#include "md5.h" + +-typedef li_MD5_CTX MD5_CTX; +-#define MD5_Init li_MD5_Init +-#define MD5_Update li_MD5_Update +-#define MD5_Final li_MD5_Final ++#define HASHLEN 16 ++#define HASHHEXLEN 32 ++typedef unsigned char HASH[HASHLEN]; ++typedef char HASHHEX[HASHHEXLEN+1]; + +-#endif ++static void CvtHex(const HASH Bin, char Hex[33]) { ++ unsigned short i; + ++ for (i = 0; i < 16; i++) { ++ Hex[i*2] = int2hex((Bin[i] >> 4) & 0xf); ++ Hex[i*2+1] = int2hex(Bin[i] & 0xf); ++ } ++ Hex[32] = '\0'; ++} ++ + /** + * the $apr1$ handling is taken from apache 1.3.x + */ +@@ -95,7 +99,7 @@ + ch = in[0]; + /* run through the whole string, converting as we go */ + for (i = 0; i < in_len; i++) { +- ch = in[i]; ++ ch = (unsigned char) in[i]; + + if (ch == '\0') break; + +@@ -435,7 +439,7 @@ + + static void to64(char *s, unsigned long v, int n) + { +- static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ ++ static const unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + while (--n >= 0) { +@@ -455,7 +459,7 @@ + const char *sp, *ep; + unsigned char final[APR_MD5_DIGESTSIZE]; + ssize_t sl, pl, i; +- MD5_CTX ctx, ctx1; ++ li_MD5_CTX ctx, ctx1; + unsigned long l; + + /* +@@ -487,33 +491,33 @@ + /* + * 'Time to make the doughnuts..' + */ +- MD5_Init(&ctx); ++ li_MD5_Init(&ctx); + + /* + * The password first, since that is what is most unknown + */ +- MD5_Update(&ctx, pw, strlen(pw)); ++ li_MD5_Update(&ctx, pw, strlen(pw)); + + /* + * Then our magic string + */ +- MD5_Update(&ctx, APR1_ID, strlen(APR1_ID)); ++ li_MD5_Update(&ctx, APR1_ID, strlen(APR1_ID)); + + /* + * Then the raw salt + */ +- MD5_Update(&ctx, sp, sl); ++ li_MD5_Update(&ctx, sp, sl); + + /* + * Then just as many characters of the MD5(pw, salt, pw) + */ +- MD5_Init(&ctx1); +- MD5_Update(&ctx1, pw, strlen(pw)); +- MD5_Update(&ctx1, sp, sl); +- MD5_Update(&ctx1, pw, strlen(pw)); +- MD5_Final(final, &ctx1); ++ li_MD5_Init(&ctx1); ++ li_MD5_Update(&ctx1, pw, strlen(pw)); ++ li_MD5_Update(&ctx1, sp, sl); ++ li_MD5_Update(&ctx1, pw, strlen(pw)); ++ li_MD5_Final(final, &ctx1); + for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) { +- MD5_Update(&ctx, final, ++ li_MD5_Update(&ctx, final, + (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl); + } + +@@ -527,10 +531,10 @@ + */ + for (i = strlen(pw); i != 0; i >>= 1) { + if (i & 1) { +- MD5_Update(&ctx, final, 1); ++ li_MD5_Update(&ctx, final, 1); + } + else { +- MD5_Update(&ctx, pw, 1); ++ li_MD5_Update(&ctx, pw, 1); + } + } + +@@ -542,7 +546,7 @@ + strncat(passwd, sp, sl); + strcat(passwd, "$"); + +- MD5_Final(final, &ctx); ++ li_MD5_Final(final, &ctx); + + /* + * And now, just to make sure things don't run too fast.. +@@ -550,28 +554,28 @@ + * need 30 seconds to build a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { +- MD5_Init(&ctx1); ++ li_MD5_Init(&ctx1); + if (i & 1) { +- MD5_Update(&ctx1, pw, strlen(pw)); ++ li_MD5_Update(&ctx1, pw, strlen(pw)); + } + else { +- MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); ++ li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); + } + if (i % 3) { +- MD5_Update(&ctx1, sp, sl); ++ li_MD5_Update(&ctx1, sp, sl); + } + + if (i % 7) { +- MD5_Update(&ctx1, pw, strlen(pw)); ++ li_MD5_Update(&ctx1, pw, strlen(pw)); + } + + if (i & 1) { +- MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); ++ li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); + } + else { +- MD5_Update(&ctx1, pw, strlen(pw)); ++ li_MD5_Update(&ctx1, pw, strlen(pw)); + } +- MD5_Final(final,&ctx1); ++ li_MD5_Final(final,&ctx1); + } + + p = passwd + strlen(passwd); +@@ -614,17 +618,17 @@ + * user:realm:md5(user:realm:password) + */ + +- MD5_CTX Md5Ctx; ++ li_MD5_CTX Md5Ctx; + HASH HA1; + char a1[256]; + +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw)); +- MD5_Final(HA1, &Md5Ctx); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw)); ++ li_MD5_Final(HA1, &Md5Ctx); + + CvtHex(HA1, a1); + +@@ -930,7 +934,7 @@ + int i; + buffer *password, *b, *username_buf, *realm_buf; + +- MD5_CTX Md5Ctx; ++ li_MD5_CTX Md5Ctx; + HASH HA1; + HASH HA2; + HASH RespHash; +@@ -1067,13 +1071,13 @@ + + if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { + /* generate password from plain-text */ +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1); +- MD5_Final(HA1, &Md5Ctx); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1); ++ li_MD5_Final(HA1, &Md5Ctx); + } else if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) { + /* HA1 */ + /* transform the 32-byte-hex-md5 to a 16-byte-md5 */ +@@ -1090,45 +1094,45 @@ + + if (algorithm && + strcasecmp(algorithm, "md5-sess") == 0) { +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)HA1, 16); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce)); +- MD5_Final(HA1, &Md5Ctx); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)HA1, 16); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce)); ++ li_MD5_Final(HA1, &Md5Ctx); + } + + CvtHex(HA1, a1); + + /* calculate H(A2) */ +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri)); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri)); + if (qop && strcasecmp(qop, "auth-int") == 0) { +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN); + } +- MD5_Final(HA2, &Md5Ctx); ++ li_MD5_Final(HA2, &Md5Ctx); + CvtHex(HA2, HA2Hex); + + /* calculate response */ +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); + if (qop && *qop) { +- MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); +- MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop)); +- MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1); + }; +- MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN); +- MD5_Final(RespHash, &Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN); ++ li_MD5_Final(RespHash, &Md5Ctx); + CvtHex(RespHash, a2); + + if (0 != strcmp(a2, respons)) { +@@ -1171,24 +1175,24 @@ + + int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer *fn, char out[33]) { + HASH h; +- MD5_CTX Md5Ctx; ++ li_MD5_CTX Md5Ctx; + char hh[32]; + + UNUSED(p); + + /* generate shared-secret */ +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1); +- MD5_Update(&Md5Ctx, (unsigned char *)"+", 1); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1); + + /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */ + LI_ltostr(hh, srv->cur_ts); +- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); +- MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy)); + LI_ltostr(hh, rand()); +- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); + +- MD5_Final(h, &Md5Ctx); ++ li_MD5_Final(h, &Md5Ctx); + + CvtHex(h, out); + +Index: src/mod_usertrack.c +=================================================================== +--- src/mod_usertrack.c (.../tags/lighttpd-1.4.29) ++++ src/mod_usertrack.c (.../branches/lighttpd-1.4.x) +@@ -8,18 +8,8 @@ + #include + #include + +-#ifdef USE_OPENSSL +-# include +-#else +-# include "md5.h" ++#include "md5.h" + +-typedef li_MD5_CTX MD5_CTX; +-#define MD5_Init li_MD5_Init +-#define MD5_Update li_MD5_Update +-#define MD5_Final li_MD5_Final +- +-#endif +- + /* plugin config for all request/connections */ + + typedef struct { +@@ -182,7 +172,7 @@ + plugin_data *p = p_d; + data_string *ds; + unsigned char h[16]; +- MD5_CTX Md5Ctx; ++ li_MD5_CTX Md5Ctx; + char hh[32]; + + if (con->uri.path->used == 0) return HANDLER_GO_ON; +@@ -228,18 +218,18 @@ + /* taken from mod_auth.c */ + + /* generate shared-secret */ +- MD5_Init(&Md5Ctx); +- MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1); +- MD5_Update(&Md5Ctx, (unsigned char *)"+", 1); ++ li_MD5_Init(&Md5Ctx); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1); + + /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */ + LI_ltostr(hh, srv->cur_ts); +- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); +- MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy)); + LI_ltostr(hh, rand()); +- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); ++ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); + +- MD5_Final(h, &Md5Ctx); ++ li_MD5_Final(h, &Md5Ctx); + + buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX); + buffer_append_string_len(ds->value, CONST_STR_LEN("; Path=/")); +Index: src/mod_status.c +=================================================================== +--- src/mod_status.c (.../tags/lighttpd-1.4.29) ++++ src/mod_status.c (.../branches/lighttpd-1.4.x) +@@ -487,7 +487,7 @@ + + buffer_append_string_len(b, CONST_STR_LEN("")); + +- if (con->request.content_length) { ++ if (c->request.content_length) { + buffer_append_long(b, c->request_content_queue->bytes_in); + buffer_append_string_len(b, CONST_STR_LEN("/")); + buffer_append_long(b, c->request.content_length); +Index: src/settings.h +=================================================================== +--- src/settings.h (.../tags/lighttpd-1.4.29) ++++ src/settings.h (.../branches/lighttpd-1.4.x) +@@ -21,8 +21,11 @@ + * 64kB (no real reason, just a guess) + */ + #define BUFFER_MAX_REUSE_SIZE (4 * 1024) +-#define MAX_READ_LIMIT (4*1024*1024) + ++/* both should be way smaller than SSIZE_MAX :) */ ++#define MAX_READ_LIMIT (256*1024) ++#define MAX_WRITE_LIMIT (256*1024) ++ + /** + * max size of the HTTP request header + * +Index: src/mod_cml_lua.c +=================================================================== +--- src/mod_cml_lua.c (.../tags/lighttpd-1.4.29) ++++ src/mod_cml_lua.c (.../branches/lighttpd-1.4.x) +@@ -11,18 +11,6 @@ + #include + #include + +-#ifdef USE_OPENSSL +-# include +-#else +-# include "md5.h" +- +-typedef li_MD5_CTX MD5_CTX; +-#define MD5_Init li_MD5_Init +-#define MD5_Update li_MD5_Update +-#define MD5_Final li_MD5_Final +- +-#endif +- + #define HASHLEN 16 + typedef unsigned char HASH[HASHLEN]; + #define HASHHEXLEN 32 +Index: src/mod_fastcgi.c +=================================================================== +--- src/mod_fastcgi.c (.../tags/lighttpd-1.4.29) ++++ src/mod_fastcgi.c (.../branches/lighttpd-1.4.x) +@@ -3075,7 +3075,7 @@ + fcgi_set_state(srv, hctx, FCGI_STATE_WRITE); + /* fall through */ + case FCGI_STATE_WRITE: +- ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); ++ ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT); + + chunkqueue_remove_finished_chunks(hctx->wb); + +@@ -3132,7 +3132,6 @@ + plugin_data *p = p_d; + + handler_ctx *hctx = con->plugin_ctx[p->id]; +- fcgi_proc *proc; + fcgi_extension_host *host; + + if (NULL == hctx) return HANDLER_GO_ON; +@@ -3201,7 +3200,6 @@ + /* ok, create the request */ + switch(fcgi_write_request(srv, hctx)) { + case HANDLER_ERROR: +- proc = hctx->proc; + host = hctx->host; + + if (hctx->state == FCGI_STATE_INIT || +Index: src/network_solaris_sendfilev.c +=================================================================== +--- src/network_solaris_sendfilev.c (.../tags/lighttpd-1.4.29) ++++ src/network_solaris_sendfilev.c (.../branches/lighttpd-1.4.x) +@@ -38,17 +38,16 @@ + */ + + +-int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) { ++int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { + chunk *c; +- size_t chunks_written = 0; + +- for(c = cq->first; c; c = c->next, chunks_written++) { ++ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { + int chunk_finished = 0; + + switch(c->type) { + case MEM_CHUNK: { + char * offset; +- size_t toSend; ++ off_t toSend; + ssize_t r; + + size_t num_chunks, i; +@@ -77,9 +76,9 @@ + chunks[i].iov_base = offset; + + /* protect the return value of writev() */ +- if (toSend > SSIZE_MAX || +- num_bytes + toSend > SSIZE_MAX) { +- chunks[i].iov_len = SSIZE_MAX - num_bytes; ++ if (toSend > max_bytes || ++ (off_t) num_bytes + toSend > max_bytes) { ++ chunks[i].iov_len = max_bytes - num_bytes; + + num_chunks = i + 1; + break; +@@ -119,11 +118,10 @@ + + if (chunk_finished) { + /* skip the chunks from further touches */ +- chunks_written++; + c = c->next; + } else { + /* chunks_written + c = c->next is done in the for()*/ +- chunk_finished++; ++ chunk_finished = 1; + } + } else { + /* partially written */ +@@ -139,8 +137,8 @@ + } + case FILE_CHUNK: { + ssize_t r; +- off_t offset; +- size_t toSend, written; ++ off_t offset, toSend; ++ size_t written; + sendfilevec_t fvec; + stat_cache_entry *sce = NULL; + int ifd; +@@ -153,6 +151,7 @@ + + offset = c->file.start + c->offset; + toSend = c->file.length - c->offset; ++ if (toSend > max_bytes) toSend = max_bytes; + + if (offset > sce->st.st_size) { + log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); +@@ -186,6 +185,7 @@ + close(ifd); + c->offset += written; + cq->bytes_out += written; ++ max_bytes -= written; + + if (c->offset == c->file.length) { + chunk_finished = 1; +@@ -207,7 +207,7 @@ + } + } + +- return chunks_written; ++ return 0; + } + + #endif +Index: src/CMakeLists.txt +=================================================================== +Index: src/mod_dirlisting.c +=================================================================== +--- src/mod_dirlisting.c (.../tags/lighttpd-1.4.29) ++++ src/mod_dirlisting.c (.../branches/lighttpd-1.4.x) +@@ -657,7 +657,8 @@ + i = dir->used - 1; + + #ifdef HAVE_PATHCONF +- if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) { ++ if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) { ++ /* some broken fs (fuse) return 0 instead of -1 */ + #ifdef NAME_MAX + name_max = NAME_MAX; + #else +Index: src/network_linux_sendfile.c +=================================================================== +--- src/network_linux_sendfile.c (.../tags/lighttpd-1.4.29) ++++ src/network_linux_sendfile.c (.../branches/lighttpd-1.4.x) +@@ -27,17 +27,16 @@ + /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */ + #undef HAVE_POSIX_FADVISE + +-int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) { ++int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { + chunk *c; +- size_t chunks_written = 0; + +- for(c = cq->first; c; c = c->next, chunks_written++) { ++ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { + int chunk_finished = 0; + + switch(c->type) { + case MEM_CHUNK: { + char * offset; +- size_t toSend; ++ off_t toSend; + ssize_t r; + + size_t num_chunks, i; +@@ -45,12 +44,10 @@ + chunk *tc; + size_t num_bytes = 0; + +- /* we can't send more then SSIZE_MAX bytes in one chunk */ +- + /* build writev list + * + * 1. limit: num_chunks < UIO_MAXIOV +- * 2. limit: num_bytes < SSIZE_MAX ++ * 2. limit: num_bytes < max_bytes + */ + for (num_chunks = 0, tc = c; + tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; +@@ -67,9 +64,9 @@ + chunks[i].iov_base = offset; + + /* protect the return value of writev() */ +- if (toSend > SSIZE_MAX || +- num_bytes + toSend > SSIZE_MAX) { +- chunks[i].iov_len = SSIZE_MAX - num_bytes; ++ if (toSend > max_bytes || ++ (off_t) num_bytes + toSend > max_bytes) { ++ chunks[i].iov_len = max_bytes - num_bytes; + + num_chunks = i + 1; + break; +@@ -100,6 +97,7 @@ + + /* check which chunks have been written */ + cq->bytes_out += r; ++ max_bytes -= r; + + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { + if (r >= (ssize_t)chunks[i].iov_len) { +@@ -109,11 +107,10 @@ + + if (chunk_finished) { + /* skip the chunks from further touches */ +- chunks_written++; + c = c->next; + } else { + /* chunks_written + c = c->next is done in the for()*/ +- chunk_finished++; ++ chunk_finished = 1; + } + } else { + /* partially written */ +@@ -130,13 +127,12 @@ + case FILE_CHUNK: { + ssize_t r; + off_t offset; +- size_t toSend; ++ off_t toSend; + stat_cache_entry *sce = NULL; + + offset = c->file.start + c->offset; +- /* limit the toSend to 2^31-1 bytes in a chunk */ +- toSend = c->file.length - c->offset > ((1 << 30) - 1) ? +- ((1 << 30) - 1) : c->file.length - c->offset; ++ toSend = c->file.length - c->offset; ++ if (toSend > max_bytes) toSend = max_bytes; + + /* open file if not already opened */ + if (-1 == c->file.fd) { +@@ -215,6 +211,7 @@ + + c->offset += r; + cq->bytes_out += r; ++ max_bytes -= r; + + if (c->offset == c->file.length) { + chunk_finished = 1; +@@ -243,7 +240,7 @@ + } + } + +- return chunks_written; ++ return 0; + } + + #endif +Index: tests/mod-auth.t +=================================================================== +--- tests/mod-auth.t (.../tags/lighttpd-1.4.29) ++++ tests/mod-auth.t (.../branches/lighttpd-1.4.x) +@@ -8,7 +8,7 @@ + + use strict; + use IO::Socket; +-use Test::More tests => 14; ++use Test::More tests => 15; + use LightyTest; + + my $tf = LightyTest->new(); +@@ -25,6 +25,14 @@ + + $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; ++ok($tf->handle_http($t) == 0, 'Basic-Auth: Invalid base64 Auth-token'); ++ ++$t->{REQUEST} = ( < 44; ++use Test::More tests => 46; + use LightyTest; + + my $tf = LightyTest->new(); +@@ -413,5 +413,21 @@ + $t->{SLOWREQUEST} = 1; + ok($tf->handle_http($t) == 0, 'GET, slow \\r\\n\\r\\n (#2105)'); + ++print "\nPathinfo for static files\n"; ++$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ]; ++ok($tf->handle_http($t) == 0, 'static file accepting pathinfo by default'); ++ ++$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; ++ok($tf->handle_http($t) == 0, 'static file with forbidden pathinfo'); ++ + ok($tf->stop_proc == 0, "Stopping lighttpd"); + +Index: tests/wrapper.sh +=================================================================== +--- tests/wrapper.sh (.../tags/lighttpd-1.4.29) ++++ tests/wrapper.sh (.../branches/lighttpd-1.4.x) +@@ -6,4 +6,4 @@ + top_builddir=$2 + export SHELL srcdir top_builddir + +-$3 ++exec $3 +Index: tests/lighttpd.conf +=================================================================== +--- tests/lighttpd.conf (.../tags/lighttpd-1.4.29) ++++ tests/lighttpd.conf (.../branches/lighttpd-1.4.x) +@@ -149,6 +149,7 @@ + $HTTP["host"] == "zzz.example.org" { + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" + server.name = "zzz.example.org" ++ static-file.disable-pathinfo = "enable" + } + + $HTTP["host"] == "symlink.example.org" { +Index: configure.ac +=================================================================== +Index: doc/config/lighttpd.conf +=================================================================== +--- doc/config/lighttpd.conf (.../tags/lighttpd-1.4.29) ++++ doc/config/lighttpd.conf (.../branches/lighttpd-1.4.x) +@@ -394,6 +394,25 @@ + ## $SERVER["socket"] == "10.0.0.1:443" { + ## ssl.engine = "enable" + ## ssl.pemfile = "/etc/ssl/private/www.example.com.pem" ++## # ++## # Mitigate BEAST attack: ++## # ++## # A stricter base cipher suite. For details see: ++## # http://blog.ivanristic.com/2011/10/mitigating-the-beast-attack-on-tls.html ++## # ++## ssl.ciphers = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM" ++## # ++## # Make the server prefer the order of the server side cipher suite instead of the client suite. ++## # This is necessary to mitigate the BEAST attack (unless you disable all non RC4 algorithms). ++## # This option is enabled by default, but only used if ssl.ciphers is set. ++## # ++## # ssl.honor-cipher-order = "enable" ++## # ++## # Mitigate CVE-2009-3555 by disabling client triggered renegotation ++## # This is enabled by default. ++## # ++## # ssl.disable-client-renegotiation = "enable" ++## # + ## server.name = "www.example.com" + ## + ## server.document-root = "/srv/www/vhosts/example.com/www/" +Index: SConstruct +=================================================================== +Index: NEWS +=================================================================== +--- NEWS (.../tags/lighttpd-1.4.29) ++++ NEWS (.../branches/lighttpd-1.4.x) +@@ -3,7 +3,20 @@ + NEWS + ==== + +-- 1.4.29 - ++- 1.4.30 - ++ * Always use our 'own' md5 implementation, fixes linking issues on MacOS (fixes #2331) ++ * Limit amount of bytes we send in one go; fixes stalling in one connection and timeouts on slow systems. ++ * [ssl] fix build errors when Elliptic-Curve Diffie-Hellman is disabled ++ * Add static-file.disable-pathinfo option to prevent handling of urls like .../secret.php/image.jpg as static file ++ * Don't overwrite 401 (auth required) with 501 (unknown method) (fixes #2341) ++ * Fix mod_status bug: always showed "0/0" in the "Read" column for uploads (fixes #2351) ++ * [mod_auth] Fix signedness error in http_auth (fixes #2370, CVE-2011-4362) ++ * [ssl] count renegotiations to prevent client renegotiations ++ * [ssl] add option to honor server cipher order (fixes #2364, BEAST attack) ++ * [core] accept dots in ipv6 addresses in host header (fixes #2359) ++ * [ssl] fix ssl connection aborts if files are larger than the MAX_WRITE_LIMIT (256kb) ++ ++- 1.4.29 - 2011-07-03 + * Fix mod_proxy waiting for response even if content-length is 0 (fixes #2259) + * Silence annoying "connection closed: poll() -> ERR" error.log message (fixes #2257) + * mod_cgi: make read buffer as big as incoming data block +Index: CMakeLists.txt +=================================================================== diff --git a/lighttpd-branding.patch b/lighttpd-branding.patch new file mode 100644 index 0000000..9fdf8a5 --- /dev/null +++ b/lighttpd-branding.patch @@ -0,0 +1,11 @@ +--- lighttpd-1.4.22/src/response.c~ 2009-04-17 00:50:21.000000000 +0300 ++++ lighttpd-1.4.22/src/response.c 2009-04-17 00:51:22.174367972 +0300 +@@ -105,7 +105,7 @@ + + if (!have_server) { + if (buffer_is_empty(con->conf.server_tag)) { +- buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_DESC)); ++ buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_DESC " (PLD Linux)")); + } else if (con->conf.server_tag->used > 1) { + buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: ")); + buffer_append_string_encoded(b, CONST_BUF_LEN(con->conf.server_tag), ENCODING_HTTP_HEADER); diff --git a/lighttpd-mime.types.sh b/lighttpd-mime.types.sh new file mode 100644 index 0000000..5252638 --- /dev/null +++ b/lighttpd-mime.types.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# Parse /etc/mime.types into lighttpd config format. +# Copyright (c) 2005 Elan Ruusamäe + +mimetypes="$1" + +# build mime.types from system mime.types +# get ones with extension +awk '!/^#/ && $2 { print } ' $mimetypes | \ +# lay out mime types with multiple extension as separate lines \ +awk '{for (a=2; a <= NF; a++) {printf("%s\t%s\n", $1, $a)}}' | \ +# sort it \ +LC_ALL=C sort -u > mime.types + +# build lighttpd.conf fragment +awk '{ + ext = $2; + type = $1; + charset = ""; + # add charset for "text/*" types + if (type ~ "text/") { + type = "\"" type "\" + mimetype_textcharsetheader" + } else { + type = "\"" type "\"" + } + + printf("\t\".%s\"%s=> %s,\n", ext, (length(ext) > 4 ? "\t" : "\t\t"), type); +}' \ + < mime.types | LC_ALL=C sort -r > mime.types.conf + +# sanity check. there can't be more than one mime type mapping for same extension +dup=$(awk -F'"' '{print $2}' mime.types.conf | sort | uniq -c | grep -v '1' | awk '{print $NF}') +if [ "$dup" ]; then + echo >&2 Found $(echo "$dup" | wc -w) extensions which have non-unique mime-type mapping: + echo "$dup" | sed -e 's,^, ,' >&2 + exit 1 +fi + +mv -f mime.types.conf mime.types.conf.tmp + +# header +cat >> mime.types.conf <> mime.types.conf + +# footer +cat >> mime.types.conf <s %b \"%{Referer}i\" \"%{User-Agent}i\"" + +# CLF +accesslog.format = "%h %l %u %t \"%r\" %>s %b" + +# Combined Log +#accesslog.format = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" + +# CLF + virtualhost +#accesslog.format = "%h %l %u %t \"%r\" %>s %b %V" diff --git a/lighttpd-mod_alias.conf b/lighttpd-mod_alias.conf new file mode 100644 index 0000000..b790e29 --- /dev/null +++ b/lighttpd-mod_alias.conf @@ -0,0 +1,12 @@ +# Alias module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModAlias + +server.modules += ( + "mod_alias" +) + +#### alias module +#alias.url = ( +# "/cgi-bin/" => "/usr/lib/cgi-bin", +#) diff --git a/lighttpd-mod_auth.conf b/lighttpd-mod_auth.conf new file mode 100644 index 0000000..d8af909 --- /dev/null +++ b/lighttpd-mod_auth.conf @@ -0,0 +1,43 @@ +# Auth module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModAuth + +server.modules += ( + "mod_auth" +) + +#### auth module +## read authentication.txt for more info +## debugging +# 0 for off, 1 for 'auth-ok' messages, 2 for verbose debugging +#auth.debug = 1 +## type of backend +# plain, htpasswd, ldap or htdigest +#auth.backend = "plain" +# filename of the password storage +## for plain +#auth.backend.plain.userfile = "/etc/lighttpd/lighttpd.user" +#auth.backend.plain.groupfile = "/etc/lighttpd/lighttpd.group" +## for htpasswd +#auth.backend.htpasswd.userfile = "/etc/lighttpd/lighttpd-htpasswd.user" +## for htdigest +#auth.backend.htdigest.userfile = "/etc/lighttpd/lighttpd-htdigest.user" +## for ldap +# the $ in auth.backend.ldap.filter is replaced by the +# 'username' from the login dialog +#auth.backend.ldap.hostname = "localhost" +#auth.backend.ldap.base-dn = "dc=my-domain,dc=com" +#auth.backend.ldap.filter = "(uid=$)" + +#auth.require = ( +# "/server-status" => ( +# "method" => "digest", +# "realm" => "download archiv", +# "require" => "user=jan" +# ), +# "/server-info" => ( +# "method" => "digest", +# "realm" => "download archiv", +# "require" => "valid-user" +# ) +#) diff --git a/lighttpd-mod_cgi.conf b/lighttpd-mod_cgi.conf new file mode 100644 index 0000000..75ed293 --- /dev/null +++ b/lighttpd-mod_cgi.conf @@ -0,0 +1,30 @@ +# CGI module +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModCGI + +server.modules += ( + "mod_cgi" +) + +$HTTP["url"] =~ "/cgi-bin/" { + cgi.assign = ( "" => "" ) +} + +alias.url += ( + "/cgi-bin/" => "/home/services/lighttpd/cgi-bin/", + # FIXME: or use system shared cgi-bin here? +# "/cgi-bin/" => "/usr/lib/cgi-bin/", +) + +cgi.assign = ( + ".cgi" => "", +# ".pl" => "/usr/bin/perl", +# ".php" => "/usr/bin/php.cgi", +# ".py" => "/usr/bin/python", +) + +#static-file.exclude-extensions = ( +# ".pl", +# ".php", +# ".py", +#) diff --git a/lighttpd-mod_cgi_php.conf b/lighttpd-mod_cgi_php.conf new file mode 100644 index 0000000..32c1147 --- /dev/null +++ b/lighttpd-mod_cgi_php.conf @@ -0,0 +1,8 @@ +# Map PHP via CGI module + +cgi.assign += ( + ".php" => "/usr/bin/php.cgi", + ".php4" => "/usr/bin/php4.cgi", +) + +static-file.exclude-extensions += (".php") diff --git a/lighttpd-mod_cml.conf b/lighttpd-mod_cml.conf new file mode 100644 index 0000000..844a069 --- /dev/null +++ b/lighttpd-mod_cml.conf @@ -0,0 +1,21 @@ +# CML is a Meta language to describe the dependencies of a page +# at one side and building a page from its fragments on the +# other side using LUA. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModCML + +server.modules += ( + "mod_cml" +) + +## the extension for file with cache information. With .cml, +## the cache info file for index.html is index.cml +cml.extension = ".cml" + +index-file.names += ( "index" + cml.extension ) + +## the memcached used by mod_cml +#cml.memcache-hosts = ( "127.0.0.1:11211" ) + +## a cml file that is executed for each request +#cml.power-magnet = "/home/services/lighttpd/html/power-magnet.cml" diff --git a/lighttpd-mod_compress.conf b/lighttpd-mod_compress.conf new file mode 100644 index 0000000..7bbd6f1 --- /dev/null +++ b/lighttpd-mod_compress.conf @@ -0,0 +1,25 @@ +# Compress module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModCompress + +server.modules += ( + "mod_compress" +) + +# Default: "bzip2", "gzip", "deflate" +# Safe list is 'gzip, deflate'. bzip2 is problematic for some browsers (MSIE) +#compress.allowed-encodings = ( "gzip", "deflate" ) + +# Default: not set, compress the file for every request +# Filenames saved to this dir have ETag appended, so theoretically you can use +# common dir across domains for this. +compress.cache-dir = "/var/cache/lighttpd/mod_compress" + +# Keep in mind that compressed JavaScript and CSS files are broken in some browsers. +# Not setting any filetypes will result in no files being compressed. +#compress.filetype = ( +# "application/x-javascript", +# "text/css", +# "text/html", +# "text/xml", +#) diff --git a/lighttpd-mod_compress.tmpwatch b/lighttpd-mod_compress.tmpwatch new file mode 100644 index 0000000..73c4172 --- /dev/null +++ b/lighttpd-mod_compress.tmpwatch @@ -0,0 +1,2 @@ +# Cleanup lighttpd-mod_compress cache files: +/var/cache/lighttpd/mod_compress -u 10d diff --git a/lighttpd-mod_deflate.conf b/lighttpd-mod_deflate.conf new file mode 100644 index 0000000..ff5a0c0 --- /dev/null +++ b/lighttpd-mod_deflate.conf @@ -0,0 +1,7 @@ +# Deflate module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModDeflate + +server.modules += ( + "mod_deflate" +) diff --git a/lighttpd-mod_deflate.patch b/lighttpd-mod_deflate.patch new file mode 100644 index 0000000..fd2f545 --- /dev/null +++ b/lighttpd-mod_deflate.patch @@ -0,0 +1,2170 @@ +diff -Naur lighttpd-1.4.19/configure.in lighttpd-1.4.19.mod_deflate.jz/configure.in +--- lighttpd-1.4.19/configure.in ++++ lighttpd-1.4.19.mod_deflate.jz/configure.in +@@ -558,7 +558,7 @@ + AC_OUTPUT + + +-do_build="mod_cgi mod_fastcgi mod_extforward mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" ++do_build="mod_cgi mod_fastcgi mod_extforward mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming mod_deflate" + + plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl" + features="regex-conditionals" +diff -Naur lighttpd-1.4.19/src/base.h lighttpd-1.4.19.mod_deflate.jz/src/base.h +--- lighttpd-1.4.19/src/base.h ++++ lighttpd-1.4.19.mod_deflate.jz/src/base.h +@@ -149,6 +149,7 @@ + + http_method_t http_method; + http_version_t http_version; ++ int true_http_10_client; + + buffer *request_line; + +@@ -360,8 +361,10 @@ + + int file_started; + int file_finished; ++ int end_chunk; /* used for chunked transfer encoding. */ + +- chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */ ++ chunkqueue *write_queue; /* a large queue for HTTP response content [ file, mem ] */ ++ chunkqueue *output_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */ + chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */ + chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/ + +@@ -596,6 +599,7 @@ + + connections *conns; + connections *joblist; ++ connections *joblist_prev; + connections *fdwaitqueue; + + stat_cache *stat_cache; +diff -Naur lighttpd-1.4.19/src/chunk.c lighttpd-1.4.19.mod_deflate.jz/src/chunk.c +--- lighttpd-1.4.19/src/chunk.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/chunk.c +@@ -16,7 +16,9 @@ + #include + #include + ++#include "server.h" + #include "chunk.h" ++#include "log.h" + + chunkqueue *chunkqueue_init(void) { + chunkqueue *cq; +@@ -241,6 +243,16 @@ + return 0; + } + ++int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src) { ++ if(src == NULL) return 0; ++ chunkqueue_append_chunk(cq, src->first); ++ cq->last = src->last; ++ src->first = NULL; ++ src->last = NULL; ++ ++ return 0; ++} ++ + buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) { + chunk *c; + +@@ -400,3 +412,105 @@ + + return 0; + } ++ ++/** ++ * the HTTP chunk-API ++ * ++ * ++ */ ++ ++static int chunk_encode_append_len(chunkqueue *cq, size_t len) { ++ size_t i, olen = len, j; ++ buffer *b; ++ ++ /*b = srv->tmp_chunk_len;*/ ++ /*b = buffer_init();*/ ++ b = chunkqueue_get_append_buffer(cq); ++ ++ if (len == 0) { ++ buffer_copy_string(b, "0"); ++ } else { ++ for (i = 0; i < 8 && len; i++) { ++ len >>= 4; ++ } ++ ++ /* i is the number of hex digits we have */ ++ buffer_prepare_copy(b, i + 1); ++ ++ for (j = i-1, len = olen; j+1 > 0; j--) { ++ b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10); ++ len >>= 4; ++ } ++ b->used = i; ++ b->ptr[b->used++] = '\0'; ++ } ++ ++ buffer_append_string(b, "\r\n"); ++ /* ++ chunkqueue_append_buffer(cq, b); ++ buffer_free(b); ++ */ ++ ++ return 0; ++} ++ ++ ++int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) { ++ if (!cq) return -1; ++ if (len == 0) return 0; ++ ++ chunk_encode_append_len(cq, len); ++ ++ chunkqueue_append_file(cq, fn, offset, len); ++ ++ chunkqueue_append_mem(cq, "\r\n", 2 + 1); ++ ++ return 0; ++} ++ ++int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem) { ++ if (!cq) return -1; ++ if (mem->used <= 1) return 0; ++ ++ chunk_encode_append_len(cq, mem->used - 1); ++ ++ chunkqueue_append_buffer(cq, mem); ++ ++ chunkqueue_append_mem(cq, "\r\n", 2 + 1); ++ ++ return 0; ++} ++ ++int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len) { ++ if (!cq) return -1; ++ if (len <= 1) return 0; ++ ++ chunk_encode_append_len(cq, len - 1); ++ ++ chunkqueue_append_mem(cq, mem, len); ++ ++ chunkqueue_append_mem(cq, "\r\n", 2 + 1); ++ ++ return 0; ++} ++ ++int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src) { ++ int len = chunkqueue_length(src); ++ if (!cq) return -1; ++ if (len == 0) return 0; ++ ++ chunk_encode_append_len(cq, len); ++ ++ chunkqueue_append_chunkqueue(cq, src); ++ ++ chunkqueue_append_mem(cq, "\r\n", 2 + 1); ++ ++ return 0; ++} ++ ++int chunk_encode_end(chunkqueue *cq) { ++ chunk_encode_append_len(cq, 0); ++ chunkqueue_append_mem(cq, "\r\n", 2 + 1); ++ return 0; ++} ++ +diff -Naur lighttpd-1.4.19/src/chunk.h lighttpd-1.4.19.mod_deflate.jz/src/chunk.h +--- lighttpd-1.4.19/src/chunk.h ++++ lighttpd-1.4.19.mod_deflate.jz/src/chunk.h +@@ -52,6 +52,7 @@ + int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len); + int chunkqueue_append_buffer(chunkqueue *c, buffer *mem); + int chunkqueue_append_buffer_weak(chunkqueue *c, buffer *mem); ++int chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src); + int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem); + + buffer * chunkqueue_get_append_buffer(chunkqueue *c); +@@ -67,4 +68,10 @@ + + int chunkqueue_is_empty(chunkqueue *c); + ++int chunk_encode_append_mem(chunkqueue *cq, const char * mem, size_t len); ++int chunk_encode_append_buffer(chunkqueue *cq, buffer *mem); ++int chunk_encode_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len); ++int chunk_encode_append_queue(chunkqueue *cq, chunkqueue *src); ++int chunk_encode_end(chunkqueue *cq); ++ + #endif +diff -Naur lighttpd-1.4.19/src/connections.c lighttpd-1.4.19.mod_deflate.jz/src/connections.c +--- lighttpd-1.4.19/src/connections.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/connections.c +@@ -18,6 +18,7 @@ + #include "response.h" + #include "network.h" + #include "http_chunk.h" ++#include "chunk.h" + #include "stat_cache.h" + #include "joblist.h" + +@@ -146,6 +147,12 @@ + return 0; + } + ++int connection_queue_is_empty(connection *con) { ++ if(!chunkqueue_is_empty(con->write_queue)) return 0; ++ if(!chunkqueue_is_empty(con->output_queue)) return 0; ++ return 1; ++} ++ + #if 0 + static void dump_packet(const unsigned char *data, size_t len) { + size_t i, j; +@@ -405,6 +412,7 @@ + con->file_finished = 1; + + chunkqueue_reset(con->write_queue); ++ chunkqueue_reset(con->output_queue); + } + break; + default: +@@ -517,12 +525,27 @@ + /* disable chunked encoding again as we have no body */ + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; + chunkqueue_reset(con->write_queue); ++ chunkqueue_reset(con->output_queue); + + con->file_finished = 1; + break; + } + ++ /* Allow filter plugins to change response headers before they are written. */ ++ switch(plugins_call_handle_response_start(srv, con)) { ++ case HANDLER_GO_ON: ++ case HANDLER_FINISHED: ++ /* response start is finished */ ++ break; ++ default: ++ /* something strange happend */ ++ log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed."); ++ connection_set_state(srv, con, CON_STATE_ERROR); ++ joblist_append(srv, con); ++ break; ++ } ++ + if (con->file_finished) { + /* we have all the content and chunked encoding is not used, set a content-length */ + +@@ -592,8 +615,9 @@ + * without the content + */ + con->file_finished = 1; + + chunkqueue_reset(con->write_queue); ++ chunkqueue_reset(con->output_queue); + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + } + +@@ -603,11 +627,57 @@ + } + + static int connection_handle_write(server *srv, connection *con) { +- switch(network_write_chunkqueue(srv, con, con->write_queue)) { ++ int finished = 0; ++ int len; ++ ++ /* Allow filter plugins to modify response conent */ ++ switch(plugins_call_handle_response_filter(srv, con)) { ++ case HANDLER_GO_ON: ++ finished = con->file_finished; ++ /* response content not changed */ ++ break; ++ case HANDLER_COMEBACK: ++ /* response filter has more work */ ++ finished = 0; ++ break; ++ case HANDLER_FINISHED: ++ /* response filter is finished */ ++ finished = 1; ++ break; ++ default: ++ /* something strange happend */ ++ log_error_write(srv, __FILE__, __LINE__, "s", "Filter plugin failed."); ++ connection_set_state(srv, con, CON_STATE_ERROR); ++ joblist_append(srv, con); ++ finished = 1; ++ break; ++ } ++ ++ /* move chunks from write_queue to output_queue. */ ++ if (con->request.http_method == HTTP_METHOD_HEAD) { ++ chunkqueue_reset(con->write_queue); ++ } else { ++ len = chunkqueue_length(con->write_queue); ++ if(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { ++ chunk_encode_append_queue(con->output_queue, con->write_queue); ++ if(finished && !con->end_chunk) { ++ con->end_chunk = 1; ++ chunk_encode_end(con->output_queue); ++ } ++ } else { ++ chunkqueue_append_chunkqueue(con->output_queue, con->write_queue); ++ } ++ con->write_queue->bytes_out += len; ++ } ++ /* write chunks from output_queue to network */ ++ switch(network_write_chunkqueue(srv, con, con->output_queue)) { + case 0: +- if (con->file_finished) { ++ if (finished) { + connection_set_state(srv, con, CON_STATE_RESPONSE_END); + joblist_append(srv, con); ++ } else { ++ /* not finished yet -> WRITE */ ++ con->is_writable = 1; + } + break; + case -1: /* error on our side */ +@@ -678,6 +747,7 @@ + + #undef CLEAN + con->write_queue = chunkqueue_init(); ++ con->output_queue = chunkqueue_init(); + con->read_queue = chunkqueue_init(); + con->request_content_queue = chunkqueue_init(); + chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs); +@@ -705,6 +776,7 @@ + connection_reset(srv, con); + + chunkqueue_free(con->write_queue); ++ chunkqueue_free(con->output_queue); + chunkqueue_free(con->read_queue); + chunkqueue_free(con->request_content_queue); + array_free(con->request.headers); +@@ -759,7 +831,10 @@ + con->http_status = 0; + con->file_finished = 0; + con->file_started = 0; ++ con->end_chunk = 0; + con->got_response = 0; ++// con->use_cache_file = 0; ++// con->write_cache_file = 0; + + con->parsed_response = 0; + +@@ -829,6 +904,7 @@ + array_reset(con->environment); + + chunkqueue_reset(con->write_queue); ++ chunkqueue_reset(con->output_queue); + chunkqueue_reset(con->request_content_queue); + + /* the plugins should cleanup themself */ +@@ -1223,7 +1299,6 @@ + } + + if (con->state == CON_STATE_WRITE && +- !chunkqueue_is_empty(con->write_queue) && + con->is_writable) { + + if (-1 == connection_handle_write(srv, con)) { +@@ -1640,15 +1715,15 @@ + } + + /* only try to write if we have something in the queue */ +- if (!chunkqueue_is_empty(con->write_queue)) { + #if 0 ++ if (!connection_queue_is_empty(con)) { + log_error_write(srv, __FILE__, __LINE__, "dsd", + con->fd, + "packets to write:", +- con->write_queue->used); +-#endif ++ con->output_queue->used); + } +- if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) { ++#endif ++ if (con->is_writable) { + if (-1 == connection_handle_write(srv, con)) { + log_error_write(srv, __FILE__, __LINE__, "ds", + con->fd, +@@ -1758,9 +1833,9 @@ + * - if we have data to write + * - if the socket is not writable yet + */ +- if (!chunkqueue_is_empty(con->write_queue) && +- (con->is_writable == 0) && +- (con->traffic_limit_reached == 0)) { ++ if ((con->is_writable == 0) && ++ (con->traffic_limit_reached == 0) && ++ !connection_queue_is_empty(con)) { + fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT); + } else { + fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); +diff -Naur lighttpd-1.4.19/src/http_chunk.c lighttpd-1.4.19.mod_deflate.jz/src/http_chunk.c +--- lighttpd-1.4.19/src/http_chunk.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/http_chunk.c +@@ -58,16 +58,9 @@ + + cq = con->write_queue; + +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { +- http_chunk_append_len(srv, con, len); +- } + + chunkqueue_append_file(cq, fn, offset, len); + +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) { +- chunkqueue_append_mem(cq, "\r\n", 2 + 1); +- } +- + return 0; + } + +@@ -78,16 +71,9 @@ + + cq = con->write_queue; + +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { +- http_chunk_append_len(srv, con, mem->used - 1); +- } + + chunkqueue_append_buffer(cq, mem); + +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) { +- chunkqueue_append_mem(cq, "\r\n", 2 + 1); +- } +- + return 0; + } + +@@ -99,24 +85,11 @@ + cq = con->write_queue; + + if (len == 0) { +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { +- chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1); +- } else { +- chunkqueue_append_mem(cq, "", 1); +- } + return 0; + } + +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { +- http_chunk_append_len(srv, con, len - 1); +- } +- + chunkqueue_append_mem(cq, mem, len); + +- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { +- chunkqueue_append_mem(cq, "\r\n", 2 + 1); +- } +- + return 0; + } + +diff -Naur lighttpd-1.4.19/src/joblist.c lighttpd-1.4.19.mod_deflate.jz/src/joblist.c +--- lighttpd-1.4.19/src/joblist.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/joblist.c +@@ -7,6 +7,7 @@ + + int joblist_append(server *srv, connection *con) { + if (con->in_joblist) return 0; ++ con->in_joblist = 1; + + if (srv->joblist->size == 0) { + srv->joblist->size = 16; +diff -Naur lighttpd-1.4.19/src/Makefile.am lighttpd-1.4.19.mod_deflate.jz/src/Makefile.am +--- lighttpd-1.4.19/src/Makefile.am ++++ lighttpd-1.4.19.mod_deflate.jz/src/Makefile.am +@@ -241,6 +241,11 @@ + mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined + mod_accesslog_la_LIBADD = $(common_libadd) + ++lib_LTLIBRARIES += mod_deflate.la ++mod_deflate_la_SOURCES = mod_deflate.c ++mod_deflate_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined ++mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd) ++ + + hdr = server.h buffer.h network.h log.h keyvalue.h \ + response.h request.h fastcgi.h chunk.h \ +diff -Naur lighttpd-1.4.19/src/Makefile.in lighttpd-1.4.19.mod_deflate.jz/src/Makefile.in +--- lighttpd-1.4.19/src/Makefile.in ++++ lighttpd-1.4.19.mod_deflate.jz/src/Makefile.in +@@ -158,8 +158,15 @@ + am_mod_compress_la_OBJECTS = mod_compress.lo + mod_compress_la_OBJECTS = $(am_mod_compress_la_OBJECTS) + mod_compress_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(mod_compress_la_LDFLAGS) $(LDFLAGS) -o $@ ++mod_deflate_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ ++ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) ++am_mod_deflate_la_OBJECTS = mod_deflate.lo ++mod_deflate_la_OBJECTS = $(am_mod_deflate_la_OBJECTS) ++mod_deflate_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ ++ $(mod_deflate_la_LDFLAGS) $(LDFLAGS) -o $@ + mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) + am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo +@@ -399,6 +404,7 @@ + $(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) \ +@@ -614,7 +619,7 @@ + mod_ssi.la mod_secdownload.la mod_expire.la mod_evhost.la \ + mod_simple_vhost.la mod_fastcgi.la mod_extforward.la \ + mod_access.la mod_compress.la mod_auth.la mod_rewrite.la \ +- mod_redirect.la mod_status.la mod_accesslog.la ++ mod_redirect.la mod_status.la mod_accesslog.la mod_deflate.la + @NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src) + @NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) + @NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined +@@ -721,6 +726,9 @@ + mod_accesslog_la_SOURCES = mod_accesslog.c + mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined + mod_accesslog_la_LIBADD = $(common_libadd) ++mod_deflate_la_SOURCES = mod_deflate.c ++mod_deflate_la_LDFLAGS = -module -export-dynamic -no-undefined ++mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd) + hdr = server.h buffer.h network.h log.h keyvalue.h \ + response.h request.h fastcgi.h chunk.h \ + settings.h http_chunk.h http_auth_digest.h \ +@@ -832,6 +840,8 @@ + $(mod_cml_la_LINK) -rpath $(libdir) $(mod_cml_la_OBJECTS) $(mod_cml_la_LIBADD) $(LIBS) + mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES) + $(mod_compress_la_LINK) -rpath $(libdir) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS) ++mod_deflate.la: $(mod_deflate_la_OBJECTS) $(mod_deflate_la_DEPENDENCIES) ++ $(mod_deflate_la_LINK) -rpath $(libdir) $(mod_deflate_la_LDFLAGS) $(mod_deflate_la_OBJECTS) $(mod_deflate_la_LIBADD) $(LIBS) + mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES) + $(mod_dirlisting_la_LINK) -rpath $(libdir) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS) + mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES) +@@ -1050,6 +1060,7 @@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_compress.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_deflate.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_dirlisting.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@ +diff -Naur lighttpd-1.4.19/src/mod_deflate.c lighttpd-1.4.19.mod_deflate.jz/src/mod_deflate.c +--- lighttpd-1.4.19/src/mod_deflate.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/mod_deflate.c +@@ -0,0 +1,1420 @@ ++/* bug fix on Robert Jakabosky from alphatrade.com's lighttp 1.4.10 mod_deflate patch ++ * ++ * new module option: ++ * deflate.nocompress-url = "^/nocompressurl/" # pcre regex which don't compress ++ * ++ * Bug fix and new features: ++ * 1) fix loop bug when content-length is bigger than work-block-size*k ++ * 2) prevent compress on buggy http 1.0 client with Accept Encoding: gzip, deflate ++ * 3) fix bug with chunk transfer encoding (under mod_fastcgi+php environment) ++ * ++ * deflate.sync-flush = "enable" is buggy on chunk encoding transfer. Use it carefully, ++ */ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(HAVE_PCRE_H) ++#include ++#endif ++ ++#include "base.h" ++#include "log.h" ++#include "buffer.h" ++#include "response.h" ++#include "joblist.h" ++#include "stat_cache.h" ++ ++#include "plugin.h" ++ ++#include "crc32.h" ++#include "etag.h" ++#include "inet_ntop_cache.h" ++ ++#if defined HAVE_ZLIB_H && defined HAVE_LIBZ ++# define USE_ZLIB ++# include ++#else ++# define Z_DEFAULT_COMPRESSION 1 ++#endif ++ ++#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2 ++# define USE_BZ2LIB ++/* we don't need stdio interface */ ++# define BZ_NO_STDIO ++# include ++#endif ++ ++#include "sys-mmap.h" ++ ++/* request: accept-encoding */ ++#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0) ++#define HTTP_ACCEPT_ENCODING_GZIP BV(1) ++#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2) ++#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3) ++#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4) ++ ++#define KByte * 1024 ++#define MByte * 1024 KByte ++#define GByte * 1024 MByte ++ ++typedef struct { ++ unsigned short debug; ++ unsigned short enabled; ++ unsigned short bzip2; ++ unsigned short sync_flush; ++ unsigned short output_buffer_size; ++ unsigned short min_compress_size; ++ unsigned short work_block_size; ++ short mem_level; ++ short compression_level; ++ short window_size; ++ array *mimetypes; ++ buffer *nocompress_url; ++#if defined(HAVE_PCRE_H) ++ pcre *nocompress_regex; ++#endif ++} plugin_config; ++ ++typedef struct { ++ PLUGIN_DATA; ++ buffer *tmp_buf; ++ ++ plugin_config **config_storage; ++ plugin_config conf; ++} plugin_data; ++ ++typedef struct { ++ int bytes_in; ++ int bytes_out; ++ chunkqueue *in_queue; ++ buffer *output; ++ /* compression type & state */ ++ int compression_type; ++ int stream_open; ++#ifdef USE_ZLIB ++ unsigned long crc; ++ z_stream z; ++ unsigned short gzip_header; ++#endif ++#ifdef USE_BZ2LIB ++ bz_stream bz; ++#endif ++ plugin_data *plugin_data; ++} handler_ctx; ++ ++static handler_ctx *handler_ctx_init() { ++ handler_ctx *hctx; ++ ++ hctx = calloc(1, sizeof(*hctx)); ++ hctx->in_queue = chunkqueue_init(); ++ ++ return hctx; ++} ++ ++static void handler_ctx_free(handler_ctx *hctx) { ++ chunkqueue_free(hctx->in_queue); ++ free(hctx); ++} ++ ++INIT_FUNC(mod_deflate_init) { ++ plugin_data *p; ++ ++ p = calloc(1, sizeof(*p)); ++ ++ p->tmp_buf = buffer_init(); ++ ++ return p; ++} ++ ++FREE_FUNC(mod_deflate_free) { ++ plugin_data *p = p_d; ++ ++ UNUSED(srv); ++ ++ if (!p) return HANDLER_GO_ON; ++ ++ if (p->config_storage) { ++ size_t i; ++ for (i = 0; i < srv->config_context->used; i++) { ++ plugin_config *s = p->config_storage[i]; ++ ++ if (!s) continue; ++ ++ array_free(s->mimetypes); ++ buffer_free(s->nocompress_url); ++#if defined(HAVE_PCRE_H) ++ if (s->nocompress_regex) pcre_free(s->nocompress_regex); ++#endif ++ free(s); ++ } ++ free(p->config_storage); ++ } ++ ++ buffer_free(p->tmp_buf); ++ ++ free(p); ++ ++ return HANDLER_GO_ON; ++} ++ ++SETDEFAULTS_FUNC(mod_deflate_setdefaults) { ++ plugin_data *p = p_d; ++ size_t i = 0; ++ ++ config_values_t cv[] = { ++ { "deflate.output-buffer-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.mimetypes", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.compression-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.mem-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.window-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.min-compress-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.work-block-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.enabled", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.bzip2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.sync-flush", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, ++ { "deflate.nocompress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, ++ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } ++ }; ++ ++ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); ++ ++ for (i = 0; i < srv->config_context->used; i++) { ++ plugin_config *s; ++#if defined(HAVE_PCRE_H) ++ const char *errptr; ++ int erroff; ++#endif ++ ++ s = calloc(1, sizeof(plugin_config)); ++ s->enabled = 1; ++ s->bzip2 = 1; ++ s->sync_flush = 0; ++ s->debug = 0; ++ s->output_buffer_size = 0; ++ s->mem_level = 9; ++ s->window_size = 15; ++ s->min_compress_size = 0; ++ s->work_block_size = 2048; ++ s->compression_level = Z_DEFAULT_COMPRESSION; ++ s->mimetypes = array_init(); ++ s->nocompress_url = buffer_init(); ++#if defined(HAVE_PCRE_H) ++ s->nocompress_regex = NULL; ++#endif ++ ++ cv[0].destination = &(s->output_buffer_size); ++ cv[1].destination = s->mimetypes; ++ cv[2].destination = &(s->compression_level); ++ cv[3].destination = &(s->mem_level); ++ cv[4].destination = &(s->window_size); ++ cv[5].destination = &(s->min_compress_size); ++ cv[6].destination = &(s->work_block_size); ++ cv[7].destination = &(s->enabled); ++ cv[8].destination = &(s->debug); ++ cv[9].destination = &(s->bzip2); ++ cv[10].destination = &(s->sync_flush); ++ cv[11].destination = s->nocompress_url; ++ ++ p->config_storage[i] = s; ++ ++ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { ++ return HANDLER_ERROR; ++ } ++ ++#if defined(HAVE_PCRE_H) ++ if (!buffer_is_empty(s->nocompress_url)) { ++ if (NULL == (s->nocompress_regex = pcre_compile(s->nocompress_url->ptr, ++ 0, &errptr, &erroff, NULL))) { ++ ++ log_error_write(srv, __FILE__, __LINE__, "sbss", ++ "compiling regex for nocompress-url failed:", ++ s->nocompress_url, "pos:", erroff); ++ return HANDLER_ERROR; ++ } ++ } ++#endif ++ if((s->compression_level < 1 || s->compression_level > 9) && ++ s->compression_level != Z_DEFAULT_COMPRESSION) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "compression-level must be between 1 and 9:", s->compression_level); ++ return HANDLER_ERROR; ++ } ++ ++ if(s->mem_level < 1 || s->mem_level > 9) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "mem-level must be between 1 and 9:", s->mem_level); ++ return HANDLER_ERROR; ++ } ++ ++ if(s->window_size < 1 || s->window_size > 15) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "window-size must be between 1 and 15:", s->window_size); ++ return HANDLER_ERROR; ++ } ++ s->window_size = 0 - s->window_size; ++ ++ if(s->sync_flush) { ++ s->output_buffer_size = 0; ++ } ++ } ++ ++ return HANDLER_GO_ON; ++ ++} ++ ++#ifdef USE_ZLIB ++/* Copied gzip_header from apache 2.2's mod_deflate.c */ ++/* RFC 1952 Section 2.3 defines the gzip header: ++ * ++ * +---+---+---+---+---+---+---+---+---+---+ ++ * |ID1|ID2|CM |FLG| MTIME |XFL|OS | ++ * +---+---+---+---+---+---+---+---+---+---+ ++ */ ++static const char gzip_header[10] = ++{ '\037', '\213', Z_DEFLATED, 0, ++ 0, 0, 0, 0, /* mtime */ ++ 0, 0x03 /* Unix OS_CODE */ ++}; ++static int stream_deflate_init(server *srv, connection *con, handler_ctx *hctx) { ++ plugin_data *p = hctx->plugin_data; ++ z_stream *z; ++ ++ UNUSED(srv); ++ UNUSED(con); ++ ++ z = &(hctx->z); ++ z->zalloc = Z_NULL; ++ z->zfree = Z_NULL; ++ z->opaque = Z_NULL; ++ z->total_in = 0; ++ z->total_out = 0; ++ z->next_out = NULL; ++ z->avail_out = 0; ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "output-buffer-size:", p->conf.output_buffer_size); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "compression-level:", p->conf.compression_level); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "mem-level:", p->conf.mem_level); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "window-size:", p->conf.window_size); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "min-compress-size:", p->conf.min_compress_size); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "work-block-size:", p->conf.work_block_size); ++ } ++ if (Z_OK != deflateInit2(z, ++ p->conf.compression_level, ++ Z_DEFLATED, ++ p->conf.window_size, /* supress zlib-header */ ++ p->conf.mem_level, ++ Z_DEFAULT_STRATEGY)) { ++ return -1; ++ } ++ hctx->stream_open = 1; ++ ++ return 0; ++} ++ ++static int stream_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) { ++ plugin_data *p = hctx->plugin_data; ++ z_stream *z; ++ int len; ++ int in = 0, out = 0; ++ ++ UNUSED(srv); ++ z = &(hctx->z); ++ ++ if(z->next_out == NULL) { ++ z->next_out = (unsigned char *)hctx->output->ptr; ++ z->avail_out = hctx->output->size; ++ } ++ ++ if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP) { ++ if(hctx->gzip_header == 0) { ++ hctx->gzip_header = 1; ++ /* copy gzip header into output buffer */ ++ buffer_copy_memory(hctx->output, gzip_header, sizeof(gzip_header)); ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "gzip_header len=", sizeof(gzip_header)); ++ } ++ /* initialize crc32 */ ++ hctx->crc = crc32(0L, Z_NULL, 0); ++ z->next_out = (unsigned char *)(hctx->output->ptr + sizeof(gzip_header)); ++ z->avail_out = hctx->output->size - sizeof(gzip_header); ++ } ++ hctx->crc = crc32(hctx->crc, start, st_size); ++ } ++ ++ z->next_in = start; ++ z->avail_in = st_size; ++ hctx->bytes_in += st_size; ++ ++ /* compress data */ ++ in = z->avail_in; ++ do { ++ if (Z_OK != deflate(z, Z_NO_FLUSH)) { ++ deflateEnd(z); ++ hctx->stream_open = 0; ++ return -1; ++ } ++ ++ if(z->avail_out == 0 || z->avail_in > 0) { ++ len = hctx->output->size - z->avail_out; ++ hctx->bytes_out += len; ++ out += len; ++ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1); ++ z->next_out = (unsigned char *)hctx->output->ptr; ++ z->avail_out = hctx->output->size; ++ } ++ } while (z->avail_in > 0); ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sdsd", ++ "compress: in=", in, ", out=", out); ++ } ++ return 0; ++} ++ ++static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) { ++ plugin_data *p = hctx->plugin_data; ++ z_stream *z; ++ int len; ++ int rc = 0; ++ int done; ++ int flush = 1; ++ int in = 0, out = 0; ++ ++ UNUSED(srv); ++ ++ z = &(hctx->z); ++ ++ if(z->next_out == NULL) { ++ z->next_out = (unsigned char *)hctx->output->ptr; ++ z->avail_out = hctx->output->size; ++ } ++ /* compress data */ ++ in = z->avail_in; ++ do { ++ done = 1; ++ if(end) { ++ rc = deflate(z, Z_FINISH); ++ if (rc == Z_OK) { ++ done = 0; ++ } else if (rc != Z_STREAM_END) { ++ deflateEnd(z); ++ hctx->stream_open = 0; ++ return -1; ++ } ++ } else { ++ if(p->conf.sync_flush) { ++ rc = deflate(z, Z_SYNC_FLUSH); ++ } else if(z->avail_in > 0) { ++ if(p->conf.output_buffer_size > 0) flush = 0; ++ rc = deflate(z, Z_NO_FLUSH); ++ } else { ++ if(p->conf.output_buffer_size > 0) flush = 0; ++ rc = Z_OK; ++ } ++ if (rc != Z_OK) { ++ deflateEnd(z); ++ hctx->stream_open = 0; ++ return -1; ++ } ++ } ++ ++ len = hctx->output->size - z->avail_out; ++ if(z->avail_out == 0 || (flush && len > 0)) { ++ hctx->bytes_out += len; ++ out += len; ++ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1); ++ z->next_out = (unsigned char *)hctx->output->ptr; ++ z->avail_out = hctx->output->size; ++ } ++ } while (z->avail_in != 0 || !done); ++ ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sdsd", ++ "flush: in=", in, ", out=", out); ++ } ++ if(p->conf.sync_flush) { ++ z->next_out = NULL; ++ z->avail_out = 0; ++ } ++ return 0; ++} ++ ++static int stream_deflate_end(server *srv, connection *con, handler_ctx *hctx) { ++ plugin_data *p = hctx->plugin_data; ++ z_stream *z; ++ int rc; ++ ++ UNUSED(srv); ++ ++ z = &(hctx->z); ++ if(!hctx->stream_open) return 0; ++ hctx->stream_open = 0; ++ ++ if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP && hctx->bytes_out > 0 && ++ (unsigned int )hctx->bytes_out >= sizeof(gzip_header)) { ++ /* write gzip footer */ ++ unsigned char c[8]; ++ ++ c[0] = (hctx->crc >> 0) & 0xff; ++ c[1] = (hctx->crc >> 8) & 0xff; ++ c[2] = (hctx->crc >> 16) & 0xff; ++ c[3] = (hctx->crc >> 24) & 0xff; ++ c[4] = (z->total_in >> 0) & 0xff; ++ c[5] = (z->total_in >> 8) & 0xff; ++ c[6] = (z->total_in >> 16) & 0xff; ++ c[7] = (z->total_in >> 24) & 0xff; ++ /* append footer to write_queue */ ++ chunkqueue_append_mem(con->write_queue, (char *)c, 9); ++ hctx->bytes_out += 8; ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "gzip_footer len=", 8); ++ } ++ } ++ ++ if ((rc = deflateEnd(z)) != Z_OK) { ++ if(rc == Z_DATA_ERROR) return 0; ++ if(z->msg != NULL) { ++ log_error_write(srv, __FILE__, __LINE__, "sdss", ++ "deflateEnd error ret=", rc, ", msg=", z->msg); ++ } else { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "deflateEnd error ret=", rc); ++ } ++ return -1; ++ } ++ return 0; ++} ++ ++#endif ++ ++#ifdef USE_BZ2LIB ++static int stream_bzip2_init(server *srv, connection *con, handler_ctx *hctx) { ++ plugin_data *p = hctx->plugin_data; ++ bz_stream *bz; ++ ++ UNUSED(srv); ++ UNUSED(con); ++ ++ bz = &(hctx->bz); ++ bz->bzalloc = NULL; ++ bz->bzfree = NULL; ++ bz->opaque = NULL; ++ bz->total_in_lo32 = 0; ++ bz->total_in_hi32 = 0; ++ bz->total_out_lo32 = 0; ++ bz->total_out_hi32 = 0; ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "output-buffer-size:", p->conf.output_buffer_size); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "compression-level:", p->conf.compression_level); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "mem-level:", p->conf.mem_level); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "window-size:", p->conf.window_size); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "min-compress-size:", p->conf.min_compress_size); ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "work-block-size:", p->conf.work_block_size); ++ } ++ if (BZ_OK != BZ2_bzCompressInit(bz, ++ p->conf.compression_level, /* blocksize = 900k */ ++ 0, /* no output */ ++ 30)) { /* workFactor: default */ ++ return -1; ++ } ++ hctx->stream_open = 1; ++ ++ return 0; ++} ++ ++static int stream_bzip2_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) { ++ plugin_data *p = hctx->plugin_data; ++ bz_stream *bz; ++ int len; ++ int rc; ++ int in = 0, out = 0; ++ ++ UNUSED(srv); ++ ++ bz = &(hctx->bz); ++ ++ if(bz->next_out == NULL) { ++ bz->next_out = hctx->output->ptr; ++ bz->avail_out = hctx->output->size; ++ } ++ ++ bz->next_in = (char *)start; ++ bz->avail_in = st_size; ++ hctx->bytes_in += st_size; ++ ++ /* compress data */ ++ in = bz->avail_in; ++ do { ++ rc = BZ2_bzCompress(bz, BZ_RUN); ++ if (rc != BZ_RUN_OK) { ++ BZ2_bzCompressEnd(bz); ++ hctx->stream_open = 0; ++ return -1; ++ } ++ ++ if(bz->avail_out == 0 || bz->avail_in > 0) { ++ len = hctx->output->size - bz->avail_out; ++ hctx->bytes_out += len; ++ out += len; ++ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1); ++ bz->next_out = hctx->output->ptr; ++ bz->avail_out = hctx->output->size; ++ } ++ } while (bz->avail_in > 0); ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sdsd", ++ "compress: in=", in, ", out=", out); ++ } ++ return 0; ++} ++ ++static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) { ++ plugin_data *p = hctx->plugin_data; ++ bz_stream *bz; ++ int len; ++ int rc; ++ int done; ++ int flush = 1; ++ int in = 0, out = 0; ++ ++ UNUSED(srv); ++ ++ bz = &(hctx->bz); ++ ++ if(bz->next_out == NULL) { ++ bz->next_out = hctx->output->ptr; ++ bz->avail_out = hctx->output->size; ++ } ++ /* compress data */ ++ in = bz->avail_in; ++ do { ++ done = 1; ++ if(end) { ++ rc = BZ2_bzCompress(bz, BZ_FINISH); ++ if (rc == BZ_FINISH_OK) { ++ done = 0; ++ } else if (rc != BZ_STREAM_END) { ++ BZ2_bzCompressEnd(bz); ++ hctx->stream_open = 0; ++ return -1; ++ } ++ } else if(bz->avail_in > 0) { ++ rc = BZ2_bzCompress(bz, BZ_RUN); ++ if (rc != BZ_RUN_OK) { ++ BZ2_bzCompressEnd(bz); ++ hctx->stream_open = 0; ++ return -1; ++ } ++ if(p->conf.output_buffer_size > 0) flush = 0; ++ } ++ ++ len = hctx->output->size - bz->avail_out; ++ if(bz->avail_out == 0 || (flush && len > 0)) { ++ hctx->bytes_out += len; ++ out += len; ++ chunkqueue_append_mem(con->write_queue, hctx->output->ptr, len+1); ++ bz->next_out = hctx->output->ptr; ++ bz->avail_out = hctx->output->size; ++ } ++ } while (bz->avail_in != 0 || !done); ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sdsd", ++ "flush: in=", in, ", out=", out); ++ } ++ if(p->conf.sync_flush) { ++ bz->next_out = NULL; ++ bz->avail_out = 0; ++ } ++ return 0; ++} ++ ++static int stream_bzip2_end(server *srv, connection *con, handler_ctx *hctx) { ++ plugin_data *p = hctx->plugin_data; ++ bz_stream *bz; ++ int rc; ++ ++ UNUSED(p); ++ UNUSED(con); ++ ++ bz = &(hctx->bz); ++ if(!hctx->stream_open) return 0; ++ hctx->stream_open = 0; ++ ++ if ((rc = BZ2_bzCompressEnd(bz)) != BZ_OK) { ++ if(rc == BZ_DATA_ERROR) return 0; ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "BZ2_bzCompressEnd error ret=", rc); ++ return -1; ++ } ++ return 0; ++} ++ ++#endif ++ ++static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) { ++ int ret = -1; ++ if(st_size == 0) return 0; ++ switch(hctx->compression_type) { ++#ifdef USE_ZLIB ++ case HTTP_ACCEPT_ENCODING_GZIP: ++ case HTTP_ACCEPT_ENCODING_DEFLATE: ++ ret = stream_deflate_compress(srv, con, hctx, start, st_size); ++ break; ++#endif ++#ifdef USE_BZ2LIB ++ case HTTP_ACCEPT_ENCODING_BZIP2: ++ ret = stream_bzip2_compress(srv, con, hctx, start, st_size); ++ break; ++#endif ++ default: ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) { ++ int ret = -1; ++ if(hctx->bytes_in == 0) return 0; ++ switch(hctx->compression_type) { ++#ifdef USE_ZLIB ++ case HTTP_ACCEPT_ENCODING_GZIP: ++ case HTTP_ACCEPT_ENCODING_DEFLATE: ++ ret = stream_deflate_flush(srv, con, hctx, end); ++ break; ++#endif ++#ifdef USE_BZ2LIB ++ case HTTP_ACCEPT_ENCODING_BZIP2: ++ ret = stream_bzip2_flush(srv, con, hctx, end); ++ break; ++#endif ++ default: ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int mod_deflate_stream_end(server *srv, connection *con, handler_ctx *hctx) { ++ int ret = -1; ++ switch(hctx->compression_type) { ++#ifdef USE_ZLIB ++ case HTTP_ACCEPT_ENCODING_GZIP: ++ case HTTP_ACCEPT_ENCODING_DEFLATE: ++ ret = stream_deflate_end(srv, con, hctx); ++ break; ++#endif ++#ifdef USE_BZ2LIB ++ case HTTP_ACCEPT_ENCODING_BZIP2: ++ ret = stream_bzip2_end(srv, con, hctx); ++ break; ++#endif ++ default: ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hctx, chunk *c, off_t st_size) { ++ plugin_data *p = hctx->plugin_data; ++ off_t abs_offset; ++ off_t toSend; ++ stat_cache_entry *sce = NULL; ++ off_t we_want_to_mmap = 2 MByte; ++ off_t we_want_to_send = st_size; ++ char *start = NULL; ++ ++ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ strerror(errno), c->file.name); ++ return -1; ++ } ++ ++ abs_offset = c->file.start + c->offset; ++ ++ if (abs_offset > sce->st.st_size) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "file was shrinked:", c->file.name); ++ ++ return -1; ++ } ++ ++ we_want_to_send = st_size; ++ /* mmap the buffer ++ * - first mmap ++ * - new mmap as the we are at the end of the last one */ ++ if (c->file.mmap.start == MAP_FAILED || ++ abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) { ++ ++ /* Optimizations for the future: ++ * ++ * adaptive mem-mapping ++ * the problem: ++ * we mmap() the whole file. If someone has alot large files and 32bit ++ * machine the virtual address area will be unrun and we will have a failing ++ * mmap() call. ++ * solution: ++ * only mmap 16M in one chunk and move the window as soon as we have finished ++ * the first 8M ++ * ++ * read-ahead buffering ++ * the problem: ++ * sending out several large files in parallel trashes the read-ahead of the ++ * kernel leading to long wait-for-seek times. ++ * solutions: (increasing complexity) ++ * 1. use madvise ++ * 2. use a internal read-ahead buffer in the chunk-structure ++ * 3. use non-blocking IO for file-transfers ++ * */ ++ ++ /* all mmap()ed areas are 512kb expect the last which might be smaller */ ++ size_t to_mmap; ++ ++ /* this is a remap, move the mmap-offset */ ++ if (c->file.mmap.start != MAP_FAILED) { ++ munmap(c->file.mmap.start, c->file.mmap.length); ++ c->file.mmap.offset += we_want_to_mmap; ++ } else { ++ /* in case the range-offset is after the first mmap()ed area we skip the area */ ++ c->file.mmap.offset = 0; ++ ++ while (c->file.mmap.offset + we_want_to_mmap < c->file.start) { ++ c->file.mmap.offset += we_want_to_mmap; ++ } ++ } ++ ++ /* length is rel, c->offset too, assume there is no limit at the mmap-boundaries */ ++ to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset; ++ if(to_mmap > we_want_to_mmap) to_mmap = we_want_to_mmap; ++ /* we have more to send than we can mmap() at once */ ++ if(we_want_to_send > to_mmap) we_want_to_send = to_mmap; ++ ++ if (-1 == c->file.fd) { /* open the file if not already open */ ++ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { ++ log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno)); ++ ++ return -1; ++ } ++#ifdef FD_CLOEXEC ++ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC); ++#endif ++ } ++ ++ if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) { ++ /* close it here, otherwise we'd have to set FD_CLOEXEC */ ++ ++ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", ++ strerror(errno), c->file.name, c->file.fd); ++ ++ return -1; ++ } ++ ++ c->file.mmap.length = to_mmap; ++#ifdef LOCAL_BUFFERING ++ buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length); ++#else ++#ifdef HAVE_MADVISE ++ /* don't advise files < 64Kb */ ++ if (c->file.mmap.length > (64 KByte) && ++ 0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) { ++ log_error_write(srv, __FILE__, __LINE__, "ssbd", "madvise failed:", ++ strerror(errno), c->file.name, c->file.fd); ++ } ++#endif ++#endif ++ ++ /* chunk_reset() or chunk_free() will cleanup for us */ ++ } ++ ++ /* to_send = abs_mmap_end - abs_offset */ ++ toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset); ++ if(toSend > we_want_to_send) toSend = we_want_to_send; ++ ++ if (toSend < 0) { ++ log_error_write(srv, __FILE__, __LINE__, "soooo", ++ "toSend is negative:", ++ toSend, ++ c->file.mmap.length, ++ abs_offset, ++ c->file.mmap.offset); ++ assert(toSend < 0); ++ } ++ ++#ifdef LOCAL_BUFFERING ++ start = c->mem->ptr; ++#else ++ start = c->file.mmap.start; ++#endif ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sdsd", ++ "compress file chunk: offset=", (int)c->offset, ++ ", toSend=", (int)toSend); ++ } ++ if (mod_deflate_compress(srv, con, hctx, ++ (unsigned char *)start + (abs_offset - c->file.mmap.offset), toSend) < 0) { ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "compress failed."); ++ return -1; ++ } ++ ++ c->offset += toSend; ++ if (c->offset == c->file.length) { ++ /* we don't need the mmaping anymore */ ++ if (c->file.mmap.start != MAP_FAILED) { ++ munmap(c->file.mmap.start, c->file.mmap.length); ++ c->file.mmap.start = MAP_FAILED; ++ } ++ } ++ ++ return toSend; ++} ++ ++static int deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) { ++ plugin_data *p = hctx->plugin_data; ++ int rc; ++ ++ rc = mod_deflate_stream_end(srv, con, hctx); ++ if(rc < 0) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "error closing stream"); ++ } ++ ++ if (hctx->bytes_in < hctx->bytes_out) { ++ log_error_write(srv, __FILE__, __LINE__, "sbsdsd", ++ "uri ", con->uri.path_raw, " in=", hctx->bytes_in, " smaller than out=", hctx->bytes_out); ++ } ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sdsd", ++ " in:", hctx->bytes_in, ++ " out:", hctx->bytes_out); ++ } ++ ++ /* cleanup compression state */ ++ if(hctx->output != p->tmp_buf) { ++ buffer_free(hctx->output); ++ } ++ handler_ctx_free(hctx); ++ con->plugin_ctx[p->id] = NULL; ++ ++ return 0; ++} ++ ++static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx, int end) { ++ plugin_data *p = hctx->plugin_data; ++ chunk *c; ++ size_t chunks_written = 0; ++ int chunk_finished = 0; ++ int rc=-1; ++ int close_stream = 0, len = 0; ++ unsigned int out = 0, max = 0; ++ ++ /* move all chunk from write_queue into our in_queue */ ++ chunkqueue_append_chunkqueue(hctx->in_queue, con->write_queue); ++ ++ len = chunkqueue_length(hctx->in_queue); ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "compress: in_queue len=", len); ++ } ++ /* calculate max bytes to compress for this call. */ ++ if(!end) { ++ max = p->conf.work_block_size * 1024; ++ if(max == 0 || max > len) max = len; ++ } else { ++ max = len; ++ } ++ ++ /* Compress chunks from in_queue into chunks for write_queue */ ++ for(c = hctx->in_queue->first; c && out < max; c = c->next) { ++ chunk_finished = 0; ++ len = 0; ++ ++ switch(c->type) { ++ case MEM_CHUNK: ++ len = c->mem->used - 1; ++ if(len > (max - out)) len = max - out; ++ if (mod_deflate_compress(srv, con, hctx, (unsigned char *)c->mem->ptr, len) < 0) { ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "compress failed."); ++ return HANDLER_ERROR; ++ } ++ c->offset += len; ++ out += len; ++ if (c->offset == c->mem->used - 1) { ++ chunk_finished = 1; ++ chunks_written++; ++ } ++ break; ++ case FILE_CHUNK: ++ len = c->file.length - c->offset; ++ if(len > (max - out)) len = max - out; ++ if ((len = mod_deflate_file_chunk(srv, con, hctx, c, len)) < 0) { ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "compress file chunk failed."); ++ return HANDLER_ERROR; ++ } ++ out += len; ++ if (c->offset == c->file.length) { ++ chunk_finished = 1; ++ chunks_written++; ++ } ++ break; ++ default: ++ ++ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); ++ ++ return HANDLER_ERROR; ++ } ++ if(!chunk_finished) break; ++ } ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "compressed bytes:", out); ++ } ++ hctx->in_queue->bytes_out += out; ++ ++ if(chunks_written > 0) { ++ chunkqueue_remove_finished_chunks(hctx->in_queue); ++ } ++ ++ close_stream = (con->file_finished && chunkqueue_is_empty(hctx->in_queue)); ++ rc = mod_deflate_stream_flush(srv, con, hctx, close_stream); ++ if(rc < 0) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "flush error"); ++ } ++ if(close_stream || end) { ++ deflate_compress_cleanup(srv, con, hctx); ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sbsb", ++ "finished uri:", con->uri.path_raw, ", query:", con->uri.query); ++ } ++ return HANDLER_FINISHED; ++ } else { ++ if(!chunkqueue_is_empty(hctx->in_queue)) { ++ /* We have more data to compress. */ ++ joblist_append(srv, con); ++ } ++ return HANDLER_COMEBACK; ++ } ++} ++ ++#define PATCH(x) \ ++ p->conf.x = s->x; ++static int mod_deflate_patch_connection(server *srv, connection *con, plugin_data *p) { ++ size_t i, j; ++ plugin_config *s = p->config_storage[0]; ++ ++ PATCH(output_buffer_size); ++ PATCH(mimetypes); ++ PATCH(compression_level); ++ PATCH(mem_level); ++ PATCH(window_size); ++ PATCH(min_compress_size); ++ PATCH(work_block_size); ++ PATCH(enabled); ++ PATCH(debug); ++ PATCH(bzip2); ++ PATCH(sync_flush); ++#if defined(HAVE_PCRE_H) ++ PATCH(nocompress_regex); ++#endif ++ ++ /* skip the first, the global context */ ++ for (i = 1; i < srv->config_context->used; i++) { ++ data_config *dc = (data_config *)srv->config_context->data[i]; ++ s = p->config_storage[i]; ++ ++ /* condition didn't match */ ++ if (!config_check_cond(srv, con, dc)) continue; ++ ++ /* merge config */ ++ for (j = 0; j < dc->value->used; j++) { ++ data_unset *du = dc->value->data[j]; ++ ++ if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.output-buffer-size"))) { ++ PATCH(output_buffer_size); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.mimetypes"))) { ++ PATCH(mimetypes); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.compression-level"))) { ++ PATCH(compression_level); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.mem-level"))) { ++ PATCH(mem_level); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.window-size"))) { ++ PATCH(window_size); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.min-compress-size"))) { ++ PATCH(min_compress_size); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.work-block-size"))) { ++ PATCH(work_block_size); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.enabled"))) { ++ PATCH(enabled); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.debug"))) { ++ PATCH(debug); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.bzip2"))) { ++ PATCH(bzip2); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.sync-flush"))) { ++ PATCH(sync_flush); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.nocompress-url"))) { ++#if defined(HAVE_PCRE_H) ++ PATCH(nocompress_regex); ++#endif ++ } ++ } ++ } ++ ++ return 0; ++} ++#undef PATCH ++ ++PHYSICALPATH_FUNC(mod_deflate_handle_response_start) { ++ plugin_data *p = p_d; ++ handler_ctx *hctx; ++ data_string *ds; ++ int accept_encoding = 0; ++ char *value; ++ int srv_encodings = 0; ++ int matched_encodings = 0; ++ const char *dflt_gzip = "gzip"; ++ const char *dflt_deflate = "deflate"; ++ const char *dflt_bzip2 = "bzip2"; ++ const char *compression_name = NULL; ++ int file_len=0; ++ int rc=-2; ++ int end = 0; ++ size_t m; ++#if defined(HAVE_PCRE_H) ++ int n; ++# define N 10 ++ int ovec[N * 3]; ++#endif ++ ++ /* disable compression for some http status types. */ ++ switch(con->http_status) { ++ case 100: ++ case 101: ++ case 204: ++ case 205: ++ case 304: ++ /* disable compression as we have no response entity */ ++ return HANDLER_GO_ON; ++ default: ++ break; ++ } ++ ++ mod_deflate_patch_connection(srv, con, p); ++ ++ /* is compression allowed */ ++ if(!p->conf.enabled) { ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "compression disabled."); ++ } ++ return HANDLER_GO_ON; ++ } ++ ++#if defined(HAVE_PCRE_H) ++ if(p->conf.nocompress_regex) { /*check no compress regex now */ ++ if ((n = pcre_exec(p->conf.nocompress_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) { ++ if (n != PCRE_ERROR_NOMATCH) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "execution error while matching:", n); ++ return HANDLER_ERROR; ++ } ++ } else { ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", "no compress for url:", con->uri.path); ++ } ++ return HANDLER_GO_ON; ++ } ++ } ++#endif ++ /* Check if response has a Content-Encoding. */ ++ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Encoding"))) { ++ return HANDLER_GO_ON; ++ } ++ ++ /* Check Accept-Encoding for supported encoding. */ ++ if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) { ++ return HANDLER_GO_ON; ++ } ++ ++ /* get client side support encodings */ ++ value = ds->value->ptr; ++#ifdef USE_ZLIB ++ if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP; ++ if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE; ++#endif ++ /* if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; */ ++#ifdef USE_BZ2LIB ++ if(p->conf.bzip2) { ++ if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2; ++ } ++#endif ++ if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY; ++ ++ /* get server side supported ones */ ++#ifdef USE_BZ2LIB ++ if(p->conf.bzip2) { ++ srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2; ++ } ++#endif ++#ifdef USE_ZLIB ++ srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP; ++ srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE; ++#endif ++ ++ /* find matching encodings */ ++ matched_encodings = accept_encoding & srv_encodings; ++ if (!matched_encodings) { ++ return HANDLER_GO_ON; ++ } ++ ++ if (con->request.true_http_10_client) { ++ /*disable gzip/bzip2 when we meet HTTP 1.0 client with Accept-Encoding ++ * maybe old buggy proxy server ++ */ ++ /* most of buggy clients are Yahoo Slurp;) */ ++ if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ss", ++ "Buggy HTTP 1.0 client sending Accept Encoding: gzip, deflate", ++ (char *) inet_ntop_cache_get_ip(srv, &(con->dst_addr))); ++ return HANDLER_GO_ON; ++ } ++ /* check if size of response is below min-compress-size */ ++ if(con->file_finished && con->request.http_method != HTTP_METHOD_HEAD) { ++ file_len = chunkqueue_length(con->write_queue); ++ if(file_len == 0) return HANDLER_GO_ON; ++ } else { ++ file_len = 0; ++ } ++ ++ if(file_len > 0 && p->conf.min_compress_size > 0 && file_len < p->conf.min_compress_size) { ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "Content-Length smaller then min_compress_size: file_len=", file_len); ++ } ++ return HANDLER_GO_ON; ++ } ++ ++ /* Check mimetype in response header "Content-Type" */ ++ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) { ++ int found = 0; ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "Content-Type:", ds->value); ++ } ++ for (m = 0; m < p->conf.mimetypes->used; m++) { ++ data_string *mimetype = (data_string *)p->conf.mimetypes->data[m]; ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "mime-type:", mimetype->value); ++ } ++ if (strncmp(mimetype->value->ptr, ds->value->ptr, mimetype->value->used-1) == 0) { ++/* if (buffer_is_equal(mimetype->value, ds->value)) { */ ++ /* mimetype found */ ++ found = 1; ++ break; ++ } ++ } ++ if(!found && p->conf.mimetypes->used > 0) { ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "No compression for mimetype:", ds->value); ++ } ++ return HANDLER_GO_ON; ++ } ++#if 0 ++ if(strncasecmp(ds->value->ptr, "application/x-javascript", 24) == 0) { ++ /*reset compress type to deflate for javascript ++ * prevent buggy IE6 SP1 doesn't work for js in IFrame ++ */ ++ matched_encodings = HTTP_ACCEPT_ENCODING_DEFLATE; ++ } ++#endif ++ } ++ ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "enable compression for ", con->uri.path); ++ } ++ ++ /* the response might change according to Accept-Encoding */ ++ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Vary"))) { ++ /* append Accept-Encoding to Vary header */ ++ if (NULL == strstr(ds->value->ptr, "Accept-Encoding")) { ++ buffer_append_string(ds->value, ",Accept-Encoding"); ++ if (p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "appending ,Accept-Encoding for ", con->uri.path); ++ } ++ } ++ } else { ++ if (p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "add Vary: Accept-Encoding for ", con->uri.path); ++ } ++ response_header_insert(srv, con, CONST_STR_LEN("Vary"), ++ CONST_STR_LEN("Accept-Encoding")); ++ } ++ ++ /* enable compression */ ++ hctx = handler_ctx_init(); ++ hctx->plugin_data = p; ++ ++ /* select best matching encoding */ ++ if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) { ++ hctx->compression_type = HTTP_ACCEPT_ENCODING_BZIP2; ++ compression_name = dflt_bzip2; ++ rc = stream_bzip2_init(srv, con, hctx); ++ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_GZIP) { ++ hctx->compression_type = HTTP_ACCEPT_ENCODING_GZIP; ++ compression_name = dflt_gzip; ++ rc = stream_deflate_init(srv, con, hctx); ++ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE) { ++ hctx->compression_type = HTTP_ACCEPT_ENCODING_DEFLATE; ++ compression_name = dflt_deflate; ++ rc = stream_deflate_init(srv, con, hctx); ++ } ++ if(rc == -1) { ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "Failed to initialize compression."); ++ } ++ ++ if(rc < 0) { ++ handler_ctx_free(hctx); ++ return HANDLER_GO_ON; ++ } ++ ++ /* setup output buffer. */ ++ if(p->conf.sync_flush || p->conf.output_buffer_size == 0) { ++ buffer_prepare_copy(p->tmp_buf, 32 * 1024); ++ hctx->output = p->tmp_buf; ++ } else { ++ hctx->output = buffer_init(); ++ buffer_prepare_copy(hctx->output, p->conf.output_buffer_size); ++ } ++ con->plugin_ctx[p->id] = hctx; ++ ++ /* set Content-Encoding to show selected compression type. */ ++ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name)); ++ ++ if (con->file_finished) end = 1; ++ ++ con->parsed_response &= ~(HTTP_CONTENT_LENGTH); ++#if 0 ++ /* debug */ ++ if (con->parsed_response & HTTP_TRANSFER_ENCODING_CHUNKED) ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "deflate: response with chunked encoding"); ++ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "deflate: transfer encoding with chunked encoding"); ++#endif ++ ++ if (con->file_finished && (p->conf.work_block_size == 0 || file_len < (p->conf.work_block_size * 1024)) ++ && con->request.http_method != HTTP_METHOD_HEAD) { ++ /* disable chunk transfer */ ++ con->response.transfer_encoding = 0; ++ con->parsed_response &= ~(HTTP_TRANSFER_ENCODING_CHUNKED); ++ if(p->conf.debug) { ++ log_error_write(srv, __FILE__, __LINE__, "sd", ++ "Compress all content and use Content-Length header: uncompress len=", file_len); ++ } ++ return deflate_compress_response(srv, con, hctx, end); ++ } else { ++ if (con->request.http_version == HTTP_VERSION_1_1) { ++ if (p->conf.debug) ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "chunk transfer encoding for uri", con->uri.path); ++ /* Make sure to use chunked encoding. */ ++ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; ++ } else { ++ if (p->conf.debug) ++ log_error_write(srv, __FILE__, __LINE__, "sb", ++ "http 1.0 encoding for uri", con->uri.path); ++ /* We don't have to use chunked encoding because HTTP 1.0 don't support it. */ ++ con->response.transfer_encoding = 0; ++ con->parsed_response &= ~(HTTP_TRANSFER_ENCODING_CHUNKED); ++ } ++ } ++ ++ if (p->conf.debug) ++ log_error_write(srv, __FILE__, __LINE__, "sdsb", "end =", end, "for uri", con->uri.path); ++ ++ deflate_compress_response(srv, con, hctx, end); ++ return HANDLER_GO_ON; ++} ++ ++JOBLIST_FUNC(mod_deflate_handle_response_filter) { ++ plugin_data *p = p_d; ++ handler_ctx *hctx = con->plugin_ctx[p->id]; ++ ++ if(hctx == NULL) return HANDLER_GO_ON; ++ if(!hctx->stream_open) return HANDLER_GO_ON; ++ if(con->request.http_method == HTTP_METHOD_HEAD) return HANDLER_GO_ON; ++ ++ return deflate_compress_response(srv, con, hctx, 0); ++} ++ ++handler_t mod_deflate_cleanup(server *srv, connection *con, void *p_d) { ++ plugin_data *p = p_d; ++ handler_ctx *hctx = con->plugin_ctx[p->id]; ++ ++ if(hctx == NULL) return HANDLER_GO_ON; ++ ++ if(p->conf.debug && hctx->stream_open) { ++ log_error_write(srv, __FILE__, __LINE__, "sbsb", ++ "stream open at cleanup. uri=", con->uri.path_raw, ", query=", con->uri.query); ++ } ++ ++ deflate_compress_cleanup(srv, con, hctx); ++ ++ return HANDLER_GO_ON; ++} ++ ++int mod_deflate_plugin_init(plugin *p) { ++ p->version = LIGHTTPD_VERSION_ID; ++ p->name = buffer_init_string("deflate"); ++ ++ p->init = mod_deflate_init; ++ p->cleanup = mod_deflate_free; ++ p->set_defaults = mod_deflate_setdefaults; ++ p->connection_reset = mod_deflate_cleanup; ++ p->handle_connection_close = mod_deflate_cleanup; ++ p->handle_response_start = mod_deflate_handle_response_start; ++ p->handle_response_filter = mod_deflate_handle_response_filter; ++ ++ p->data = NULL; ++ ++ return 0; ++} +diff -Naur lighttpd-1.4.19/src/plugin.c lighttpd-1.4.19.mod_deflate.jz/src/plugin.c +--- lighttpd-1.4.19/src/plugin.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/plugin.c +@@ -40,6 +40,8 @@ + PLUGIN_FUNC_HANDLE_SIGHUP, + PLUGIN_FUNC_HANDLE_SUBREQUEST, + PLUGIN_FUNC_HANDLE_SUBREQUEST_START, ++ PLUGIN_FUNC_HANDLE_RESPONSE_START, ++ PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, + PLUGIN_FUNC_HANDLE_JOBLIST, + PLUGIN_FUNC_HANDLE_DOCROOT, + PLUGIN_FUNC_HANDLE_PHYSICAL, +@@ -266,6 +268,8 @@ + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) ++PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start) ++PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, handle_response_filter) + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist) + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) +@@ -395,6 +399,8 @@ + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup); + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest); + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start); ++ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start); ++ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_FILTER, handle_response_filter); + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist); + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot); + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical); +diff -Naur lighttpd-1.4.19/src/plugin.h lighttpd-1.4.19.mod_deflate.jz/src/plugin.h +--- lighttpd-1.4.19/src/plugin.h ++++ lighttpd-1.4.19.mod_deflate.jz/src/plugin.h +@@ -54,6 +54,8 @@ + * has to be found + */ + handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */ ++ handler_t (* handle_response_start) (server *srv, connection *con, void *p_d); /* before response headers are written */ ++ handler_t (* handle_response_filter) (server *srv, connection *con, void *p_d); /* response content filter */ + handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */ + void *data; + +@@ -68,6 +70,8 @@ + handler_t plugins_call_handle_uri_clean(server *srv, connection *con); + handler_t plugins_call_handle_subrequest_start(server *srv, connection *con); + handler_t plugins_call_handle_subrequest(server *srv, connection *con); ++handler_t plugins_call_handle_response_start(server *srv, connection *con); ++handler_t plugins_call_handle_response_filter(server *srv, connection *con); + handler_t plugins_call_handle_request_done(server *srv, connection *con); + handler_t plugins_call_handle_docroot(server *srv, connection *con); + handler_t plugins_call_handle_physical(server *srv, connection *con); +diff -Naur lighttpd-1.4.19/src/request.c lighttpd-1.4.19.mod_deflate.jz/src/request.c +--- lighttpd-1.4.19/src/request.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/request.c +@@ -415,8 +415,10 @@ + + if (major_num == 1 && minor_num == 1) { + con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0; ++ con->request.true_http_10_client = 0; + } else if (major_num == 1 && minor_num == 0) { + con->request.http_version = HTTP_VERSION_1_0; ++ con->request.true_http_10_client = 1; + } else { + con->http_status = 505; + +diff -Naur lighttpd-1.4.19/src/response.c lighttpd-1.4.19.mod_deflate.jz/src/response.c +--- lighttpd-1.4.19/src/response.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/response.c +@@ -32,7 +32,7 @@ + int have_date = 0; + int have_server = 0; + +- b = chunkqueue_get_prepend_buffer(con->write_queue); ++ b = chunkqueue_get_prepend_buffer(con->output_queue); + + if (con->request.http_version == HTTP_VERSION_1_1) { + BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 "); +@@ -49,6 +49,8 @@ + } + + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { ++/* if (!(con->parsed_response & HTTP_TRANSFER_ENCODING_CHUNKED) && ++ (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED)) { */ + BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked"); + } + +@@ -65,6 +67,16 @@ + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1; + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1; + ++ /* remove Transfer-Encoding: chunked header when HTTP 1.0 ++ * or transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED == 0 ++ */ ++ if ( (con->request.http_version == HTTP_VERSION_1_0 || ++ !(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED)) && ++ 0 == strncasecmp(ds->value->ptr, "chunked", sizeof("chunked")-1) && ++ 0 == strncasecmp(ds->key->ptr, "Transfer-Encoding", sizeof("Transfer-Encoding") - 1)) { ++ continue ; ++ } ++ + BUFFER_APPEND_STRING_CONST(b, "\r\n"); + buffer_append_string_buffer(b, ds->key); + BUFFER_APPEND_STRING_CONST(b, ": "); +@@ -576,7 +588,7 @@ + } + + if (slash) pathinfo = slash; +- } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2))); ++ } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > con->physical.basedir->used - 2)); + + if (found == 0) { + /* no it really doesn't exists */ +diff -Naur lighttpd-1.4.19/src/server.c lighttpd-1.4.19.mod_deflate.jz/src/server.c +--- lighttpd-1.4.19/src/server.c ++++ lighttpd-1.4.19.mod_deflate.jz/src/server.c +@@ -203,6 +203,9 @@ + srv->joblist = calloc(1, sizeof(*srv->joblist)); + assert(srv->joblist); + ++ srv->joblist_prev = calloc(1, sizeof(*srv->joblist)); ++ assert(srv->joblist_prev); ++ + srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue)); + assert(srv->fdwaitqueue); + +@@ -294,6 +297,7 @@ + #undef CLEAN + + joblist_free(srv, srv->joblist); ++ joblist_free(srv, srv->joblist_prev); + fdwaitqueue_free(srv, srv->fdwaitqueue); + + if (srv->stat_cache) { +@@ -1137,6 +1141,7 @@ + /* main-loop */ + while (!srv_shutdown) { + int n; ++ int timeout; + size_t ndx; + time_t min_ts; + +@@ -1388,7 +1393,12 @@ + } + } + +- if ((n = fdevent_poll(srv->ev, 1000)) > 0) { ++ if(srv->joblist->used > 0) { ++ timeout = 500; ++ } else { ++ timeout = 1000; ++ } ++ if ((n = fdevent_poll(srv->ev, timeout)) > 0) { + /* n is the number of events */ + int revents; + int fd_ndx; +@@ -1436,10 +1446,16 @@ + strerror(errno)); + } + +- for (ndx = 0; ndx < srv->joblist->used; ndx++) { +- connection *con = srv->joblist->ptr[ndx]; ++ if(srv->joblist->used > 0) { ++ connections *joblist = srv->joblist; ++ /* switch joblist queues. */ ++ srv->joblist = srv->joblist_prev; ++ srv->joblist_prev = joblist; ++ for (ndx = 0; ndx < joblist->used; ndx++) { ++ connection *con = joblist->ptr[ndx]; + handler_t r; + ++ con->in_joblist = 0; + connection_state_machine(srv, con); + + switch(r = plugins_call_handle_joblist(srv, con)) { +@@ -1450,11 +1466,9 @@ + log_error_write(srv, __FILE__, __LINE__, "d", r); + break; + } +- +- con->in_joblist = 0; + } +- +- srv->joblist->used = 0; ++ joblist->used = 0; ++ } + } + + if (srv->srvconf.pid_file->used && diff --git a/lighttpd-mod_dirlisting.conf b/lighttpd-mod_dirlisting.conf new file mode 100644 index 0000000..ba9cc52 --- /dev/null +++ b/lighttpd-mod_dirlisting.conf @@ -0,0 +1,9 @@ +# Virtual directory listings. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModDirlisting + +# NOTE: this module is automatically loaded + +#dir-listing.encoding = "utf-8" +#dir-listing.activate = "enable" +dir-listing.hide-dotfiles = "enable" diff --git a/lighttpd-mod_evasive-status_code.patch b/lighttpd-mod_evasive-status_code.patch new file mode 100644 index 0000000..02cbd9e --- /dev/null +++ b/lighttpd-mod_evasive-status_code.patch @@ -0,0 +1,97 @@ +--- lighttpd-1.4.19/src/mod_evasive.c 2008-09-19 17:50:24.307245276 +0300 ++++ lighttpd-1.4.22/src/mod_evasive.c 2009-05-12 02:21:58.524447939 +0300 +@@ -28,11 +28,15 @@ + typedef struct { + unsigned short max_conns; + unsigned short silent; ++ unsigned short http_status_code; ++ unsigned int retry_after; + } plugin_config; + + typedef struct { + PLUGIN_DATA; + ++ buffer *evasive_rftmp; ++ + plugin_config **config_storage; + + plugin_config conf; +@@ -46,6 +50,10 @@ + + p = calloc(1, sizeof(*p)); + ++ p->evasive_rftmp = buffer_init(); ++ ++ buffer_prepare_copy(p->evasive_rftmp, 255); ++ + return p; + } + +@@ -56,6 +64,8 @@ + + if (!p) return HANDLER_GO_ON; + ++ buffer_free(p->evasive_rftmp); ++ + if (p->config_storage) { + size_t i; + for (i = 0; i < srv->config_context->used; i++) { +@@ -85,6 +85,8 @@ + config_values_t cv[] = { + { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ + { "evasive.silent", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ ++ { "evasive.http-status-code", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ ++ { "evasive.retry-after", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } + }; + +@@ -94,11 +96,15 @@ + plugin_config *s; + + s = calloc(1, sizeof(plugin_config)); +- s->max_conns = 0; +- s->silent = 0; ++ s->max_conns = 0; ++ s->silent = 0; ++ s->http_status_code = 503; ++ s->retry_after = 0; + + cv[0].destination = &(s->max_conns); + cv[1].destination = &(s->silent); ++ cv[2].destination = &(s->http_status_code); ++ cv[3].destination = &(s->retry_after); + + p->config_storage[i] = s; + +@@ -107,6 +123,8 @@ + + PATCH(max_conns); + PATCH(silent); ++ PATCH(http_status_code); ++ PATCH(retry_after); + + /* skip the first, the global context */ + for (i = 1; i < srv->config_context->used; i++) { +@@ -124,6 +142,10 @@ + PATCH(max_conns); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.silent"))) { + PATCH(silent); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.http-status-code"))) { ++ PATCH(http_status_code); ++ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.retry-after"))) { ++ PATCH(retry_after); + } + } + } +@@ -192,8 +214,10 @@ + inet_ntop_cache_get_ip(srv, &(con->dst_addr)), + "turned away. Too many connections."); + +- con->http_status = 403; + con->mode = DIRECT; ++ con->http_status = p->conf.http_status_code; ++ buffer_copy_long(p->evasive_rftmp, p->conf.retry_after); ++ response_header_overwrite(srv, con, CONST_STR_LEN("Retry-After"), CONST_BUF_LEN(p->evasive_rftmp)); + return HANDLER_FINISHED; + } + } diff --git a/lighttpd-mod_evasive.conf b/lighttpd-mod_evasive.conf new file mode 100644 index 0000000..8ecb17f --- /dev/null +++ b/lighttpd-mod_evasive.conf @@ -0,0 +1,12 @@ +# Evasive module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModEvasive + +server.modules += ( + "mod_evasive" +) + +## +## Limits number of connections per IP +## +#evasive.max-conns-per-ip = 5 diff --git a/lighttpd-mod_evhost.conf b/lighttpd-mod_evhost.conf new file mode 100644 index 0000000..744068a --- /dev/null +++ b/lighttpd-mod_evhost.conf @@ -0,0 +1,17 @@ +# Enhanced virtual-hosting module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModEVhost + +server.modules += ( + "mod_evhost" +) + +# define a pattern for the host url finding +# %% => % sign +# %0 => domain name + tld +# %1 => tld +# %2 => domain name without tld +# %3 => subdomain 1 name +# %4 => subdomain 2 name +# +#evhost.path-pattern = "/home/storage/dev/www/%3/htdocs/" diff --git a/lighttpd-mod_expire.conf b/lighttpd-mod_expire.conf new file mode 100644 index 0000000..d8f6daa --- /dev/null +++ b/lighttpd-mod_expire.conf @@ -0,0 +1,12 @@ +# Expires module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModExpire + +server.modules += ( + "mod_expire" +) + +#expire.url = ( +# "/buggy/" => "access 2 hours", +# "/asdhas/" => "access plus 1 seconds 2 minutes", +#) diff --git a/lighttpd-mod_extforward.conf b/lighttpd-mod_extforward.conf new file mode 100644 index 0000000..5ad8a90 --- /dev/null +++ b/lighttpd-mod_extforward.conf @@ -0,0 +1,42 @@ +# mod_extforward for lighttpd +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModExtForward + +server.modules += ( + "mod_extforward" +) + +# Trust proxy 10.0.0.232 and 10.0.0.232 +#extforward.forwarder = ( +# "10.0.0.232" => "trust", +# "10.0.0.233" => "trust", +#) + +# Trust all proxies (NOT RECOMMENDED!) +#extforward.forwarder = ( "all" => "trust") + +# Note that "all" has precedence over specific entries, +# so "all except" setups will not work. + +# Note: The effect of this module is variable on $HTTP["remotip"] directives and +# other module's remote ip dependent actions. +# Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP. +# Things done in between these two moments will match on the real client's IP. +# The moment things are done by a module depends on in which hook it does things and within the same hook +# on whether they are before/after us in the module loading order +# (order in the server.modules directive in the config file). +# +# Tested behaviours: +# +# mod_access: Will match on the real client. +# +# mod_accesslog: +# In order to see the "real" ip address in access log , +# you'll have to load mod_extforward after mod_accesslog. +# like this: +# +# server.modules = ( +# ..... +# mod_accesslog, +# mod_extforward +# ) diff --git a/lighttpd-mod_fastcgi.conf b/lighttpd-mod_fastcgi.conf new file mode 100644 index 0000000..fabe29a --- /dev/null +++ b/lighttpd-mod_fastcgi.conf @@ -0,0 +1,17 @@ +# FastCGI programs have the same functionality as CGI programs, +# but are considerably faster through lower interpreter startup +# time and socketed communication +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFastCGI + +server.modules += ( + "mod_fastcgi" +) + +#### fastcgi module +## read fastcgi.txt for more info +#fastcgi.debug = 1 + +#static-file.exclude-extensions = ( +# ".fcgi", +#) diff --git a/lighttpd-mod_flv_streaming.conf b/lighttpd-mod_flv_streaming.conf new file mode 100644 index 0000000..898654c --- /dev/null +++ b/lighttpd-mod_flv_streaming.conf @@ -0,0 +1,7 @@ +# FLV streaming module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFLVStreaming + +server.modules += ( + "mod_flv_streaming" +) diff --git a/lighttpd-mod_h264_streaming.conf b/lighttpd-mod_h264_streaming.conf new file mode 100644 index 0000000..1e137ca --- /dev/null +++ b/lighttpd-mod_h264_streaming.conf @@ -0,0 +1,11 @@ +# h264 streaming module. +# +# Documentation: http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-Lighttpd-Version2 + +server.modules += ( + "mod_h264_streaming" +) + +h264-streaming.extensions = ( + ".mp4", +) diff --git a/lighttpd-mod_h264_streaming.patch b/lighttpd-mod_h264_streaming.patch new file mode 100644 index 0000000..e9430b6 --- /dev/null +++ b/lighttpd-mod_h264_streaming.patch @@ -0,0 +1,3440 @@ +--- lighttpd-1.4.18/src/Makefile.am 2007-09-03 01:23:53.000000000 +0300 ++++ lighttpd-mod_h264_streaming-1.4.18/src/Makefile.am 2007-10-23 23:42:37.736979478 +0300 +@@ -77,6 +77,11 @@ + mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined + mod_flv_streaming_la_LIBADD = $(common_libadd) + ++lib_LTLIBRARIES += mod_h264_streaming.la ++mod_h264_streaming_la_SOURCES = mod_h264_streaming.c moov.c ++mod_h264_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined ++mod_h264_streaming_la_LIBADD = $(common_libadd) ++ + lib_LTLIBRARIES += mod_evasive.la + mod_evasive_la_SOURCES = mod_evasive.c + mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined +--- /dev/null 2008-11-04 20:33:38.146691408 +0200 ++++ lighttpd-1.4.18/src/mod_h264_streaming.c 2009-01-26 20:59:51.385271731 +0200 +@@ -0,0 +1,337 @@ ++/******************************************************************************* ++ mod_h264_streaming.c ++ ++ mod_h264_streaming - A lighttpd plugin for pseudo-streaming Quicktime/MPEG4 files. ++ http://h264.code-shop.com ++ ++ Copyright (C) 2007-2009 CodeShop B.V. ++******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++#include "base.h" ++#include "log.h" ++#include "buffer.h" ++#include "response.h" ++#include "http_chunk.h" ++#include "stat_cache.h" ++ ++#include "plugin.h" ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "moov.h" ++ ++/* plugin config for all request/connections */ ++ ++typedef struct { ++ array *extensions; ++} plugin_config; ++ ++typedef struct { ++ PLUGIN_DATA; ++ ++ buffer *query_str; ++ array *get_params; ++ ++ plugin_config **config_storage; ++ ++ plugin_config conf; ++} plugin_data; ++ ++/* init the plugin data */ ++INIT_FUNC(mod_h264_streaming_init) { ++ plugin_data *p; ++ ++ p = calloc(1, sizeof(*p)); ++ ++ p->query_str = buffer_init(); ++ p->get_params = array_init(); ++ ++ return p; ++} ++ ++/* detroy the plugin data */ ++FREE_FUNC(mod_h264_streaming_free) { ++ plugin_data *p = p_d; ++ ++ UNUSED(srv); ++ ++ if (!p) return HANDLER_GO_ON; ++ ++ if (p->config_storage) { ++ size_t i; ++ ++ for (i = 0; i < srv->config_context->used; i++) { ++ plugin_config *s = p->config_storage[i]; ++ ++ if (!s) continue; ++ ++ array_free(s->extensions); ++ ++ free(s); ++ } ++ free(p->config_storage); ++ } ++ ++ buffer_free(p->query_str); ++ array_free(p->get_params); ++ ++ free(p); ++ ++ return HANDLER_GO_ON; ++} ++ ++/* handle plugin config and check values */ ++ ++SETDEFAULTS_FUNC(mod_h264_streaming_set_defaults) { ++ plugin_data *p = p_d; ++ size_t i = 0; ++ ++ config_values_t cv[] = { ++ { "h264-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ ++ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } ++ }; ++ ++ if (!p) return HANDLER_ERROR; ++ ++ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); ++ ++ for (i = 0; i < srv->config_context->used; i++) { ++ plugin_config *s; ++ ++ s = calloc(1, sizeof(plugin_config)); ++ s->extensions = array_init(); ++ ++ cv[0].destination = s->extensions; ++ ++ p->config_storage[i] = s; ++ ++ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { ++ return HANDLER_ERROR; ++ } ++ } ++ ++ return HANDLER_GO_ON; ++} ++ ++#define PATCH(x) \ ++ p->conf.x = s->x; ++static int mod_h264_streaming_patch_connection(server *srv, connection *con, plugin_data *p) { ++ size_t i, j; ++ plugin_config *s = p->config_storage[0]; ++ ++ PATCH(extensions); ++ ++ /* skip the first, the global context */ ++ for (i = 1; i < srv->config_context->used; i++) { ++ data_config *dc = (data_config *)srv->config_context->data[i]; ++ s = p->config_storage[i]; ++ ++ /* condition didn't match */ ++ if (!config_check_cond(srv, con, dc)) continue; ++ ++ /* merge config */ ++ for (j = 0; j < dc->value->used; j++) { ++ data_unset *du = dc->value->data[j]; ++ ++ if (buffer_is_equal_string(du->key, CONST_STR_LEN("h264-streaming.extensions"))) { ++ PATCH(extensions); ++ } ++ } ++ } ++ ++ return 0; ++} ++#undef PATCH ++ ++static int split_get_params(array *get_params, buffer *qrystr) { ++ size_t is_key = 1; ++ size_t i; ++ char *key = NULL, *val = NULL; ++ ++ key = qrystr->ptr; ++ ++ /* we need the \0 */ ++ for (i = 0; i < qrystr->used; i++) { ++ switch(qrystr->ptr[i]) { ++ case '=': ++ if (is_key) { ++ val = qrystr->ptr + i + 1; ++ ++ qrystr->ptr[i] = '\0'; ++ ++ is_key = 0; ++ } ++ ++ break; ++ case '&': ++ case '\0': /* fin symbol */ ++ if (!is_key) { ++ data_string *ds; ++ /* we need at least a = since the last & */ ++ ++ /* terminate the value */ ++ qrystr->ptr[i] = '\0'; ++ ++ if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) { ++ ds = data_string_init(); ++ } ++ buffer_copy_string_len(ds->key, key, strlen(key)); ++ buffer_copy_string_len(ds->value, val, strlen(val)); ++ ++ array_insert_unique(get_params, (data_unset *)ds); ++ } ++ ++ key = qrystr->ptr + i + 1; ++ val = NULL; ++ is_key = 1; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++URIHANDLER_FUNC(mod_h264_streaming_path_handler) { ++ plugin_data *p = p_d; ++ int s_len; ++ size_t k; ++ ++ UNUSED(srv); ++ ++ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON; ++ ++ mod_h264_streaming_patch_connection(srv, con, p); ++ ++ s_len = con->physical.path->used - 1; ++ ++ for (k = 0; k < p->conf.extensions->used; k++) { ++ data_string *ds = (data_string *)p->conf.extensions->data[k]; ++ int ct_len = ds->value->used - 1; ++ ++ if (ct_len > s_len) continue; ++ if (ds->value->used == 0) continue; ++ ++ if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { ++ data_string *get_param; ++ stat_cache_entry *sce = NULL; ++ double start = 0.0; ++ double end = 0.0; ++ char *err = NULL; ++ int client_is_flash = 0; ++ ++ array_reset(p->get_params); ++ buffer_copy_string_buffer(p->query_str, con->uri.query); ++ split_get_params(p->get_params, p->query_str); ++ ++ /* if there is a start=[0-9]+ in the header use it as start, ++ * otherwise send the full file */ ++ if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "start"))) ++ { ++ /* check if it is a number */ ++ start = strtod(get_param->value->ptr, &err); ++ if (*err != '\0') { ++ return HANDLER_GO_ON; ++ } ++ if (start < 0) return HANDLER_GO_ON; ++ } ++ ++ /* if there is an end=[0-9]+ in the header use it as end */ ++ if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "end"))) ++ { ++ /* check if it is a number */ ++ end = strtod(get_param->value->ptr, &err); ++ if (*err != '\0') { ++ return HANDLER_GO_ON; ++ } ++ if (end < 0 || start >= end) return HANDLER_GO_ON; ++ } ++ ++ if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "client"))) ++ { ++ client_is_flash = starts_with(get_param->value->ptr, "FLASH"); ++ } ++ ++ /* get file info */ ++ if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { ++ return HANDLER_GO_ON; ++ } ++ ++ /* we are safe now, let's build a h264 header */ ++ { ++ { ++ unsigned int filesize = sce->st.st_size; ++ ++ void* mp4_header; ++ uint32_t mp4_header_size; ++ uint64_t mdat_offset; ++ uint64_t mdat_size; ++ ++ int result = mp4_split(con->physical.path->ptr, filesize, start, end, ++ &mp4_header, &mp4_header_size, ++ &mdat_offset, &mdat_size, client_is_flash); ++ ++ if(result) ++ { ++ buffer* b = chunkqueue_get_append_buffer(con->write_queue); ++ buffer_append_memory(b, mp4_header, mp4_header_size); ++ b->used++; /* add virtual \0 */ ++ ++ http_chunk_append_file(srv, con, con->physical.path, ++ mdat_offset, mdat_size); ++ } ++ ++ if(mp4_header) ++ { ++ free(mp4_header); ++ } ++ ++ if(!result) ++ { ++ return HANDLER_GO_ON; ++ } ++ } ++ } ++ ++ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/mp4")); ++ if(!client_is_flash) ++ { ++ response_header_overwrite(srv, con, CONST_STR_LEN("X-Mod-H264-Streaming"), CONST_STR_LEN("version=2.0")); ++ } ++ else ++ { ++ response_header_overwrite(srv, con, CONST_STR_LEN("X-Mod-H264-Streaming"), CONST_STR_LEN("version=2.0,client=flash")); ++ } ++ ++ con->file_finished = 1; ++ ++ return HANDLER_FINISHED; ++ } ++ } ++ ++ /* not found */ ++ return HANDLER_GO_ON; ++} ++ ++/* this function is called at dlopen() time and inits the callbacks */ ++ ++int mod_h264_streaming_plugin_init(plugin *p) { ++ p->version = LIGHTTPD_VERSION_ID; ++ p->name = buffer_init_string("h264_streaming"); ++ ++ p->init = mod_h264_streaming_init; ++ p->handle_physical = mod_h264_streaming_path_handler; ++ p->set_defaults = mod_h264_streaming_set_defaults; ++ p->cleanup = mod_h264_streaming_free; ++ ++ p->data = NULL; ++ ++ return 0; ++} ++ +--- /dev/null 2008-11-04 20:33:38.146691408 +0200 ++++ lighttpd-1.4.18/src/moov.c 2009-01-26 21:00:05.071936866 +0200 +@@ -0,0 +1,3031 @@ ++/******************************************************************************* ++ moov.c (version 2) ++ ++ moov - A library for splitting Quicktime/MPEG4 files. ++ http://h264.code-shop.com ++ ++ Copyright (C) 2007-2009 CodeShop B.V. ++ ++ Licensing ++ The H264 Streaming Module is licened under a Creative Common License. It allows ++ you to use, modify and redistribute the module, but only for *noncommercial* ++ purposes. For corporate use, please apply for a commercial license. ++ ++ Creative Commons License: ++ http://creativecommons.org/licenses/by-nc-sa/3.0/ ++ ++ Commercial License: ++ http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-License-Version2 ++******************************************************************************/ ++ ++#include "moov.h" ++ ++#ifdef _MSVC_VER ++#define _CRTDBG_MAP_ALLOC ++#include ++#include ++#endif ++ ++#ifdef UNUSED ++#elif defined(__GNUC__) ++# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) ++#elif defined(__LCLINT__) ++# define UNUSED(x) /*@unused@*/ x ++#else ++# define UNUSED(x) x ++#endif ++ ++/* ++ The QuickTime File Format PDF from Apple: ++ http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#ifdef HAVE_STDINT_H ++# include ++#endif ++#ifdef HAVE_INTTYPES_H ++# include ++#endif ++#if defined HAVE_ZLIB_H && defined HAVE_LIBZ ++// Compress the MOOV atom. Turn this off for Flash as it doesn't support it. ++// # define COMPRESS_MOOV_ATOM ++# include ++#endif ++ ++#ifdef WIN32 ++#define ftello _ftelli64 ++#define fseeko _fseeki64 ++#endif ++ ++#define MAX_TRACKS 8 ++ ++#define FOURCC(a, b, c, d) ((uint32_t)(a) << 24) + \ ++ ((uint32_t)(b) << 16) + \ ++ ((uint32_t)(c) << 8) + \ ++ ((uint32_t)(d)) ++ ++/* Returns true when the test string is a prefix of the input */ ++int starts_with(const char* input, const char* test) ++{ ++ while(*input && *test) ++ { ++ if(*input != *test) ++ return 0; ++ ++input; ++ ++test; ++ } ++ ++ return *test == '\0'; ++} ++ ++static unsigned int read_8(unsigned char const* buffer) ++{ ++ return buffer[0]; ++} ++ ++static unsigned char* write_8(unsigned char* buffer, unsigned char v) ++{ ++ buffer[0] = v; ++ ++ return buffer + 1; ++} ++ ++static uint16_t read_16(unsigned char const* buffer) ++{ ++ return (buffer[0] << 8) | ++ (buffer[1] << 0); ++} ++ ++static unsigned char* write_16(unsigned char* buffer, unsigned int v) ++{ ++ buffer[0] = (unsigned char)(v >> 8); ++ buffer[1] = (unsigned char)(v >> 0); ++ ++ return buffer + 2; ++} ++ ++static unsigned int read_24(unsigned char const* buffer) ++{ ++ return (buffer[0] << 16) | ++ (buffer[1] << 8) | ++ (buffer[2] << 0); ++} ++ ++static unsigned char* write_24(unsigned char* buffer, unsigned int v) ++{ ++ buffer[0] = (unsigned char)(v >> 16); ++ buffer[1] = (unsigned char)(v >> 8); ++ buffer[2] = (unsigned char)(v >> 0); ++ ++ return buffer + 3; ++} ++ ++static uint32_t read_32(unsigned char const* buffer) ++{ ++ return (buffer[0] << 24) | ++ (buffer[1] << 16) | ++ (buffer[2] << 8) | ++ (buffer[3] << 0); ++} ++ ++static unsigned char* write_32(unsigned char* buffer, uint32_t v) ++{ ++ buffer[0] = (unsigned char)(v >> 24); ++ buffer[1] = (unsigned char)(v >> 16); ++ buffer[2] = (unsigned char)(v >> 8); ++ buffer[3] = (unsigned char)(v >> 0); ++ ++ return buffer + 4; ++} ++ ++static uint64_t read_64(unsigned char const* buffer) ++{ ++ return ((uint64_t)(read_32(buffer)) << 32) + read_32(buffer + 4); ++} ++ ++static unsigned char* write_64(unsigned char* buffer, uint64_t v) ++{ ++ write_32(buffer + 0, (uint32_t)(v >> 32)); ++ write_32(buffer + 4, (uint32_t)(v >> 0)); ++ ++ return buffer + 8; ++} ++ ++#define ATOM_PREAMBLE_SIZE 8 ++ ++struct atom_t ++{ ++ uint32_t type_; ++ uint32_t short_size_; ++ uint64_t size_; ++ unsigned char* start_; ++ unsigned char* end_; ++}; ++ ++static unsigned char* atom_read_header(unsigned char* buffer, struct atom_t* atom) ++{ ++ atom->start_ = buffer; ++ atom->short_size_ = read_32(buffer); ++ atom->type_ = read_32(buffer + 4); ++ ++ if(atom->short_size_ == 1) ++ atom->size_ = read_64(buffer + 8); ++ else ++ atom->size_ = atom->short_size_; ++ ++ atom->end_ = atom->start_ + atom->size_; ++ ++ return buffer + ATOM_PREAMBLE_SIZE + (atom->short_size_ == 1 ? 8 : 0); ++} ++ ++static void atom_print(struct atom_t const* atom) ++{ ++ printf("Atom(%c%c%c%c,%lld)\n", ++ atom->type_ >> 24, ++ atom->type_ >> 16, ++ atom->type_ >> 8, ++ atom->type_, ++ atom->size_); ++} ++ ++struct unknown_atom_t ++{ ++ void* atom_; ++ struct unknown_atom_t* next_; ++}; ++ ++static struct unknown_atom_t* unknown_atom_init() ++{ ++ struct unknown_atom_t* atom = (struct unknown_atom_t*)malloc(sizeof(struct unknown_atom_t)); ++ atom->atom_ = 0; ++ atom->next_ = 0; ++ ++ return atom; ++} ++ ++static void unknown_atom_exit(struct unknown_atom_t* atom) ++{ ++ while(atom) ++ { ++ struct unknown_atom_t* next = atom->next_; ++ free(atom->atom_); ++ free(atom); ++ atom = next; ++ } ++} ++ ++static struct unknown_atom_t* unknown_atom_add_atom(struct unknown_atom_t* parent, void* atom) ++{ ++ size_t size = read_32(atom); ++ struct unknown_atom_t* unknown = unknown_atom_init(); ++ unknown->atom_ = malloc(size); ++ memcpy(unknown->atom_, atom, size); ++ unknown->next_ = parent; ++ return unknown; ++} ++ ++struct atom_read_list_t ++{ ++ uint32_t type_; ++ void* parent_; ++ int (*destination_)(void* parent, void* child); ++ void* (*reader_)(void* parent, unsigned char* buffer, uint64_t size); ++}; ++ ++static int atom_reader(struct atom_read_list_t* atom_read_list, ++ unsigned int atom_read_list_size, ++ void* parent, ++ unsigned char* buffer, uint64_t size) ++{ ++ struct atom_t leaf_atom; ++ unsigned char* buffer_start = buffer; ++ ++ while(buffer < buffer_start + size) ++ { ++ unsigned int i; ++ buffer = atom_read_header(buffer, &leaf_atom); ++ ++ atom_print(&leaf_atom); ++ ++ for(i = 0; i != atom_read_list_size; ++i) ++ { ++ if(leaf_atom.type_ == atom_read_list[i].type_) ++ { ++ break; ++ } ++ } ++ ++ if(i == atom_read_list_size) ++ { ++ // add to unkown chunks ++ (*(struct unknown_atom_t**)parent) = ++ unknown_atom_add_atom(*(struct unknown_atom_t**)(parent), buffer - ATOM_PREAMBLE_SIZE); ++ } ++ else ++ { ++ void* child = ++ atom_read_list[i].reader_(parent, buffer, ++ leaf_atom.size_ - ATOM_PREAMBLE_SIZE); ++ if(!child) ++ break; ++ if(!atom_read_list[i].destination_(parent, child)) ++ break; ++ } ++ buffer = leaf_atom.end_; ++ } ++ ++ if(buffer < buffer_start + size) ++ { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++struct atom_write_list_t ++{ ++ uint32_t type_; ++ void* parent_; ++ void* source_; ++ unsigned char* (*writer_)(void* parent, void* atom, unsigned char* buffer); ++}; ++ ++static unsigned char* atom_writer_unknown(struct unknown_atom_t* atoms, ++ unsigned char* buffer) ++{ ++ while(atoms) ++ { ++ size_t size = read_32(atoms->atom_); ++ memcpy(buffer, atoms->atom_, size); ++ buffer += size; ++ atoms = atoms->next_; ++ } ++ ++ return buffer; ++} ++ ++static unsigned char* atom_writer(struct unknown_atom_t* unknown_atoms, ++ struct atom_write_list_t* atom_write_list, ++ unsigned int atom_write_list_size, ++ unsigned char* buffer) ++{ ++ unsigned i; ++ const int write_box64 = 0; ++ ++ if(unknown_atoms) ++ { ++ buffer = atom_writer_unknown(unknown_atoms, buffer); ++ } ++ ++ for(i = 0; i != atom_write_list_size; ++i) ++ { ++ if(atom_write_list[i].source_ != 0) ++ { ++ unsigned char* atom_start = buffer; ++ // atom size ++ if(write_box64) ++ { ++ write_32(buffer, 1); // box64 ++ } ++ buffer += 4; ++ ++ // atom type ++ buffer = write_32(buffer, atom_write_list[i].type_); ++ if(write_box64) ++ { ++ buffer += 8; // box64 ++ } ++ ++ // atom payload ++ buffer = atom_write_list[i].writer_(atom_write_list[i].parent_, ++ atom_write_list[i].source_, buffer); ++ ++ if(write_box64) ++ write_64(atom_start + 8, buffer - atom_start); ++ else ++ write_32(atom_start, buffer - atom_start); ++ } ++ } ++ ++ return buffer; ++} ++ ++struct tkhd_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint64_t creation_time_; ++ uint64_t modification_time_; ++ uint32_t track_id_; ++ uint32_t reserved_; ++ uint64_t duration_; ++ uint32_t reserved2_[2]; ++ uint16_t layer_; ++ uint16_t predefined_; ++ uint16_t volume_; ++ uint16_t reserved3_; ++ uint32_t matrix_[9]; ++ uint32_t width_; ++ uint32_t height_; ++}; ++ ++struct mdhd_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint64_t creation_time_; ++ uint64_t modification_time_; ++ uint32_t timescale_; ++ uint64_t duration_; ++ unsigned int language_[3]; ++ uint16_t predefined_; ++}; ++ ++struct vmhd_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint16_t graphics_mode_; ++ uint16_t opcolor_[3]; ++}; ++ ++struct hdlr_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t predefined_; ++ uint32_t handler_type_; ++ uint32_t reserved1_; ++ uint32_t reserved2_; ++ uint32_t reserved3_; ++ char* name_; ++}; ++ ++struct stbl_t ++{ ++ struct unknown_atom_t* unknown_atoms_; ++//struct stsd_t* stsd_; // sample description ++ struct stts_t* stts_; // decoding time-to-sample ++ struct stss_t* stss_; // sync sample ++ struct stsc_t* stsc_; // sample-to-chunk ++ struct stsz_t* stsz_; // sample size ++ struct stco_t* stco_; // chunk offset ++ struct ctts_t* ctts_; // composition time-to-sample ++ ++ void* stco_inplace_; // newly generated stco (patched inplace) ++}; ++ ++struct stts_table_t ++{ ++ uint32_t sample_count_; ++ uint32_t sample_duration_; ++}; ++ ++struct stts_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t entries_; ++ struct stts_table_t* table_; ++}; ++ ++struct stss_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t entries_; ++ uint32_t* sample_numbers_; ++}; ++ ++struct stsc_table_t ++{ ++ uint32_t chunk_; ++ uint32_t samples_; ++ uint32_t id_; ++}; ++ ++struct stsc_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t entries_; ++ struct stsc_table_t* table_; ++}; ++ ++struct stsz_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t sample_size_; ++ uint32_t entries_; ++ uint32_t* sample_sizes_; ++}; ++ ++struct stco_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t entries_; ++ uint64_t* chunk_offsets_; ++}; ++ ++struct ctts_table_t ++{ ++ uint32_t sample_count_; ++ uint32_t sample_offset_; ++}; ++ ++struct ctts_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint32_t entries_; ++ struct ctts_table_t* table_; ++}; ++ ++struct minf_t ++{ ++ struct unknown_atom_t* unknown_atoms_; ++ struct vmhd_t* vmhd_; ++// struct dinf_t* dinf_; ++ struct stbl_t* stbl_; ++}; ++ ++struct mdia_t ++{ ++ struct unknown_atom_t* unknown_atoms_; ++ struct mdhd_t* mdhd_; ++ struct hdlr_t* hdlr_; ++ struct minf_t* minf_; ++}; ++ ++struct chunks_t ++{ ++ unsigned int sample_; // number of the first sample in the chunk ++ unsigned int size_; // number of samples in the chunk ++ int id_; // for multiple codecs mode - not used ++ uint64_t pos_; // start byte position of chunk ++}; ++ ++struct samples_t ++{ ++ unsigned int pts_; // decoding/presentation time ++ unsigned int size_; // size in bytes ++ uint64_t pos_; // byte offset ++ unsigned int cto_; // composition time offset ++}; ++ ++struct trak_t ++{ ++ struct unknown_atom_t* unknown_atoms_; ++ struct tkhd_t* tkhd_; ++ struct mdia_t* mdia_; ++ ++ /* temporary indices */ ++ unsigned int chunks_size_; ++ struct chunks_t* chunks_; ++ ++ unsigned int samples_size_; ++ struct samples_t* samples_; ++}; ++ ++struct mvhd_t ++{ ++ unsigned int version_; ++ unsigned int flags_; ++ uint64_t creation_time_; ++ uint64_t modification_time_; ++ uint32_t timescale_; ++ uint64_t duration_; ++ uint32_t rate_; ++ uint16_t volume_; ++ uint16_t reserved1_; ++ uint32_t reserved2_[2]; ++ uint32_t matrix_[9]; ++ uint32_t predefined_[6]; ++ uint32_t next_track_id_; ++}; ++ ++struct moov_t ++{ ++ struct unknown_atom_t* unknown_atoms_; ++ struct mvhd_t* mvhd_; ++ unsigned int tracks_; ++ struct trak_t* traks_[MAX_TRACKS]; ++}; ++ ++ ++static struct tkhd_t* tkhd_init() ++{ ++ struct tkhd_t* tkhd = (struct tkhd_t*)malloc(sizeof(struct tkhd_t)); ++ ++ return tkhd; ++} ++ ++static void tkhd_exit(struct tkhd_t* tkhd) ++{ ++ free(tkhd); ++} ++ ++static void* tkhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct tkhd_t* tkhd = tkhd_init(); ++ ++ tkhd->version_ = read_8(buffer + 0); ++ tkhd->flags_ = read_24(buffer + 1); ++ if(tkhd->version_ == 0) ++ { ++ if(size < 92-8) ++ return 0; ++ ++ tkhd->creation_time_ = read_32(buffer + 4); ++ tkhd->modification_time_ = read_32(buffer + 8); ++ tkhd->track_id_ = read_32(buffer + 12); ++ tkhd->reserved_ = read_32(buffer + 16); ++ tkhd->duration_ = read_32(buffer + 20); ++ buffer += 24; ++ } ++ else ++ { ++ if(size < 104-8) ++ return 0; ++ ++ tkhd->creation_time_ = read_64(buffer + 4); ++ tkhd->modification_time_ = read_64(buffer + 12); ++ tkhd->track_id_ = read_32(buffer + 20); ++ tkhd->reserved_ = read_32(buffer + 24); ++ tkhd->duration_ = read_64(buffer + 28); ++ buffer += 36; ++ } ++ ++ tkhd->reserved2_[0] = read_32(buffer + 0); ++ tkhd->reserved2_[1] = read_32(buffer + 4); ++ tkhd->layer_ = read_16(buffer + 8); ++ tkhd->predefined_ = read_16(buffer + 10); ++ tkhd->volume_ = read_16(buffer + 12); ++ tkhd->reserved3_ = read_16(buffer + 14); ++ buffer += 16; ++ ++ for(i = 0; i != 9; ++i) ++ { ++ tkhd->matrix_[i] = read_32(buffer); ++ buffer += 4; ++ } ++ ++ tkhd->width_ = read_32(buffer + 0); ++ tkhd->height_ = read_32(buffer + 4); ++ ++ return tkhd; ++} ++ ++static unsigned char* tkhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct tkhd_t const* tkhd = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, tkhd->version_); ++ buffer = write_24(buffer, tkhd->flags_); ++ ++ if(tkhd->version_ == 0) ++ { ++ buffer = write_32(buffer, (uint32_t)tkhd->creation_time_); ++ buffer = write_32(buffer, (uint32_t)tkhd->modification_time_); ++ buffer = write_32(buffer, tkhd->track_id_); ++ buffer = write_32(buffer, tkhd->reserved_); ++ buffer = write_32(buffer, (uint32_t)tkhd->duration_); ++ } ++ else ++ { ++ buffer = write_64(buffer, tkhd->creation_time_); ++ buffer = write_64(buffer, tkhd->modification_time_); ++ buffer = write_32(buffer, tkhd->track_id_); ++ buffer = write_32(buffer, tkhd->reserved_); ++ buffer = write_64(buffer, tkhd->duration_); ++ } ++ ++ buffer = write_32(buffer, tkhd->reserved2_[0]); ++ buffer = write_32(buffer, tkhd->reserved2_[1]); ++ buffer = write_16(buffer, tkhd->layer_); ++ buffer = write_16(buffer, tkhd->predefined_); ++ buffer = write_16(buffer, tkhd->volume_); ++ buffer = write_16(buffer, tkhd->reserved3_); ++ ++ for(i = 0; i != 9; ++i) ++ { ++ buffer = write_32(buffer, tkhd->matrix_[i]); ++ } ++ ++ buffer = write_32(buffer, tkhd->width_); ++ buffer = write_32(buffer, tkhd->height_); ++ ++ return buffer; ++} ++ ++static struct mdhd_t* mdhd_init() ++{ ++ struct mdhd_t* mdhd = (struct mdhd_t*)malloc(sizeof(struct mdhd_t)); ++ ++ return mdhd; ++} ++ ++static void mdhd_exit(struct mdhd_t* mdhd) ++{ ++ free(mdhd); ++} ++ ++static void* mdhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t UNUSED(size)) ++{ ++ uint16_t language; ++ unsigned int i; ++ ++ struct mdhd_t* mdhd = mdhd_init(); ++ mdhd->version_ = read_8(buffer + 0); ++ mdhd->flags_ = read_24(buffer + 1); ++ if(mdhd->version_ == 0) ++ { ++ mdhd->creation_time_ = read_32(buffer + 4); ++ mdhd->modification_time_ = read_32(buffer + 8); ++ mdhd->timescale_ = read_32(buffer + 12); ++ mdhd->duration_ = read_32(buffer + 16); ++ buffer += 20; ++ } ++ else ++ { ++ mdhd->creation_time_ = read_64(buffer + 4); ++ mdhd->modification_time_ = read_64(buffer + 12); ++ mdhd->timescale_ = read_32(buffer + 20); ++ mdhd->duration_ = read_64(buffer + 24); ++ buffer += 32; ++ } ++ ++ language = read_16(buffer + 0); ++ for(i = 0; i != 3; ++i) ++ { ++ mdhd->language_[i] = ((language >> ((2 - i) * 5)) & 0x1f) + 0x60; ++ } ++ ++ mdhd->predefined_ = read_16(buffer + 2); ++ ++ return mdhd; ++} ++ ++static unsigned char* mdhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct mdhd_t const* mdhd = atom; ++ ++ buffer = write_8(buffer, mdhd->version_); ++ buffer = write_24(buffer, mdhd->flags_); ++ ++ if(mdhd->version_ == 0) ++ { ++ buffer = write_32(buffer, (uint32_t)mdhd->creation_time_); ++ buffer = write_32(buffer, (uint32_t)mdhd->modification_time_); ++ buffer = write_32(buffer, mdhd->timescale_); ++ buffer = write_32(buffer, (uint32_t)mdhd->duration_); ++ } ++ else ++ { ++ buffer = write_64(buffer, mdhd->creation_time_); ++ buffer = write_64(buffer, mdhd->modification_time_); ++ buffer = write_32(buffer, mdhd->timescale_); ++ buffer = write_64(buffer, mdhd->duration_); ++ } ++ ++ buffer = write_16(buffer, ++ ((mdhd->language_[0] - 0x60) << 10) + ++ ((mdhd->language_[1] - 0x60) << 5) + ++ ((mdhd->language_[2] - 0x60) << 0)); ++ ++ buffer = write_16(buffer, mdhd->predefined_); ++ ++ return buffer; ++} ++ ++static struct vmhd_t* vmhd_init() ++{ ++ struct vmhd_t* atom = (struct vmhd_t*)malloc(sizeof(struct vmhd_t)); ++ ++ return atom; ++} ++ ++void vmhd_exit(struct vmhd_t* atom) ++{ ++ free(atom); ++} ++ ++static void* vmhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct vmhd_t* atom; ++ ++ if(size < 20-8) ++ return 0; ++ ++ atom = vmhd_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ ++ atom->graphics_mode_ = read_16(buffer + 4); ++ buffer += 6; ++ for(i = 0; i != 3; ++i) ++ { ++ atom->opcolor_[i] = read_16(buffer); ++ buffer += 2; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* vmhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct vmhd_t const* vmhd = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, vmhd->version_); ++ buffer = write_24(buffer, vmhd->flags_); ++ buffer = write_16(buffer, vmhd->graphics_mode_); ++ for(i = 0; i != 3; ++i) ++ { ++ buffer = write_16(buffer, vmhd->opcolor_[i]); ++ } ++ ++ return buffer; ++} ++ ++static struct hdlr_t* hdlr_init() ++{ ++ struct hdlr_t* atom = (struct hdlr_t*)malloc(sizeof(struct hdlr_t)); ++ atom->name_ = 0; ++ ++ return atom; ++} ++ ++static void hdlr_exit(struct hdlr_t* atom) ++{ ++ if(atom->name_) ++ { ++ free(atom->name_); ++ } ++ free(atom); ++} ++ ++static void* hdlr_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ struct hdlr_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = hdlr_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->predefined_ = read_32(buffer + 4); ++ atom->handler_type_ = read_32(buffer + 8); ++ atom->reserved1_ = read_32(buffer + 12); ++ atom->reserved2_ = read_32(buffer + 16); ++ atom->reserved3_ = read_32(buffer + 20); ++ buffer += 24; ++ size -= 24; ++ if(size > 0) ++ { ++ size_t length = (size_t)size; ++ atom->name_ = malloc(length + 1); ++ if(atom->predefined_ == FOURCC('m', 'h', 'l', 'r')) ++ { ++ length = read_8(buffer); ++ buffer += 1; ++ if(size < length) ++ length = (size_t)size; ++ } ++ memcpy(atom->name_, buffer, length); ++ atom->name_[length] = '\0'; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* hdlr_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct hdlr_t* hdlr = atom; ++ buffer = write_8(buffer, hdlr->version_); ++ buffer = write_24(buffer, hdlr->flags_); ++ ++ buffer = write_32(buffer, hdlr->predefined_); ++ buffer = write_32(buffer, hdlr->handler_type_); ++ buffer = write_32(buffer, hdlr->reserved1_); ++ buffer = write_32(buffer, hdlr->reserved2_); ++ buffer = write_32(buffer, hdlr->reserved3_); ++ if(hdlr->name_) ++ { ++ char const* p; ++ if(hdlr->predefined_ == FOURCC('m', 'h', 'l', 'r')) ++ { ++ buffer = write_8(buffer, strlen(hdlr->name_)); ++ } ++ ++ for(p = hdlr->name_; *p; ++p) ++ buffer = write_8(buffer, *p); ++ } ++ ++ return buffer; ++} ++ ++static struct stts_t* stts_init() ++{ ++ struct stts_t* atom = (struct stts_t*)malloc(sizeof(struct stts_t)); ++ atom->table_ = 0; ++ ++ return atom; ++} ++ ++void stts_exit(struct stts_t* atom) ++{ ++ if(atom->table_) ++ { ++ free(atom->table_); ++ } ++ free(atom); ++} ++ ++static void* stts_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct stts_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = stts_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->entries_ = read_32(buffer + 4); ++ ++ if(size < 8 + atom->entries_ * sizeof(struct stts_table_t)) ++ return 0; ++ ++ buffer += 8; ++ ++ atom->table_ = (struct stts_table_t*)(malloc(atom->entries_ * sizeof(struct stts_table_t))); ++ ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->table_[i].sample_count_ = read_32(buffer + 0); ++ atom->table_[i].sample_duration_ = read_32(buffer + 4); ++ buffer += 8; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* stts_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct stts_t* stts = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, stts->version_); ++ buffer = write_24(buffer, stts->flags_); ++ buffer = write_32(buffer, stts->entries_); ++ for(i = 0; i != stts->entries_; ++i) ++ { ++ buffer = write_32(buffer, stts->table_[i].sample_count_); ++ buffer = write_32(buffer, stts->table_[i].sample_duration_); ++ } ++ ++ return buffer; ++} ++ ++static unsigned int stts_get_sample(struct stts_t const* stts, uint64_t time) ++{ ++ unsigned int stts_index = 0; ++ unsigned int stts_count; ++ ++ unsigned int ret = 0; ++ uint64_t time_count = 0; ++ ++ for(; stts_index != stts->entries_; ++stts_index) ++ { ++ unsigned int sample_count = stts->table_[stts_index].sample_count_; ++ unsigned int sample_duration = stts->table_[stts_index].sample_duration_; ++ if(time_count + (uint64_t)sample_duration * (uint64_t)sample_count >= time) ++ { ++ stts_count = (unsigned int)((time - time_count) / sample_duration); ++ time_count += (uint64_t)stts_count * (uint64_t)sample_duration; ++ ret += stts_count; ++ break; ++ } ++ else ++ { ++ time_count += (uint64_t)sample_duration * (uint64_t)sample_count; ++ ret += sample_count; ++ } ++ } ++ return ret; ++} ++ ++static uint64_t stts_get_time(struct stts_t const* stts, unsigned int sample) ++{ ++ uint64_t ret = 0; ++ unsigned int stts_index = 0; ++ unsigned int sample_count = 0; ++ ++ for(;;) ++ { ++ unsigned int table_sample_count = stts->table_[stts_index].sample_count_; ++ unsigned int table_sample_duration = stts->table_[stts_index].sample_duration_; ++ if(sample_count + table_sample_count > sample) ++ { ++ unsigned int stts_count = (sample - sample_count); ++ ret += (uint64_t)stts_count * (uint64_t)table_sample_duration; ++ break; ++ } ++ else ++ { ++ sample_count += table_sample_count; ++ ret += (uint64_t)table_sample_count * (uint64_t)table_sample_duration; ++ stts_index++; ++ } ++ } ++ return ret; ++} ++ ++static uint64_t stts_get_duration(struct stts_t const* stts) ++{ ++ uint64_t duration = 0; ++ unsigned int i; ++ for(i = 0; i != stts->entries_; ++i) ++ { ++ unsigned int sample_count = stts->table_[i].sample_count_; ++ unsigned int sample_duration = stts->table_[i].sample_duration_; ++ duration += (uint64_t)sample_duration * (uint64_t)sample_count; ++ } ++ ++ return duration; ++} ++ ++static unsigned int stts_get_samples(struct stts_t const* stts) ++{ ++ unsigned int samples = 0; ++ unsigned int entries = stts->entries_; ++ unsigned int i; ++ for(i = 0; i != entries; ++i) ++ { ++ unsigned int sample_count = stts->table_[i].sample_count_; ++// unsigned int sample_duration = stts->table_[i].sample_duration_; ++ samples += sample_count; ++ } ++ ++ return samples; ++} ++ ++static struct stss_t* stss_init() ++{ ++ struct stss_t* atom = (struct stss_t*)malloc(sizeof(struct stss_t)); ++ atom->sample_numbers_ = 0; ++ ++ return atom; ++} ++ ++void stss_exit(struct stss_t* atom) ++{ ++ if(atom->sample_numbers_) ++ { ++ free(atom->sample_numbers_); ++ } ++ free(atom); ++} ++ ++static void* stss_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct stss_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = stss_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->entries_ = read_32(buffer + 4); ++ ++ if(size < 8 + atom->entries_ * sizeof(uint32_t)) ++ return 0; ++ ++ buffer += 8; ++ ++ atom->sample_numbers_ = (uint32_t*)malloc(atom->entries_ * sizeof(uint32_t)); ++ ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->sample_numbers_[i] = read_32(buffer); ++ buffer += 4; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* stss_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct stss_t const* stss = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, stss->version_); ++ buffer = write_24(buffer, stss->flags_); ++ buffer = write_32(buffer, stss->entries_); ++ for(i = 0; i != stss->entries_; ++i) ++ { ++ buffer = write_32(buffer, stss->sample_numbers_[i]); ++ } ++ ++ return buffer; ++} ++ ++static unsigned int stss_get_nearest_keyframe(struct stss_t const* stss, unsigned int sample) ++{ ++ // scan the sync samples to find the key frame that precedes the sample number ++ unsigned int i; ++ unsigned int table_sample = 0; ++ for(i = 0; i != stss->entries_; ++i) ++ { ++ table_sample = stss->sample_numbers_[i]; ++ if(table_sample >= sample) ++ break; ++ } ++ if(table_sample == sample) ++ return table_sample; ++ else ++ return stss->sample_numbers_[i - 1]; ++} ++ ++static struct stsc_t* stsc_init() ++{ ++ struct stsc_t* atom = (struct stsc_t*)malloc(sizeof(struct stsc_t)); ++ atom->table_ = 0; ++ ++ return atom; ++} ++ ++static void stsc_exit(struct stsc_t* atom) ++{ ++ if(atom->table_) ++ { ++ free(atom->table_); ++ } ++ free(atom); ++} ++ ++static void* stsc_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct stsc_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = stsc_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->entries_ = read_32(buffer + 4); ++ ++ if(size < 8 + atom->entries_ * sizeof(struct stsc_table_t)) ++ return 0; ++ ++ buffer += 8; ++ ++ // reserve space for one extra entry as when splitting the video we may have to ++ // split the first entry ++ atom->table_ = (struct stsc_table_t*)(malloc((atom->entries_ + 1) * sizeof(struct stsc_table_t))); ++ ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->table_[i].chunk_ = read_32(buffer + 0) - 1; // Note: we use zero based ++ atom->table_[i].samples_ = read_32(buffer + 4); ++ atom->table_[i].id_ = read_32(buffer + 8); ++ buffer += 12; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* stsc_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct stsc_t* stsc = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, stsc->version_); ++ buffer = write_24(buffer, stsc->flags_); ++ buffer = write_32(buffer, stsc->entries_); ++ for(i = 0; i != stsc->entries_; ++i) ++ { ++ buffer = write_32(buffer, stsc->table_[i].chunk_ + 1); ++ buffer = write_32(buffer, stsc->table_[i].samples_); ++ buffer = write_32(buffer, stsc->table_[i].id_); ++ } ++ ++ return buffer; ++} ++ ++static struct stsz_t* stsz_init() ++{ ++ struct stsz_t* atom = (struct stsz_t*)malloc(sizeof(struct stsz_t)); ++ atom->sample_sizes_ = 0; ++ ++ return atom; ++} ++ ++static void stsz_exit(struct stsz_t* atom) ++{ ++ if(atom->sample_sizes_) ++ { ++ free(atom->sample_sizes_); ++ } ++ free(atom); ++} ++ ++static void* stsz_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct stsz_t* atom; ++ ++ if(size < 12) ++ { ++ printf("Error: not enough bytes for stsz atom\n"); ++ return 0; ++ } ++ ++ atom = stsz_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->sample_size_ = read_32(buffer + 4); ++ atom->entries_ = read_32(buffer + 8); ++ buffer += 12; ++ ++ // fix for clayton.mp4, it mistakenly says there is 1 entry ++ if(atom->sample_size_ && atom->entries_) ++ atom->entries_ = 0; ++ ++ if(size < 12 + atom->entries_ * sizeof(uint32_t)) ++ { ++ printf("Error: stsz.entries don't match with size\n"); ++ stsz_exit(atom); ++ return 0; ++ } ++ ++ if(!atom->sample_size_) ++ { ++ atom->sample_sizes_ = (uint32_t*)malloc(atom->entries_ * sizeof(uint32_t)); ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->sample_sizes_[i] = read_32(buffer); ++ buffer += 4; ++ } ++ } ++ ++ return atom; ++} ++ ++static unsigned char* stsz_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct stsz_t* stsz = atom; ++ unsigned int i; ++ unsigned int entries = stsz->sample_size_ ? 0 : stsz->entries_; ++ ++ buffer = write_8(buffer, stsz->version_); ++ buffer = write_24(buffer, stsz->flags_); ++ buffer = write_32(buffer, stsz->sample_size_); ++ buffer = write_32(buffer, entries); ++ for(i = 0; i != entries; ++i) ++ { ++ buffer = write_32(buffer, stsz->sample_sizes_[i]); ++ } ++ ++ return buffer; ++} ++ ++static struct stco_t* stco_init() ++{ ++ struct stco_t* atom = (struct stco_t*)malloc(sizeof(struct stco_t)); ++ atom->chunk_offsets_ = 0; ++ ++ return atom; ++} ++ ++static void stco_exit(struct stco_t* atom) ++{ ++ if(atom->chunk_offsets_) ++ { ++ free(atom->chunk_offsets_); ++ } ++ free(atom); ++} ++ ++static void* stco_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct stco_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = stco_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->entries_ = read_32(buffer + 4); ++ buffer += 8; ++ ++ if(size < 8 + atom->entries_ * sizeof(uint32_t)) ++ return 0; ++ ++ atom->chunk_offsets_ = (uint64_t*)malloc(atom->entries_ * sizeof(uint64_t)); ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->chunk_offsets_[i] = read_32(buffer); ++ buffer += 4; ++ } ++ ++ return atom; ++} ++ ++static void* co64_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct stco_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = stco_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->entries_ = read_32(buffer + 4); ++ buffer += 8; ++ ++ if(size < 8 + atom->entries_ * sizeof(uint64_t)) ++ return 0; ++ ++ atom->chunk_offsets_ = (uint64_t*)malloc(atom->entries_ * sizeof(uint64_t)); ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->chunk_offsets_[i] = read_64(buffer); ++ buffer += 8; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* stco_write(void* parent, void* atom, unsigned char* buffer) ++{ ++ struct stbl_t* stbl = parent; ++ struct stco_t* stco = atom; ++ unsigned int i; ++ ++ stbl->stco_inplace_ = buffer; // newly generated stco (patched inplace) ++ ++ buffer = write_8(buffer, stco->version_); ++ buffer = write_24(buffer, stco->flags_); ++ buffer = write_32(buffer, stco->entries_); ++ for(i = 0; i != stco->entries_; ++i) ++ { ++ buffer = write_32(buffer, (uint32_t)(stco->chunk_offsets_[i])); ++ } ++ ++ return buffer; ++} ++ ++static void stco_shift_offsets(struct stco_t* stco, int offset) ++{ ++ unsigned int i; ++ for(i = 0; i != stco->entries_; ++i) ++ stco->chunk_offsets_[i] += offset; ++} ++ ++static void stco_shift_offsets_inplace(unsigned char* stco, int offset) ++{ ++ unsigned int entries = read_32(stco + 4); ++ unsigned int* table = (unsigned int*)(stco + 8); ++ unsigned int i; ++ for(i = 0; i != entries; ++i) ++ write_32((unsigned char*)&table[i], (read_32((unsigned char*)&table[i]) + offset)); ++} ++ ++static struct ctts_t* ctts_init() ++{ ++ struct ctts_t* atom = (struct ctts_t*)malloc(sizeof(struct ctts_t)); ++ atom->table_ = 0; ++ ++ return atom; ++} ++ ++static void ctts_exit(struct ctts_t* atom) ++{ ++ if(atom->table_) ++ { ++ free(atom->table_); ++ } ++ free(atom); ++} ++ ++static void* ctts_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct ctts_t* atom; ++ ++ if(size < 8) ++ return 0; ++ ++ atom = ctts_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ atom->entries_ = read_32(buffer + 4); ++ ++ if(size < 8 + atom->entries_ * sizeof(struct ctts_table_t)) ++ return 0; ++ ++ buffer += 8; ++ ++ atom->table_ = (struct ctts_table_t*)(malloc(atom->entries_ * sizeof(struct ctts_table_t))); ++ ++ for(i = 0; i != atom->entries_; ++i) ++ { ++ atom->table_[i].sample_count_ = read_32(buffer + 0); ++ atom->table_[i].sample_offset_ = read_32(buffer + 4); ++ buffer += 8; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* ctts_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct ctts_t const* ctts = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, ctts->version_); ++ buffer = write_24(buffer, ctts->flags_); ++ buffer = write_32(buffer, ctts->entries_); ++ for(i = 0; i != ctts->entries_; ++i) ++ { ++ buffer = write_32(buffer, (uint32_t)(ctts->table_[i].sample_count_)); ++ buffer = write_32(buffer, (uint32_t)(ctts->table_[i].sample_offset_)); ++ } ++ ++ return buffer; ++} ++ ++static unsigned int ctts_get_samples(struct ctts_t const* ctts) ++{ ++ unsigned int samples = 0; ++ unsigned int entries = ctts->entries_; ++ unsigned int i; ++ for(i = 0; i != entries; ++i) ++ { ++ unsigned int sample_count = ctts->table_[i].sample_count_; ++// unsigned int sample_offset = ctts->table_[i].sample_offset_; ++ samples += sample_count; ++ } ++ ++ return samples; ++} ++ ++static struct stbl_t* stbl_init() ++{ ++ struct stbl_t* atom = (struct stbl_t*)malloc(sizeof(struct stbl_t)); ++ atom->unknown_atoms_ = 0; ++ atom->stts_ = 0; ++ atom->stss_ = 0; ++ atom->stsc_ = 0; ++ atom->stsz_ = 0; ++ atom->stco_ = 0; ++ atom->ctts_ = 0; ++ ++ return atom; ++} ++ ++static void stbl_exit(struct stbl_t* atom) ++{ ++ if(atom->unknown_atoms_) ++ { ++ unknown_atom_exit(atom->unknown_atoms_); ++ } ++ if(atom->stts_) ++ { ++ stts_exit(atom->stts_); ++ } ++ if(atom->stss_) ++ { ++ stss_exit(atom->stss_); ++ } ++ if(atom->stsc_) ++ { ++ stsc_exit(atom->stsc_); ++ } ++ if(atom->stsz_) ++ { ++ stsz_exit(atom->stsz_); ++ } ++ if(atom->stco_) ++ { ++ stco_exit(atom->stco_); ++ } ++ if(atom->ctts_) ++ { ++ ctts_exit(atom->ctts_); ++ } ++ ++ free(atom); ++} ++ ++static int stbl_add_stts(void* parent, void* child) ++{ ++ struct stbl_t* stbl = parent; ++ stbl->stts_ = child; ++ ++ return 1; ++} ++ ++static int stbl_add_stss(void* parent, void* child) ++{ ++ struct stbl_t* stbl = parent; ++ stbl->stss_ = child; ++ ++ return 1; ++} ++ ++static int stbl_add_stsc(void* parent, void* child) ++{ ++ struct stbl_t* stbl = parent; ++ stbl->stsc_ = child; ++ ++ return 1; ++} ++ ++static int stbl_add_stsz(void* parent, void* child) ++{ ++ struct stbl_t* stbl = parent; ++ stbl->stsz_ = child; ++ ++ return 1; ++} ++ ++static int stbl_add_stco(void* parent, void* child) ++{ ++ struct stbl_t* stbl = parent; ++ stbl->stco_ = child; ++ ++ return 1; ++} ++ ++static int stbl_add_ctts(void* parent, void* child) ++{ ++ struct stbl_t* stbl = parent; ++ stbl->ctts_ = child; ++ ++ return 1; ++} ++ ++static void* stbl_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ struct stbl_t* atom = stbl_init(); ++ ++ struct atom_read_list_t atom_read_list[] = { ++ { FOURCC('s', 't', 't', 's'), atom, &stbl_add_stts, &stts_read }, ++ { FOURCC('s', 't', 's', 's'), atom, &stbl_add_stss, &stss_read }, ++ { FOURCC('s', 't', 's', 'c'), atom, &stbl_add_stsc, &stsc_read }, ++ { FOURCC('s', 't', 's', 'z'), atom, &stbl_add_stsz, &stsz_read }, ++ { FOURCC('s', 't', 'c', 'o'), atom, &stbl_add_stco, &stco_read }, ++ { FOURCC('c', 'o', '6', '4'), atom, &stbl_add_stco, &co64_read }, ++ { FOURCC('c', 't', 't', 's'), atom, &stbl_add_ctts, &ctts_read }, ++ }; ++ ++ int result = atom_reader(atom_read_list, ++ sizeof(atom_read_list) / sizeof(atom_read_list[0]), ++ atom, ++ buffer, size); ++ ++ // check for mandatory atoms ++ if(!atom->stts_) ++ { ++ printf("stbl: missing stts\n"); ++ result = 0; ++ } ++ ++ if(!atom->stsc_) ++ { ++ printf("stbl: missing stsc\n"); ++ result = 0; ++ } ++ ++ if(!atom->stsz_) ++ { ++ printf("stbl: missing stsz\n"); ++ result = 0; ++ } ++ ++ if(!atom->stco_) ++ { ++ printf("stbl: missing stco\n"); ++ result = 0; ++ } ++ ++ if(!result) ++ { ++ stbl_exit(atom); ++ return 0; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* stbl_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct stbl_t* stbl = atom; ++ struct atom_write_list_t atom_write_list[] = { ++ { FOURCC('s', 't', 't', 's'), stbl, stbl->stts_, &stts_write }, ++ { FOURCC('s', 't', 's', 's'), stbl, stbl->stss_, &stss_write }, ++ { FOURCC('s', 't', 's', 'c'), stbl, stbl->stsc_, &stsc_write }, ++ { FOURCC('s', 't', 's', 'z'), stbl, stbl->stsz_, &stsz_write }, ++ { FOURCC('s', 't', 'c', 'o'), stbl, stbl->stco_, &stco_write }, ++ { FOURCC('c', 't', 't', 's'), stbl, stbl->ctts_, &ctts_write }, ++ }; ++ ++ buffer = atom_writer(stbl->unknown_atoms_, ++ atom_write_list, ++ sizeof(atom_write_list) / sizeof(atom_write_list[0]), ++ buffer); ++ ++ return buffer; ++} ++ ++static unsigned int stbl_get_nearest_keyframe(struct stbl_t const* stbl, unsigned int sample) ++{ ++ // If the sync atom is not present, all samples are implicit sync samples. ++ if(!stbl->stss_) ++ return sample; ++ ++ return stss_get_nearest_keyframe(stbl->stss_, sample); ++} ++ ++static struct minf_t* minf_init() ++{ ++ struct minf_t* atom = (struct minf_t*)malloc(sizeof(struct minf_t)); ++ atom->unknown_atoms_ = 0; ++ atom->vmhd_ = 0; ++ atom->stbl_ = 0; ++ ++ return atom; ++} ++ ++static void minf_exit(struct minf_t* atom) ++{ ++ if(atom->unknown_atoms_) ++ { ++ unknown_atom_exit(atom->unknown_atoms_); ++ } ++ if(atom->vmhd_) ++ { ++ vmhd_exit(atom->vmhd_); ++ } ++ if(atom->stbl_) ++ { ++ stbl_exit(atom->stbl_); ++ } ++ free(atom); ++} ++ ++static int minf_add_vmhd(void* parent, void* child) ++{ ++ struct minf_t* minf = parent; ++ minf->vmhd_ = child; ++ ++ return 1; ++} ++ ++static int minf_add_stbl(void* parent, void* child) ++{ ++ struct minf_t* minf = parent; ++ minf->stbl_ = child; ++ ++ return 1; ++} ++ ++static void* minf_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ struct minf_t* atom = minf_init(); ++ ++ struct atom_read_list_t atom_read_list[] = { ++ { FOURCC('v', 'm', 'h', 'd'), atom, &minf_add_vmhd, &vmhd_read }, ++ { FOURCC('s', 't', 'b', 'l'), atom, &minf_add_stbl, &stbl_read } ++ }; ++ ++ int result = atom_reader(atom_read_list, ++ sizeof(atom_read_list) / sizeof(atom_read_list[0]), ++ atom, ++ buffer, size); ++ ++ // check for mandatory atoms ++ if(!atom->stbl_) ++ { ++ printf("minf: missing stbl\n"); ++ result = 0; ++ } ++ ++ if(!result) ++ { ++ minf_exit(atom); ++ return 0; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* minf_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct minf_t const* minf = atom; ++ struct atom_write_list_t atom_write_list[] = { ++ { FOURCC('v', 'm', 'h', 'd'), atom, minf->vmhd_, &vmhd_write }, ++ { FOURCC('s', 't', 'b', 'l'), atom, minf->stbl_, &stbl_write } ++ }; ++ ++ buffer = atom_writer(minf->unknown_atoms_, ++ atom_write_list, ++ sizeof(atom_write_list) / sizeof(atom_write_list[0]), ++ buffer); ++ ++ return buffer; ++} ++ ++static struct mdia_t* mdia_init() ++{ ++ struct mdia_t* atom = (struct mdia_t*)malloc(sizeof(struct mdia_t)); ++ atom->unknown_atoms_ = 0; ++ atom->mdhd_ = 0; ++ atom->hdlr_ = 0; ++ atom->minf_ = 0; ++ ++ return atom; ++} ++ ++static void mdia_exit(struct mdia_t* atom) ++{ ++ if(atom->unknown_atoms_) ++ { ++ unknown_atom_exit(atom->unknown_atoms_); ++ } ++ if(atom->mdhd_) ++ { ++ mdhd_exit(atom->mdhd_); ++ } ++ if(atom->hdlr_) ++ { ++ hdlr_exit(atom->hdlr_); ++ } ++ if(atom->minf_) ++ { ++ minf_exit(atom->minf_); ++ } ++ free(atom); ++} ++ ++static int mdia_add_mdhd(void* parent, void* child) ++{ ++ struct mdia_t* mdia = parent; ++ mdia->mdhd_ = child; ++ ++ return 1; ++} ++ ++static int mdia_add_hdlr(void* parent, void* child) ++{ ++ struct mdia_t* mdia = parent; ++ mdia->hdlr_ = child; ++ ++ return 1; ++} ++ ++static int mdia_add_minf(void* parent, void* child) ++{ ++ struct mdia_t* mdia = parent; ++ mdia->minf_ = child; ++ ++ return 1; ++} ++ ++static void* mdia_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ struct mdia_t* atom = mdia_init(); ++ ++ struct atom_read_list_t atom_read_list[] = { ++ { FOURCC('m', 'd', 'h', 'd'), atom, &mdia_add_mdhd, &mdhd_read }, ++ { FOURCC('h', 'd', 'l', 'r'), atom, &mdia_add_hdlr, &hdlr_read }, ++ { FOURCC('m', 'i', 'n', 'f'), atom, &mdia_add_minf, &minf_read } ++ }; ++ ++ int result = atom_reader(atom_read_list, ++ sizeof(atom_read_list) / sizeof(atom_read_list[0]), ++ atom, ++ buffer, size); ++ ++ // check for mandatory atoms ++ if(!atom->mdhd_) ++ { ++ printf("mdia: missing mdhd\n"); ++ result = 0; ++ } ++ ++ if(!atom->hdlr_) ++ { ++ printf("mdia: missing hdlr\n"); ++ result = 0; ++ } ++ ++ if(!atom->minf_) ++ { ++ printf("mdia: missing minf\n"); ++ result = 0; ++ } ++ ++ if(!result) ++ { ++ mdia_exit(atom); ++ return 0; ++ } ++ ++ return atom; ++} ++ ++static unsigned char* mdia_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct mdia_t const* mdia = atom; ++ struct atom_write_list_t atom_write_list[] = { ++ { FOURCC('m', 'd', 'h', 'd'), atom, mdia->mdhd_, &mdhd_write }, ++ { FOURCC('h', 'd', 'l', 'r'), atom, mdia->hdlr_, &hdlr_write }, ++ { FOURCC('m', 'i', 'n', 'f'), atom, mdia->minf_, &minf_write } ++ }; ++ ++ buffer = atom_writer(mdia->unknown_atoms_, ++ atom_write_list, ++ sizeof(atom_write_list) / sizeof(atom_write_list[0]), ++ buffer); ++ ++ return buffer; ++} ++ ++void trak_build_index(struct trak_t* trak) ++{ ++ struct stco_t const* stco = trak->mdia_->minf_->stbl_->stco_; ++ ++ trak->chunks_size_ = stco->entries_; ++ trak->chunks_ = malloc(trak->chunks_size_ * sizeof(struct chunks_t)); ++ ++ { ++ unsigned int i; ++ for(i = 0; i != trak->chunks_size_; ++i) ++ { ++ trak->chunks_[i].pos_ = stco->chunk_offsets_[i]; ++ } ++ } ++ ++ // process chunkmap: ++ { ++ struct stsc_t const* stsc = trak->mdia_->minf_->stbl_->stsc_; ++ unsigned int last = trak->chunks_size_; ++ unsigned int i = stsc->entries_; ++ while(i > 0) ++ { ++ unsigned int j; ++ ++ --i; ++ ++ for(j = stsc->table_[i].chunk_; j < last; j++) ++ { ++ trak->chunks_[j].id_ = stsc->table_[i].id_; ++ trak->chunks_[j].size_ = stsc->table_[i].samples_; ++ } ++ last = stsc->table_[i].chunk_; ++ } ++ } ++ ++ // calc pts of chunks: ++ { ++ struct stsz_t const* stsz = trak->mdia_->minf_->stbl_->stsz_; ++ unsigned int sample_size = stsz->sample_size_; ++ unsigned int s = 0; ++ { ++ unsigned int j; ++ for(j = 0; j < trak->chunks_size_; j++) ++ { ++ trak->chunks_[j].sample_ = s; ++ s += trak->chunks_[j].size_; ++ } ++ } ++ ++ if(sample_size == 0) ++ { ++ trak->samples_size_ = stsz->entries_; ++ } ++ else ++ { ++ trak->samples_size_ = s; ++ } ++ ++ trak->samples_ = malloc(trak->samples_size_ * sizeof(struct samples_t)); ++ ++ if(sample_size == 0) ++ { ++ unsigned int i; ++ for(i = 0; i != trak->samples_size_ ; ++i) ++ trak->samples_[i].size_ = stsz->sample_sizes_[i]; ++ } ++ else ++ { ++ unsigned int i; ++ for(i = 0; i != trak->samples_size_ ; ++i) ++ trak->samples_[i].size_ = sample_size; ++ } ++ } ++ ++// i = 0; ++// for (j = 0; j < trak->durmap_size; j++) ++// i += trak->durmap[j].num; ++// if (i != s) { ++// mp_msg(MSGT_DEMUX, MSGL_WARN, ++// "MOV: durmap and chunkmap sample count differ (%i vs %i)\n", i, s); ++// if (i > s) s = i; ++// } ++ ++ // calc pts: ++ { ++ struct stts_t const* stts = trak->mdia_->minf_->stbl_->stts_; ++ unsigned int s = 0; ++ unsigned int pts = 0; ++ unsigned int entries = stts->entries_; ++ unsigned int j; ++ for(j = 0; j < entries; j++) ++ { ++ unsigned int i; ++ unsigned int sample_count = stts->table_[j].sample_count_; ++ unsigned int sample_duration = stts->table_[j].sample_duration_; ++ for(i = 0; i < sample_count; i++) ++ { ++ trak->samples_[s].pts_ = pts; ++ ++s; ++ pts += sample_duration; ++ } ++ } ++ } ++ ++ // calc composition times: ++ { ++ struct ctts_t const* ctts = trak->mdia_->minf_->stbl_->ctts_; ++ if(ctts) ++ { ++ unsigned int s = 0; ++ unsigned int entries = ctts->entries_; ++ unsigned int j; ++ for(j = 0; j != entries; j++) ++ { ++ unsigned int i; ++ unsigned int sample_count = ctts->table_[j].sample_count_; ++ unsigned int sample_offset = ctts->table_[j].sample_offset_; ++ for(i = 0; i < sample_count; i++) ++ { ++ trak->samples_[s].cto_ = sample_offset; ++ ++s; ++ } ++ } ++ } ++ } ++ ++ // calc sample offsets ++ { ++ unsigned int s = 0; ++ unsigned int j; ++ for(j = 0; j != trak->chunks_size_; j++) ++ { ++ uint64_t pos = trak->chunks_[j].pos_; ++ unsigned int i; ++ for(i = 0; i != trak->chunks_[j].size_; i++) ++ { ++ trak->samples_[s].pos_ = pos; ++ pos += trak->samples_[s].size_; ++ ++s; ++ } ++ } ++ } ++} ++ ++void trak_update_index(struct trak_t* trak, unsigned int start, unsigned int end) ++{ ++ // write samples [start,end> ++ ++ // stts = [entries * [sample_count, sample_duration] ++ { ++ struct stts_t* stts = trak->mdia_->minf_->stbl_->stts_; ++ ++ unsigned int entries = 0; ++ unsigned int s; ++ ++ for(s = start; s != end; ++s) ++ { ++ unsigned int sample_count = 1; ++ unsigned int sample_duration = ++ trak->samples_[s + 1].pts_ - trak->samples_[s].pts_; ++ while(s != end - 1) ++ { ++ if((trak->samples_[s + 1].pts_ - trak->samples_[s].pts_) != sample_duration) ++ break; ++ ++sample_count; ++ ++s; ++ } ++ stts->table_[entries].sample_count_ = sample_count; ++ stts->table_[entries].sample_duration_ = sample_duration; ++ ++entries; ++ } ++ stts->entries_ = entries; ++ ++ if(stts_get_samples(stts) != end - start) ++ { ++ printf("ERROR: stts_get_samples=%d, should be %d\n", ++ stts_get_samples(stts), end - start); ++ } ++ } ++ ++ // ctts = [entries * [sample_count, sample_offset] ++ { ++ struct ctts_t* ctts = trak->mdia_->minf_->stbl_->ctts_; ++ if(ctts) ++ { ++ unsigned int entries = 0; ++ unsigned int s; ++ ++ for(s = start; s != end; ++s) ++ { ++ unsigned int sample_count = 1; ++ unsigned int sample_offset = trak->samples_[s].cto_; ++ while(s != end - 1) ++ { ++ if(trak->samples_[s + 1].cto_ != sample_offset) ++ break; ++ ++sample_count; ++ ++s; ++ } ++ // write entry ++ ctts->table_[entries].sample_count_ = sample_count; ++ ctts->table_[entries].sample_offset_ = sample_offset; ++ ++entries; ++ } ++ ctts->entries_ = entries; ++ if(ctts_get_samples(ctts) != end - start) ++ { ++ printf("ERROR: ctts_get_samples=%d, should be %d\n", ++ ctts_get_samples(ctts), end - start); ++ } ++ } ++ } ++ ++ // process chunkmap: ++ { ++ struct stsc_t* stsc = trak->mdia_->minf_->stbl_->stsc_; ++ unsigned int i; ++ ++ for(i = 0; i != trak->chunks_size_; ++i) ++ { ++ if(trak->chunks_[i].sample_ + trak->chunks_[i].size_ > start) ++ break; ++ } ++ ++ { ++ unsigned int stsc_entries = 0; ++ unsigned int chunk_start = i; ++ unsigned int chunk_end; ++ // problem.mp4: reported by Jin-seok Lee. Second track contains no samples ++ if(trak->chunks_size_ != 0) ++ { ++ unsigned int samples = ++ trak->chunks_[i].sample_ + trak->chunks_[i].size_ - start; ++ unsigned int id = trak->chunks_[i].id_; ++ ++ // write entry [chunk,samples,id] ++ stsc->table_[stsc_entries].chunk_ = 0; ++ stsc->table_[stsc_entries].samples_ = samples; ++ stsc->table_[stsc_entries].id_ = id; ++ ++stsc_entries; ++ ++ if(i != trak->chunks_size_) ++ { ++ for(i += 1; i != trak->chunks_size_; ++i) ++ { ++ if(trak->chunks_[i].sample_ >= end) ++ break; ++ ++ if(trak->chunks_[i].size_ != samples) ++ { ++ samples = trak->chunks_[i].size_; ++ id = trak->chunks_[i].id_; ++ ++ stsc->table_[stsc_entries].chunk_ = i - chunk_start; ++ stsc->table_[stsc_entries].samples_ = samples; ++ stsc->table_[stsc_entries].id_ = id; ++ ++stsc_entries; ++ } ++ } ++ } ++ } ++ chunk_end = i; ++ stsc->entries_ = stsc_entries; ++ ++ { ++ struct stco_t* stco = trak->mdia_->minf_->stbl_->stco_; ++ unsigned int entries = 0; ++ for(i = chunk_start; i != chunk_end; ++i) ++ { ++ stco->chunk_offsets_[entries] = stco->chunk_offsets_[i]; ++ ++entries; ++ } ++ stco->entries_ = entries; ++ ++ // patch first chunk with correct sample offset ++ stco->chunk_offsets_[0] = (uint32_t)trak->samples_[start].pos_; ++ } ++ } ++ } ++ ++ // process sync samples: ++ if(trak->mdia_->minf_->stbl_->stss_) ++ { ++ struct stss_t* stss = trak->mdia_->minf_->stbl_->stss_; ++ unsigned int entries = 0; ++ unsigned int stss_start; ++ unsigned int i; ++ ++ for(i = 0; i != stss->entries_; ++i) ++ { ++ if(stss->sample_numbers_[i] >= start + 1) ++ break; ++ } ++ stss_start = i; ++ for(; i != stss->entries_; ++i) ++ { ++ unsigned int sync_sample = stss->sample_numbers_[i]; ++ if(sync_sample >= end + 1) ++ break; ++ stss->sample_numbers_[entries] = sync_sample - start; ++ ++entries; ++ } ++ stss->entries_ = entries; ++ } ++ ++ // process sample sizes ++ { ++ struct stsz_t* stsz = trak->mdia_->minf_->stbl_->stsz_; ++ ++ if(stsz->sample_size_ == 0) ++ { ++ unsigned int entries = 0; ++ unsigned int i; ++ for(i = start; i != end; ++i) ++ { ++ stsz->sample_sizes_[entries] = stsz->sample_sizes_[i]; ++ ++entries; ++ } ++ stsz->entries_ = entries; ++ } ++ } ++} ++ ++static struct trak_t* trak_init() ++{ ++ struct trak_t* trak = (struct trak_t*)malloc(sizeof(struct trak_t)); ++ trak->unknown_atoms_ = 0; ++ trak->tkhd_ = 0; ++ trak->mdia_ = 0; ++ trak->chunks_size_ = 0; ++ trak->chunks_ = 0; ++ trak->samples_size_ = 0; ++ trak->samples_ = 0; ++ ++ return trak; ++} ++ ++static void trak_exit(struct trak_t* trak) ++{ ++ if(trak->unknown_atoms_) ++ { ++ unknown_atom_exit(trak->unknown_atoms_); ++ } ++ if(trak->tkhd_) ++ { ++ tkhd_exit(trak->tkhd_); ++ } ++ if(trak->mdia_) ++ { ++ mdia_exit(trak->mdia_); ++ } ++ if(trak->chunks_) ++ { ++ free(trak->chunks_); ++ } ++ if(trak->samples_) ++ { ++ free(trak->samples_); ++ } ++ free(trak); ++} ++ ++static int trak_add_tkhd(void* parent, void* tkhd) ++{ ++ struct trak_t* trak = parent; ++ trak->tkhd_ = tkhd; ++ ++ return 1; ++} ++ ++static int trak_add_mdia(void* parent, void* mdia) ++{ ++ struct trak_t* trak = parent; ++ trak->mdia_ = mdia; ++ ++ return 1; ++} ++ ++static void* trak_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ struct trak_t* atom = trak_init(); ++ ++ struct atom_read_list_t atom_read_list[] = { ++ { FOURCC('t', 'k', 'h', 'd'), atom, &trak_add_tkhd, &tkhd_read }, ++ { FOURCC('m', 'd', 'i', 'a'), atom, &trak_add_mdia, &mdia_read } ++ }; ++ ++ int result = atom_reader(atom_read_list, ++ sizeof(atom_read_list) / sizeof(atom_read_list[0]), ++ atom, ++ buffer, size); ++ ++ // check for mandatory atoms ++ if(!atom->tkhd_) ++ { ++ printf("trak: missing tkhd\n"); ++ result = 0; ++ } ++ ++ if(!atom->mdia_) ++ { ++ printf("trak: missing mdia\n"); ++ result = 0; ++ } ++ ++ if(!result) ++ { ++ trak_exit(atom); ++ return 0; ++ } ++ ++ trak_build_index(atom); ++ ++ return atom; ++} ++ ++static unsigned char* trak_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct trak_t* trak = atom; ++ struct atom_write_list_t atom_write_list[] = { ++ { FOURCC('t', 'k', 'h', 'd'), atom, trak->tkhd_, &tkhd_write }, ++ { FOURCC('m', 'd', 'i', 'a'), atom, trak->mdia_, &mdia_write } ++ }; ++ ++ buffer = atom_writer(trak->unknown_atoms_, ++ atom_write_list, ++ sizeof(atom_write_list) / sizeof(atom_write_list[0]), ++ buffer); ++ ++ return buffer; ++} ++ ++void trak_shift_offsets(struct trak_t* trak, int64_t offset) ++{ ++ struct stco_t* stco = trak->mdia_->minf_->stbl_->stco_; ++ stco_shift_offsets(stco, (int32_t)offset); ++} ++ ++void trak_shift_offsets_inplace(struct trak_t* trak, int64_t offset) ++{ ++ void* stco = trak->mdia_->minf_->stbl_->stco_inplace_; ++ stco_shift_offsets_inplace(stco, (int32_t)offset); ++} ++ ++static struct mvhd_t* mvhd_init() ++{ ++ struct mvhd_t* atom = (struct mvhd_t*)malloc(sizeof(struct mvhd_t)); ++ ++ return atom; ++} ++ ++void mvhd_exit(struct mvhd_t* atom) ++{ ++ free(atom); ++} ++ ++static void* mvhd_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ unsigned int i; ++ ++ struct mvhd_t* atom = mvhd_init(); ++ atom->version_ = read_8(buffer + 0); ++ atom->flags_ = read_24(buffer + 1); ++ if(atom->version_ == 0) ++ { ++ if(size < 108-8) ++ return 0; ++ ++ atom->creation_time_ = read_32(buffer + 4); ++ atom->modification_time_ = read_32(buffer + 8); ++ atom->timescale_ = read_32(buffer + 12); ++ atom->duration_ = read_32(buffer + 16); ++ buffer += 20; ++ } ++ else ++ { ++ if(size < 120-8) ++ return 0; ++ ++ atom->creation_time_ = read_64(buffer + 4); ++ atom->modification_time_ = read_64(buffer + 12); ++ atom->timescale_ = read_32(buffer + 20); ++ atom->duration_ = read_64(buffer + 24); ++ buffer += 32; ++ } ++ atom->rate_ = read_32(buffer + 0); ++ atom->volume_ = read_16(buffer + 4); ++ atom->reserved1_ = read_16(buffer + 6); ++ atom->reserved2_[0] = read_32(buffer + 8); ++ atom->reserved2_[1] = read_32(buffer + 12); ++ buffer += 16; ++ ++ for(i = 0; i != 9; ++i) ++ { ++ atom->matrix_[i] = read_32(buffer); ++ buffer += 4; ++ } ++ ++ for(i = 0; i != 6; ++i) ++ { ++ atom->predefined_[i] = read_32(buffer); ++ buffer += 4; ++ } ++ ++ atom->next_track_id_ = read_32(buffer + 0); ++ ++ return atom; ++} ++ ++static unsigned char* mvhd_write(void* UNUSED(parent), void* atom, unsigned char* buffer) ++{ ++ struct mvhd_t const* mvhd = atom; ++ unsigned int i; ++ ++ buffer = write_8(buffer, mvhd->version_); ++ buffer = write_24(buffer, mvhd->flags_); ++ ++ if(mvhd->version_ == 0) ++ { ++ buffer = write_32(buffer, (uint32_t)mvhd->creation_time_); ++ buffer = write_32(buffer, (uint32_t)mvhd->modification_time_); ++ buffer = write_32(buffer, mvhd->timescale_); ++ buffer = write_32(buffer, (uint32_t)mvhd->duration_); ++ } ++ else ++ { ++ buffer = write_64(buffer, mvhd->creation_time_); ++ buffer = write_64(buffer, mvhd->modification_time_); ++ buffer = write_32(buffer, mvhd->timescale_); ++ buffer = write_64(buffer, mvhd->duration_); ++ } ++ ++ buffer = write_32(buffer, mvhd->rate_); ++ buffer = write_16(buffer, mvhd->volume_); ++ buffer = write_16(buffer, mvhd->reserved1_); ++ buffer = write_32(buffer, mvhd->reserved2_[0]); ++ buffer = write_32(buffer, mvhd->reserved2_[1]); ++ ++ for(i = 0; i != 9; ++i) ++ { ++ buffer = write_32(buffer, mvhd->matrix_[i]); ++ } ++ ++ for(i = 0; i != 6; ++i) ++ { ++ buffer = write_32(buffer, mvhd->predefined_[i]); ++ } ++ ++ buffer = write_32(buffer, mvhd->next_track_id_); ++ ++ return buffer; ++} ++ ++static struct moov_t* moov_init() ++{ ++ struct moov_t* moov = malloc(sizeof(struct moov_t)); ++ moov->unknown_atoms_ = 0; ++ moov->mvhd_ = 0; ++ moov->tracks_ = 0; ++ ++ return moov; ++} ++ ++static void moov_exit(struct moov_t* atom) ++{ ++ unsigned int i; ++ if(atom->unknown_atoms_) ++ { ++ unknown_atom_exit(atom->unknown_atoms_); ++ } ++ if(atom->mvhd_) ++ { ++ mvhd_exit(atom->mvhd_); ++ } ++ for(i = 0; i != atom->tracks_; ++i) ++ { ++ trak_exit(atom->traks_[i]); ++ } ++ free(atom); ++} ++ ++static int moov_add_mvhd(void* parent, void* mvhd) ++{ ++ struct moov_t* moov = parent; ++ moov->mvhd_ = mvhd; ++ ++ return 1; ++} ++ ++static int moov_add_trak(void* parent, void* child) ++{ ++ struct moov_t* moov = parent; ++ struct trak_t* trak = child; ++ if(moov->tracks_ == MAX_TRACKS) ++ { ++ trak_exit(trak); ++ return 0; ++ } ++ ++ if(trak->mdia_->hdlr_->handler_type_ != FOURCC('v', 'i', 'd', 'e') && ++ trak->mdia_->hdlr_->handler_type_ != FOURCC('s', 'o', 'u', 'n')) ++ { ++ printf("Trak ignored (handler_type=%c%c%c%c, name=%s)\n", ++ trak->mdia_->hdlr_->handler_type_ >> 24, ++ trak->mdia_->hdlr_->handler_type_ >> 16, ++ trak->mdia_->hdlr_->handler_type_ >> 8, ++ trak->mdia_->hdlr_->handler_type_, ++ trak->mdia_->hdlr_->name_); ++ trak_exit(trak); ++ return 1; // continue ++ } ++ ++ moov->traks_[moov->tracks_] = trak; ++ ++moov->tracks_; ++ ++ return 1; ++} ++ ++static void* moov_read(void* UNUSED(parent), unsigned char* buffer, uint64_t size) ++{ ++ struct moov_t* atom = moov_init(); ++ ++ struct atom_read_list_t atom_read_list[] = { ++ { FOURCC('m', 'v', 'h', 'd'), atom, &moov_add_mvhd, &mvhd_read }, ++ { FOURCC('t', 'r', 'a', 'k'), atom, &moov_add_trak, &trak_read } ++ }; ++ ++ int result = atom_reader(atom_read_list, ++ sizeof(atom_read_list) / sizeof(atom_read_list[0]), ++ atom, ++ buffer, size); ++ ++ // check for mandatory atoms ++ if(!atom->mvhd_) ++ { ++ printf("moov: missing mvhd\n"); ++ result = 0; ++ } ++ ++ if(!atom->tracks_) ++ { ++ printf("moov: missing trak\n"); ++ result = 0; ++ } ++ ++ if(!result) ++ { ++ moov_exit(atom); ++ return 0; ++ } ++ ++ return atom; ++} ++ ++static void moov_write(struct moov_t* atom, unsigned char* buffer) ++{ ++ unsigned i; ++ ++ unsigned char* atom_start = buffer; ++ ++ struct atom_write_list_t atom_write_list[] = { ++ { FOURCC('m', 'v', 'h', 'd'), atom, atom->mvhd_, &mvhd_write }, ++ }; ++ ++ // atom size ++ buffer += 4; ++ ++ // atom type ++ buffer = write_32(buffer, FOURCC('m', 'o', 'o', 'v')); ++ ++ buffer = atom_writer(atom->unknown_atoms_, ++ atom_write_list, ++ sizeof(atom_write_list) / sizeof(atom_write_list[0]), ++ buffer); ++ ++ for(i = 0; i != atom->tracks_; ++i) ++ { ++ struct atom_write_list_t trak_atom_write_list[] = { ++ { FOURCC('t', 'r', 'a', 'k'), atom, atom->traks_[i], &trak_write }, ++ }; ++ buffer = atom_writer(0, ++ trak_atom_write_list, ++ sizeof(trak_atom_write_list) / sizeof(trak_atom_write_list[0]), ++ buffer); ++ } ++ write_32(atom_start, buffer - atom_start); ++} ++ ++void moov_shift_offsets(struct moov_t* moov, int64_t offset) ++{ ++ unsigned int i; ++ for(i = 0; i != moov->tracks_; ++i) ++ { ++ trak_shift_offsets(moov->traks_[i], offset); ++ } ++} ++ ++void moov_shift_offsets_inplace(struct moov_t* moov, int64_t offset) ++{ ++ unsigned int i; ++ for(i = 0; i != moov->tracks_; ++i) ++ { ++ trak_shift_offsets_inplace(moov->traks_[i], offset); ++ } ++} ++ ++unsigned int moov_seek(unsigned char* moov_data, ++ uint64_t* moov_size, ++ float start_time, ++ float end_time, ++ uint64_t* mdat_start, ++ uint64_t* mdat_size, ++ uint64_t offset, ++ int client_is_flash) ++{ ++ struct moov_t* moov = moov_read(NULL, moov_data + ATOM_PREAMBLE_SIZE, ++ *moov_size - ATOM_PREAMBLE_SIZE); ++ ++ if(moov == 0 || moov->mvhd_ == 0) ++ { ++ printf("Error parsing moov header\n"); ++ return 0; ++ } ++ ++ { ++ long moov_time_scale = moov->mvhd_->timescale_; ++ unsigned int start = (unsigned int)(start_time * moov_time_scale); ++ unsigned int end = (unsigned int)(end_time * moov_time_scale); ++ uint64_t skip_from_start = UINT64_MAX; ++ uint64_t end_offset = 0; ++ unsigned int i; ++ unsigned int pass; ++ ++ // for every trak, convert seconds to sample (time-to-sample). ++ // adjust sample to keyframe ++ unsigned int trak_sample_start[MAX_TRACKS]; ++ unsigned int trak_sample_end[MAX_TRACKS]; ++ ++ uint64_t moov_duration = 0; ++ ++ // clayton.mp4 has a third track with one sample that lasts the whole clip. ++ // Assuming the first two tracks are the audio and video track, we patch ++ // the remaining tracks to 'free' atoms. ++// if(moov->tracks_ > 2) ++// { ++// for(i = 2; i != moov->tracks_; ++i) ++// { ++// // patch 'trak' to 'free' ++// unsigned char* p = moov->traks_[i].start_ - 4; ++// p[0] = 'f'; ++// p[1] = 'r'; ++// p[2] = 'e'; ++// p[3] = 'e'; ++// } ++// moov->tracks_ = 2; ++// } ++ ++ // reported by everwanna: ++ // av out of sync because: ++ // audio track 0 without stss, seek to the exact time. ++ // video track 1 with stss, seek to the nearest key frame time. ++ // ++ // fixed: ++ // first pass we get the new aligned times for traks with an stss present ++ // second pass is for traks without an stss ++ for(pass = 0; pass != 2; ++pass) ++ { ++ for(i = 0; i != moov->tracks_; ++i) ++ { ++ struct trak_t* trak = moov->traks_[i]; ++ struct stbl_t* stbl = trak->mdia_->minf_->stbl_; ++ long trak_time_scale = trak->mdia_->mdhd_->timescale_; ++ float moov_to_trak_time = (float)trak_time_scale / (float)moov_time_scale; ++ float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale; ++ ++ // 1st pass: stss present, 2nd pass: no stss present ++ if(pass == 0 && !stbl->stss_) ++ continue; ++ if(pass == 1 && stbl->stss_) ++ continue; ++ ++ // ignore empty track ++ if(trak->mdia_->mdhd_->duration_ == 0) ++ continue; ++ ++ // get start ++ if(start == 0) ++ { ++ trak_sample_start[i] = start; ++ } ++ else ++ { ++ start = stts_get_sample(stbl->stts_, (uint64_t)(start * moov_to_trak_time)); ++ printf("start=%u (trac time)=%.2f (seconds)", start, ++ stts_get_time(stbl->stts_, start) / (float)trak_time_scale); ++ start = stbl_get_nearest_keyframe(stbl, start + 1) - 1; ++ printf("=%u (zero based keyframe)", start); ++ trak_sample_start[i] = start; ++ start = (unsigned int)(stts_get_time(stbl->stts_, start) * trak_to_moov_time); ++ printf("=%u (moov time)\n", start); ++ } ++ ++ // get end ++ if(end == 0) ++ { ++ trak_sample_end[i] = trak->samples_size_; ++ } ++ else ++ { ++ end = stts_get_sample(stbl->stts_, (uint64_t)(end * moov_to_trak_time)); ++ if(end >= trak->samples_size_) ++ { ++ end = trak->samples_size_; ++ } ++ else ++ { ++ end = stbl_get_nearest_keyframe(stbl, end + 1) - 1; ++ } ++ trak_sample_end[i] = end; ++ printf("endframe=%u, samples_size_=%u\n", end, trak->samples_size_); ++ end = (unsigned int)(stts_get_time(stbl->stts_, end) * trak_to_moov_time); ++ } ++ } ++ } ++ ++ printf("start=%u\n", start); ++ printf("end=%u\n", end); ++ ++ if(end && start >= end) ++ { ++ moov_exit(moov); ++ return 0; ++ } ++ ++ for(i = 0; i != moov->tracks_; ++i) ++ { ++ struct trak_t* trak = moov->traks_[i]; ++ struct stbl_t* stbl = trak->mdia_->minf_->stbl_; ++ ++ unsigned int start_sample = trak_sample_start[i]; ++ unsigned int end_sample = trak_sample_end[i]; ++ ++ // ignore empty track ++ if(trak->mdia_->mdhd_->duration_ == 0) ++ continue; ++ ++ trak_update_index(trak, start_sample, end_sample); ++ ++ { ++ uint64_t skip = ++ trak->samples_[start_sample].pos_ - trak->samples_[0].pos_; ++ if(skip < skip_from_start) ++ skip_from_start = skip; ++ printf("Trak can skip %llu bytes\n", skip); ++ ++ if(end_sample != trak->samples_size_) ++ { ++ uint64_t end_pos = trak->samples_[end_sample].pos_; ++ if(end_pos > end_offset) ++ end_offset = end_pos; ++ printf("New endpos=%llu\n", end_pos); ++ printf("Trak can skip %llu bytes at end\n", ++ *mdat_start + *mdat_size - end_offset); ++ } ++ } ++ ++ { ++ // fixup trak (duration) ++ uint64_t trak_duration = stts_get_duration(stbl->stts_); ++ long trak_time_scale = trak->mdia_->mdhd_->timescale_; ++ float trak_to_moov_time = (float)moov_time_scale / (float)trak_time_scale; ++ { ++ uint64_t duration = (long)((float)trak_duration * trak_to_moov_time); ++ trak->mdia_->mdhd_->duration_= trak_duration; ++ trak->tkhd_->duration_ = duration; ++ printf("trak: new_duration=%lld\n", duration); ++ ++ if(duration > moov_duration) ++ moov_duration = duration; ++ } ++ } ++ ++// printf("stco.size=%d, ", read_int32(stbl->stco_ + 4)); ++// printf("stts.size=%d samples=%d\n", read_int32(stbl->stts_ + 4), stts_get_samples(stbl->stts_)); ++// printf("stsz.size=%d\n", read_int32(stbl->stsz_ + 8)); ++// printf("stsc.samples=%d\n", stsc_get_samples(stbl->stsc_)); ++ } ++ moov->mvhd_->duration_ = moov_duration; ++ ++ // subtract bytes we skip at the front of the mdat atom ++ offset -= skip_from_start; ++ ++ // subtract old moov size ++ offset -= *moov_size; ++ ++ printf("moov: writing header\n"); ++ ++ moov_write(moov, moov_data); ++ *moov_size = read_32(moov_data); ++ ++ // add new moov size ++ offset += *moov_size; ++ ++ printf("shifting offsets by %lld\n", offset); ++ moov_shift_offsets_inplace(moov, offset); ++ ++// moov_write(moov, moov_data); ++ ++#ifdef COMPRESS_MOOV_ATOM ++ if(!client_is_flash) ++ { ++ uLong sourceLen = *moov_size - ATOM_PREAMBLE_SIZE; ++ uLong destLen = compressBound(sourceLen); ++ unsigned char* cmov = malloc(destLen); ++ int zstatus = compress(cmov, &destLen, moov_data, sourceLen); ++ if(zstatus == Z_OK) ++ { ++ printf("cmov size = %lu (%ld%%)\n", destLen, 100 * destLen / sourceLen); ++ } ++ ++ { ++ const int extra_space = 4096; ++ if(destLen + extra_space < sourceLen) ++ { ++ const int bytes_saved = sourceLen - destLen; ++ uLong destLen2; ++ int extra = 0; ++ printf("shifting offsets by %d\n", -bytes_saved); ++ moov_shift_offsets_inplace(moov, -bytes_saved); ++ ++ extra += ATOM_PREAMBLE_SIZE + 4; // dcom ++ extra += ATOM_PREAMBLE_SIZE + 4; // cmvd ++ extra += ATOM_PREAMBLE_SIZE; // cmov ++ extra += ATOM_PREAMBLE_SIZE + extra_space; // free ++ ++ printf("shifting offsets by %d\n", extra); ++ moov_shift_offsets_inplace(moov, extra); ++ ++ // recompress ++ destLen2 = compressBound(sourceLen); ++ zstatus = compress(cmov, &destLen2, moov_data, sourceLen); ++ if(zstatus == Z_OK) ++ { ++ printf("cmov size = %lu (%ld%%)\n", destLen2, 100 * destLen2 / sourceLen); ++ ++ if(destLen2 < destLen + extra_space) ++ { ++ // copy compressed movie atom ++ unsigned char* outbuffer = moov_data; ++ ++ uint32_t dcom_size = ATOM_PREAMBLE_SIZE + 4; ++ uint32_t cmvd_size = ATOM_PREAMBLE_SIZE + 4 + destLen2; ++ uint32_t cmov_size = ATOM_PREAMBLE_SIZE + dcom_size + cmvd_size; ++ uint32_t free_size = ATOM_PREAMBLE_SIZE + extra_space + destLen - destLen2; ++ *moov_size = ATOM_PREAMBLE_SIZE + cmov_size + free_size; ++ ++ outbuffer = write_32(outbuffer, (uint32_t)*moov_size); ++ ++ // skip 'moov' ++ outbuffer += 4; ++ ++ outbuffer = write_32(outbuffer, cmov_size); ++ { ++ outbuffer = write_32(outbuffer, FOURCC('c', 'm', 'o', 'v')); ++ outbuffer = write_32(outbuffer, dcom_size); ++ outbuffer = write_32(outbuffer, FOURCC('d', 'c', 'o', 'm')); ++ outbuffer = write_32(outbuffer, FOURCC('z', 'l', 'i', 'b')); ++ ++ outbuffer = write_32(outbuffer, cmvd_size); ++ { ++ outbuffer = write_32(outbuffer, FOURCC('c', 'm', 'v', 'd')); ++ outbuffer = write_32(outbuffer, sourceLen); ++ memcpy(outbuffer, cmov, destLen2); ++ outbuffer += destLen2; ++ } ++ } ++ ++ // add final padding ++ outbuffer = write_32(outbuffer, free_size); ++ outbuffer = write_32(outbuffer, FOURCC('f', 'r', 'e', 'e')); ++ { ++ const char free_bytes[8] = ++ { ++ 'C', 'o', 'd', 'e','S','h', 'o', 'p' ++ }; ++ uint32_t padding_index; ++ for(padding_index = ATOM_PREAMBLE_SIZE; padding_index != free_size; ++padding_index) ++ { ++ outbuffer[padding_index] = free_bytes[padding_index % 8]; ++ } ++ } ++ } ++ else ++ { ++ printf("2nd pass compress overflow\n"); ++ } ++ } ++ } ++ } ++ free(cmov); ++ } ++#endif ++ ++ *mdat_start += skip_from_start; ++ if(end_offset != 0) ++ { ++ *mdat_size = end_offset; ++ } ++ *mdat_size -= skip_from_start; ++ } ++ ++ moov_exit(moov); ++ ++ return 1; ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++ ++struct mp4_atom_t ++{ ++ uint32_t type_; ++ uint32_t short_size_; ++ uint64_t size_; ++ uint64_t start_; ++ uint64_t end_; ++}; ++ ++static int mp4_atom_read_header(FILE* infile, struct mp4_atom_t* atom) ++{ ++ unsigned char atom_header[8]; ++ ++ atom->start_ = ftell(infile); ++ fread(atom_header, 8, 1, infile); ++ atom->short_size_ = read_32(&atom_header[0]); ++ atom->type_ = read_32(&atom_header[4]); ++ ++ if(atom->short_size_ == 1) ++ { ++ fread(atom_header, 8, 1, infile); ++ atom->size_ = read_64(&atom_header[0]); ++ } ++ else ++ { ++ atom->size_ = atom->short_size_; ++ } ++ ++ atom->end_ = atom->start_ + atom->size_; ++ ++ return 1; ++} ++ ++static int mp4_atom_write_header(unsigned char* outbuffer, struct mp4_atom_t* atom) ++{ ++ int write_box64 = atom->short_size_ == 1 ? 1 : 0; ++ ++ if(write_box64) ++ write_32(outbuffer, 1); ++ else ++ write_32(outbuffer, (uint32_t)atom->size_); ++ ++ write_32(outbuffer + 4, atom->type_); ++ ++ if(write_box64) ++ { ++ write_64(outbuffer + 8, atom->size_); ++ return 16; ++ } ++ else ++ { ++ return 8; ++ } ++} ++ ++int mp4_split(const char* filename, int64_t filesize, ++ float start_time, float end_time, ++ void** mp4_header, uint32_t* mp4_header_size, ++ uint64_t* mdat_offset, uint64_t* mdat_size, ++ int client_is_flash) ++{ ++ FILE* infile; ++ struct mp4_atom_t ftyp_atom; ++ struct mp4_atom_t moov_atom; ++ struct mp4_atom_t mdat_atom; ++ unsigned char* moov_data = 0; ++ unsigned char* buffer; ++ uint64_t new_mdat_start; ++ ++ *mp4_header = 0; ++ memset(&ftyp_atom, 0, sizeof(ftyp_atom)); ++ memset(&moov_atom, 0, sizeof(moov_atom)); ++ memset(&mdat_atom, 0, sizeof(mdat_atom)); ++ ++ infile = fopen(filename, "rb"); ++ if(infile == NULL) ++ { ++ return 0; ++ } ++ ++ while(ftello(infile) < filesize) ++ { ++ struct mp4_atom_t leaf_atom; ++ ++ if(!mp4_atom_read_header(infile, &leaf_atom)) ++ break; ++ ++ printf("Atom(%c%c%c%c,%lld)\n", ++ leaf_atom.type_ >> 24, leaf_atom.type_ >> 16, ++ leaf_atom.type_ >> 8, leaf_atom.type_, ++ leaf_atom.size_); ++ ++ switch(leaf_atom.type_) ++ { ++ case FOURCC('f', 't', 'y', 'p'): ++ ftyp_atom = leaf_atom; ++ break; ++ case FOURCC('m', 'o', 'o', 'v'): ++ moov_atom = leaf_atom; ++ moov_data = (unsigned char*)malloc((size_t)moov_atom.size_); ++ fseeko(infile, moov_atom.start_, SEEK_SET); ++ fread(moov_data, (off_t)moov_atom.size_, 1, infile); ++ break; ++ case FOURCC('m', 'd', 'a', 't'): ++ mdat_atom = leaf_atom; ++ break; ++ } ++ fseeko(infile, leaf_atom.end_, SEEK_SET); ++ } ++ ++ if(moov_atom.size_ == 0) ++ { ++ printf("Error: moov atom not found\n"); ++ fclose(infile); ++ return 0; ++ } ++ ++ if(mdat_atom.size_ == 0) ++ { ++ printf("Error: mdat atom not found\n"); ++ fclose(infile); ++ return 0; ++ } ++ ++ buffer = (unsigned char*)malloc((uint32_t)moov_atom.size_ + 4 * 1024); ++ *mp4_header = buffer; ++ ++ if(ftyp_atom.size_) ++ { ++ fseeko(infile, ftyp_atom.start_, SEEK_SET); ++ fread(buffer, (off_t)ftyp_atom.size_, 1, infile); ++ buffer += ftyp_atom.size_; ++ } ++ ++ { ++ static char const free_data[] = { ++ 0x0, 0x0, 0x0, 42, 'f', 'r', 'e', 'e', ++ 'v', 'i', 'd', 'e', 'o', ' ', 's', 'e', ++ 'r', 'v', 'e', 'd', ' ', 'b', 'y', ' ', ++ 'm', 'o', 'd', '_', 'h', '2', '6', '4', ++ '_', 's', 't', 'r', 'e', 'a', 'm', 'i', ++ 'n', 'g' ++ }; ++ memcpy(buffer, free_data, sizeof(free_data)); ++ buffer += sizeof(free_data); ++ } ++ ++ new_mdat_start = buffer - (unsigned char*)(*mp4_header) + moov_atom.size_; ++ if(!moov_seek(moov_data, ++ &moov_atom.size_, ++ start_time, ++ end_time, ++ &mdat_atom.start_, ++ &mdat_atom.size_, ++ new_mdat_start - mdat_atom.start_, ++ client_is_flash)) ++ { ++ free(moov_data); ++ fclose(infile); ++ return 0; ++ } ++ ++ memcpy(buffer, moov_data, (uint32_t)moov_atom.size_); ++ buffer += moov_atom.size_; ++ free(moov_data); ++ ++ { ++ int mdat_header_size = mp4_atom_write_header(buffer, &mdat_atom); ++ buffer += mdat_header_size; ++ *mdat_offset = mdat_atom.start_ + mdat_header_size; ++ *mdat_size = mdat_atom.size_ - mdat_header_size; ++ } ++ ++ *mp4_header_size = (uint32_t)(buffer - (unsigned char*)(*mp4_header)); ++ ++ fclose(infile); ++ ++ return 1; ++} ++ ++// End Of File ++ +--- /dev/null 2008-11-04 20:33:38.146691408 +0200 ++++ lighttpd-1.4.18/src/moov.h 2009-01-26 21:00:05.071936866 +0200 +@@ -0,0 +1,49 @@ ++/******************************************************************************* ++ moov.h (version 2) ++ ++ moov - A library for splitting Quicktime/MPEG4 files. ++ http://h264.code-shop.com ++ ++ Copyright (C) 2007-2009 CodeShop B.V. ++ ++ Licensing ++ The H264 Streaming Module is licened under a Creative Common License. It allows ++ you to use, modify and redistribute the module, but only for *noncommercial* ++ purposes. For corporate use, please apply for a commercial license. ++ ++ Creative Commons License: ++ http://creativecommons.org/licenses/by-nc-sa/3.0/ ++ ++ Commercial License: ++ http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-License-Version2 ++******************************************************************************/ ++ ++// NOTE: don't include stdio.h (for FILE) or sys/types.h (for off_t). ++// nginx redefines _FILE_OFFSET_BITS and off_t will have different sizes ++// depending on include order ++ ++#ifndef _MSC_VER ++#include ++#else ++#include "inttypes.h" ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern int mp4_split(const char* infile, int64_t filesize, ++ float start_time, float end_time, ++ void** mp4_header, uint32_t* mp4_header_size, ++ uint64_t* mdat_offset, uint64_t* mdat_size, ++ int client_is_flash); ++ ++/* Returns true when the test string is a prefix of the input */ ++extern int starts_with(const char* input, const char* test); ++ ++#ifdef __cplusplus ++} /* extern C definitions */ ++#endif ++ ++// End Of File ++ diff --git a/lighttpd-mod_indexfile.conf b/lighttpd-mod_indexfile.conf new file mode 100644 index 0000000..61d7477 --- /dev/null +++ b/lighttpd-mod_indexfile.conf @@ -0,0 +1,13 @@ +# indexfile module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Index-file-names_Details + +# NOTE: this module is automatically loaded + +# files to check for if .../ is requested +index-file.names = ( + "index.html", + "index.htm", + "index.php", + "default.htm", +) diff --git a/lighttpd-mod_magnet.conf b/lighttpd-mod_magnet.conf new file mode 100644 index 0000000..3df693f --- /dev/null +++ b/lighttpd-mod_magnet.conf @@ -0,0 +1,10 @@ +# a power-magnet module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModMagnet + +server.modules += ( + "mod_magnet" +) + +#magnet.attract-raw-url-to = ... +#magnet.attract-physical-path-to = ... diff --git a/lighttpd-mod_mysql_vhost.conf b/lighttpd-mod_mysql_vhost.conf new file mode 100644 index 0000000..b54b090 --- /dev/null +++ b/lighttpd-mod_mysql_vhost.conf @@ -0,0 +1,7 @@ +# mysql_vhost module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModMySQLVhost + +server.modules += ( + "mod_mysql_vhost" +) diff --git a/lighttpd-mod_proxy.conf b/lighttpd-mod_proxy.conf new file mode 100644 index 0000000..db61021 --- /dev/null +++ b/lighttpd-mod_proxy.conf @@ -0,0 +1,31 @@ +# Let lighttpd act as a proxy server for special file types, hosts etc +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModProxy + +server.modules += ( + "mod_proxy" +) + +## Balance algorithm, possible values are: "hash", "round-robin" or "fair" (default) +# proxy.balance = "hash" + +## Redirect all queries to files ending with ".php" to 192.168.0.101:80 +#proxy.server = ( +# ".php" => (( +# "host" => "192.168.0.101", +# "port" => 80 +# )) +#) + +## Redirect all connections on www.example.com to 10.0.0.1{0,1,2,3} +#$HTTP["host"] == "www.example.com" { +# proxy.balance = "hash" +# proxy.server = ( +# "" => ( +# ( "host" => "10.0.0.10" ), +# ( "host" => "10.0.0.11" ), +# ( "host" => "10.0.0.12" ), +# ( "host" => "10.0.0.13" ), +# ) +# ) +#} diff --git a/lighttpd-mod_redirect.conf b/lighttpd-mod_redirect.conf new file mode 100644 index 0000000..d511b63 --- /dev/null +++ b/lighttpd-mod_redirect.conf @@ -0,0 +1,15 @@ +# Redirection module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModRedirect + +server.modules += ( + "mod_redirect" +) + +#url.redirect = ( +# "^/wishlist/(.+)" => "http://www.123.org/$1", +#) +#### both rewrite/redirect support back reference to regex conditional using %n +#$HTTP["host"] =~ "^www\.(.*)" { +# url.redirect = ( "^/(.*)" => "http://%1/$1" ) +#} diff --git a/lighttpd-mod_rewrite.conf b/lighttpd-mod_rewrite.conf new file mode 100644 index 0000000..0c9fe5a --- /dev/null +++ b/lighttpd-mod_rewrite.conf @@ -0,0 +1,12 @@ +# Rewrite module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModRewrite + +server.modules += ( + "mod_rewrite" +) + +#### url handling modules (rewrite, redirect, access) +#url.rewrite-once = ( +# "^/$" => "/server-status", +#) diff --git a/lighttpd-mod_rrdtool.conf b/lighttpd-mod_rrdtool.conf new file mode 100644 index 0000000..0db0f77 --- /dev/null +++ b/lighttpd-mod_rrdtool.conf @@ -0,0 +1,11 @@ +# rrdtool module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModRRDTool + +server.modules += ( + "mod_rrdtool" +) + +#### rrdtool +rrdtool.binary = "/usr/bin/rrdtool" +rrdtool.db-name = "/var/lib/lighttpd/lighttpd.rrd" diff --git a/lighttpd-mod_scgi.conf b/lighttpd-mod_scgi.conf new file mode 100644 index 0000000..1558dab --- /dev/null +++ b/lighttpd-mod_scgi.conf @@ -0,0 +1,7 @@ +# SCGI module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModSCGI + +server.modules += ( + "mod_scgi" +) diff --git a/lighttpd-mod_secdownload.conf b/lighttpd-mod_secdownload.conf new file mode 100644 index 0000000..c916f1d --- /dev/null +++ b/lighttpd-mod_secdownload.conf @@ -0,0 +1,7 @@ +# secure and fast downloading module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModSecDownload + +server.modules += ( + "mod_secdownload" +) diff --git a/lighttpd-mod_setenv.conf b/lighttpd-mod_setenv.conf new file mode 100644 index 0000000..68763d9 --- /dev/null +++ b/lighttpd-mod_setenv.conf @@ -0,0 +1,19 @@ +# setenv module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModSetEnv + +server.modules += ( + "mod_setenv" +) + +#### setenv +#setenv.add-request-header = ( "TRAV_ENV" => "mysql://user@host/db" ) +#setenv.add-response-header = ( "X-Secret-Message" => "42" ) + +# Add CORS header for font requests +# http://davidwalsh.name/cdn-fonts +#$HTTP["url"] =~ "\.(?:eot|ttf|otf|woff)$" { +# setenv.add-response-header += ( +# "Access-Control-Allow-Origin" => "*", +# ) +#} diff --git a/lighttpd-mod_simple_vhost.conf b/lighttpd-mod_simple_vhost.conf new file mode 100644 index 0000000..5ffb73e --- /dev/null +++ b/lighttpd-mod_simple_vhost.conf @@ -0,0 +1,15 @@ +# Simple name-based virtual hosting +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModSimpleVhost + +server.modules += ( + "mod_simple_vhost" +) + +## The document root of a virtual host isdocument-root = +## simple-vhost.server-root + $HTTP["host"] + simple-vhost.document-root +simple-vhost.server-root = "/home/services/lighttpd/" +simple-vhost.document-root = "/html/" + +## the default host if no host is sent +simple-vhost.default-host = "www.example.com" diff --git a/lighttpd-mod_ssi.conf b/lighttpd-mod_ssi.conf new file mode 100644 index 0000000..21a40d7 --- /dev/null +++ b/lighttpd-mod_ssi.conf @@ -0,0 +1,11 @@ +# Server-Side Include implements simple preprocessing of +# HTML files compatible to Apache SSI. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModSSI + +server.modules += ( + "mod_ssi" +) + +## The extension of the files which should be preprocessed (mostly .shtml) +ssi.extension = ( ".shtml" ) diff --git a/lighttpd-mod_staticfile.conf b/lighttpd-mod_staticfile.conf new file mode 100644 index 0000000..c20d661 --- /dev/null +++ b/lighttpd-mod_staticfile.conf @@ -0,0 +1,11 @@ +# staticfile module. + +# NOTE: this module is automatically loaded + +# see http://redmine.lighttpd.net/issues/1209 +#etag.use-inode = "enable" +#etag.use-mtime = "enable" +#etag.use-size = "enable" + +# ETag header generation (default: enabled) +#static-file.etags = "enable" diff --git a/lighttpd-mod_status.conf b/lighttpd-mod_status.conf new file mode 100644 index 0000000..e388e9d --- /dev/null +++ b/lighttpd-mod_status.conf @@ -0,0 +1,13 @@ +# Status module +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModStatus + +server.modules += ( + "mod_status" +) + +$HTTP["remoteip"] == "127.0.0.1" { + status.status-url = "/server-status" + status.config-url = "/server-config" + status.statistics-url = "/server-stats" +} diff --git a/lighttpd-mod_trigger_b4_dl.conf b/lighttpd-mod_trigger_b4_dl.conf new file mode 100644 index 0000000..1b63371 --- /dev/null +++ b/lighttpd-mod_trigger_b4_dl.conf @@ -0,0 +1,24 @@ +# A module to prevent deep-linking from other sites. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModTriggerBeforeDownload + +server.modules += ( + "mod_trigger_b4_dl" +) + +## guarded download URL, direct access is denied +#trigger-before-download.download-url = "^/download/" + +## trigger URL to allow downloads from +#trigger-before-download.trigger-url = "^/trigger/" + +## if access to a file is denied, the user is redirected to this URL +#trigger-before-download.deny-url = "/home/services/lighttpd/html/deny.html" + +## access to granted for seconds after the trigger +#trigger-before-download.trigger-timeout = 10 + +## storage of trigger information. If both destinations are provided, +## the GDBM file takes precedence. +#trigger-before-download.gdbm-filename = "/home/services/lighttpd/data/trigger.db" +#trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" ) diff --git a/lighttpd-mod_userdir.conf b/lighttpd-mod_userdir.conf new file mode 100644 index 0000000..bc0e418 --- /dev/null +++ b/lighttpd-mod_userdir.conf @@ -0,0 +1,18 @@ +# The userdir module provides a simple way to link user-based directories into +# the global namespace of the webserver. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModUserDir + +server.modules += ( + "mod_userdir" +) + +## the subdirectory of a user's home dir which should be accessible +## under http://$host/~$user +userdir.path = "public_html" + +## The users whose home directories should not be accessible +userdir.exclude-user = ( "root", "postmaster" ) + +## enable userdir module +userdir.active = "enable" diff --git a/lighttpd-mod_usertrack.conf b/lighttpd-mod_usertrack.conf new file mode 100644 index 0000000..eb1aba4 --- /dev/null +++ b/lighttpd-mod_usertrack.conf @@ -0,0 +1,7 @@ +# usertrack module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModUserTrack + +server.modules += ( + "mod_usertrack" +) diff --git a/lighttpd-mod_webdav.conf b/lighttpd-mod_webdav.conf new file mode 100644 index 0000000..86bc602 --- /dev/null +++ b/lighttpd-mod_webdav.conf @@ -0,0 +1,7 @@ +# webdav module. +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModWebDAV + +server.modules += ( + "mod_webdav" +) diff --git a/lighttpd-modinit-before-fork.patch b/lighttpd-modinit-before-fork.patch new file mode 100644 index 0000000..2f2c5e5 --- /dev/null +++ b/lighttpd-modinit-before-fork.patch @@ -0,0 +1,187 @@ +--- ./src/server.c (working copy) ++++ lighttpd-1.4.19/src/server.c 2008-09-19 17:43:33.695522751 +0300 +@@ -865,34 +865,9 @@ + return -1; + } + +-#ifdef HAVE_FORK +- /* network is up, let's deamonize ourself */ +- if (srv->srvconf.dont_daemonize == 0) daemonize(); +-#endif +- + srv->gid = getgid(); + srv->uid = getuid(); + +- /* write pid file */ +- if (pid_fd != -1) { +- buffer_copy_long(srv->tmp_buf, getpid()); +- buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); +- write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1); +- close(pid_fd); +- pid_fd = -1; +- } +- +- /* Close stderr ASAP in the child process to make sure that nothing +- * is being written to that fd which may not be valid anymore. */ +- if (-1 == log_error_open(srv)) { +- log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); +- +- plugins_free(srv); +- network_close(srv); +- server_free(srv); +- return -1; +- } +- + if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { + log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); + +@@ -918,7 +893,86 @@ + return -1; + } + ++ if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { ++ log_error_write(srv, __FILE__, __LINE__, ++ "s", "fdevent_init failed"); ++ return -1; ++ } ++ /* ++ * kqueue() is called here, select resets its internals, ++ * all server sockets get their handlers ++ * ++ * */ ++ if (0 != network_register_fdevents(srv)) { ++ plugins_free(srv); ++ network_close(srv); ++ server_free(srv); ++ ++ return -1; ++ } ++ ++ /* might fail if user is using fam (not gamin) and famd isn't running */ ++ if (NULL == (srv->stat_cache = stat_cache_init())) { ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "stat-cache could not be setup, dieing."); ++ return -1; ++ } ++ ++#ifdef HAVE_FAM_H ++ /* setup FAM */ ++ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { ++ if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { ++ log_error_write(srv, __FILE__, __LINE__, "s", ++ "could not open a fam connection, dieing."); ++ return -1; ++ } ++#ifdef HAVE_FAMNOEXISTS ++ FAMNoExists(srv->stat_cache->fam); ++#endif ++ ++ srv->stat_cache->fam_fcce_ndx = -1; ++ fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); ++ fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN); ++ } ++#endif ++ ++ ++ /* get the current number of FDs */ ++ srv->cur_fds = open("/dev/null", O_RDONLY); ++ close(srv->cur_fds); ++ ++ for (i = 0; i < srv->srv_sockets.used; i++) { ++ server_socket *srv_socket = srv->srv_sockets.ptr[i]; ++ if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { ++ log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); ++ return -1; ++ } ++ } ++ ++ /* Close stderr ASAP to make sure that nothing is being written to ++ * that fd which may not be valid anymore after forking. */ ++ if (-1 == log_error_open(srv)) { ++ log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); ++ ++ plugins_free(srv); ++ network_close(srv); ++ server_free(srv); ++ return -1; ++ } ++ ++#ifdef HAVE_FORK ++ /* network is up, let's deamonize ourself */ ++ if (srv->srvconf.dont_daemonize == 0) daemonize(); ++#endif + ++ /* write pid file */ ++ if (pid_fd != -1) { ++ buffer_copy_long(srv->tmp_buf, getpid()); ++ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); ++ write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1); ++ close(pid_fd); ++ pid_fd = -1; ++ } + + + #ifdef HAVE_SIGACTION +@@ -1042,62 +1096,6 @@ + } + #endif + +- if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { +- log_error_write(srv, __FILE__, __LINE__, +- "s", "fdevent_init failed"); +- return -1; +- } +- /* +- * kqueue() is called here, select resets its internals, +- * all server sockets get their handlers +- * +- * */ +- if (0 != network_register_fdevents(srv)) { +- plugins_free(srv); +- network_close(srv); +- server_free(srv); +- +- return -1; +- } +- +- /* might fail if user is using fam (not gamin) and famd isn't running */ +- if (NULL == (srv->stat_cache = stat_cache_init())) { +- log_error_write(srv, __FILE__, __LINE__, "s", +- "stat-cache could not be setup, dieing."); +- return -1; +- } +- +-#ifdef HAVE_FAM_H +- /* setup FAM */ +- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { +- if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { +- log_error_write(srv, __FILE__, __LINE__, "s", +- "could not open a fam connection, dieing."); +- return -1; +- } +-#ifdef HAVE_FAMNOEXISTS +- FAMNoExists(srv->stat_cache->fam); +-#endif +- +- srv->stat_cache->fam_fcce_ndx = -1; +- fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); +- fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN); +- } +-#endif +- +- +- /* get the current number of FDs */ +- srv->cur_fds = open("/dev/null", O_RDONLY); +- close(srv->cur_fds); +- +- for (i = 0; i < srv->srv_sockets.used; i++) { +- server_socket *srv_socket = srv->srv_sockets.ptr[i]; +- if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { +- log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); +- return -1; +- } +- } +- + /* main-loop */ + while (!srv_shutdown) { + int n; diff --git a/lighttpd-php-external.conf b/lighttpd-php-external.conf new file mode 100644 index 0000000..73741aa --- /dev/null +++ b/lighttpd-php-external.conf @@ -0,0 +1,48 @@ +# FastCGI server for PHP + +# Sometimes you need to run old html file(s) as php pages, especially if you +# are migrating from Apache web server. To treat html pages as php you need to +# map multiple extensions to the same fastcgi server using fastcgi.map-extensions +# directive. +#fastcgi.map-extensions = ( +# ".html" => ".php", +# ".php3" => ".php", +#) + +fastcgi.server += ( + ".php" => (( + "socket" => "/var/run/php/php-fpm.sock", # spawned by php-fpm +# "socket" => "/var/run/php/fcgi.sock", # spawned by php-fcgi-init + # we enable check-local so you can use server.error-handler-404 for php files too + "check-local" => "enable", + "disable-time" => 1, +# "allow-x-send-file" => "enable", + )), + +# for this to work set in /etc/php/php-fpm.conf: +# pm.status_path = /fpm-status +# "/fpm-status" => (( +# "socket" => "/var/run/php/fpm.sock", +# "check-local" => "disable", +# "disable-time" => 1, +# )), +) + +#fastcgi.server += ( +# ".php" => ( +# "local" => ( +# "host" => "127.0.0.1", +# "port" => 1026, +# # we enable check-local so you can use server.error-handler-404 for php files too +# "check-local" => "enable", +# ), +# "slave" => ( +# "host" => "192.168.5.93", +# "port" => 1026, +# # we enable check-local so you can use server.error-handler-404 for php files too +# "check-local" => "enable", +# ), +# ), +#) + +static-file.exclude-extensions += (".php") diff --git a/lighttpd-php-spawned.conf b/lighttpd-php-spawned.conf new file mode 100644 index 0000000..b9869ae --- /dev/null +++ b/lighttpd-php-spawned.conf @@ -0,0 +1,34 @@ +# FastCGI server for PHP + +# Sometimes you need to run old html file(s) as php pages, especially if you +# are migrating from Apache web server. To treat html pages as php you need to +# map multiple extensions to the same fastcgi server using fastcgi.map-extensions +# directive. +#fastcgi.map-extensions = ( +# ".html" => ".php", +# ".php3" => ".php", +#) + +fastcgi.server += ( + ".php" => (( + "bin-path" => "/usr/bin/php.fcgi", + "socket" => "/var/run/php/php-fcgi-" + var.pid + ".sock", + "max-procs" => 2, + "idle-timeout" => 20, + # SIGTERM is graceful shutdown in PLD Linux, use `kill -l' to figure out other signal numbers. +# "kill-signal" => 15, + "bin-environment" => ( + "PHP_FCGI_CHILDREN" => "4", + "PHP_FCGI_MAX_REQUESTS" => "10000" + ), + "bin-copy-environment" => ( + "PATH", "SHELL" + ), + "broken-scriptfilename" => "enable", + "check-local" => "enable", + "disable-time" => 1, +# "allow-x-send-file" => "enable", + )) +) + +static-file.exclude-extensions += (".php") diff --git a/lighttpd-pld.html b/lighttpd-pld.html new file mode 100644 index 0000000..1ff430b --- /dev/null +++ b/lighttpd-pld.html @@ -0,0 +1,29 @@ + + + + + + + Powered by lighttpd + + + + + + +

+LIGHTTPD - fly light. +

+ +

+Powered by Lighttpd
+Powered by PLD Linux +

+ + + diff --git a/lighttpd-ssl.conf b/lighttpd-ssl.conf new file mode 100644 index 0000000..7e89b24 --- /dev/null +++ b/lighttpd-ssl.conf @@ -0,0 +1,52 @@ +# lighttpd support for SSLv2 and SSLv3 +# +# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_SSL + +# (Following SSL/TLS Deployment Best Practices 1.3 / 17 September 2013 from: +# https://www.ssllabs.com/projects/best-practices/index.html) +# - BEAST is considered mitigaed on client side now, and new weaknesses have been found in RC4, +# so it is strongly advised to disable RC4 ciphers (HIGH doesn't include RC4) +# - It is recommended to disable 3DES too (although disabling RC4 and 3DES breaks IE6+8 on Windows XP, +# so you might want to support 3DES for now - just remove the '!3DES' parts below). +# - The examples below prefer ciphersuites with "Forward Secrecy" (and ECDHE over DHE (alias EDH)), remove '+kEDH +kRSA' +# if you don't want that. +# - SRP and PSK are not supported anyway, excluding those ('!kSRP !kPSK') just keeps the list smaller (easier to review) +# Check your cipher list with: openssl ciphers -v '...' (use single quotes as your shell won't like ! in double quotes) +# +# If you know you have RSA keys (standard), you can use: +#ssl.cipher-list = "aRSA+HIGH !3DES +kEDH +kRSA !kSRP !kPSK" +# The more generic version (without the restriction to RSA keys) is +#ssl.cipher-list = "HIGH !aNULL !3DES +kEDH +kRSA !kSRP !kPSK" + +# Make the server prefer the order of the server side cipher suite instead of the client suite. +# This option is enabled by default, but only used if ssl.cipher-list is set. +# +#ssl.honor-cipher-order = "enable" +# + +$SERVER["socket"] == ":443" { + ssl.engine = "enable" + + # unsafe protocols + ssl.use-sslv2 = "disable" + ssl.use-sslv3 = "disable" + + # https://wiki.mozilla.org/Security/Server_Side_TLS + # forward secrecy + ssl.honor-cipher-order = "enable" + ssl.cipher-list = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA" + + # ssl.pemfile: path to the PEM file for SSL support (Should contain both + # the private key and the certificate) + ## If you have a .crt and a .key file, cat them together into a + ## single PEM file: + ## $ cat lighttpd.key lighttpd.crt > lighttpd.pem + ssl.pemfile = "/etc/lighttpd/server.pem" + + # ssl.ca-file: path to the CA file for support of chained certificates +# ssl.ca-file = "/etc/certs/ca-certificates.crt" + + $HTTP["useragent"] =~ "MSIE" { + server.max-keep-alive-requests = 0 + } +} diff --git a/lighttpd-use_bin_sh.patch b/lighttpd-use_bin_sh.patch new file mode 100644 index 0000000..de08dd3 --- /dev/null +++ b/lighttpd-use_bin_sh.patch @@ -0,0 +1,20 @@ +## Use /bin/sh to execute external programs instead of getting +## the shell from $SHELL (See ticket #388) +# +# http://trac.lighttpd.net/trac/ticket/388 + +--- lighttpd-1.4.12/src/proc_open.c~ 2006-09-19 15:49:41.846531074 +0300 ++++ lighttpd-1.4.12/src/proc_open.c 2006-09-19 15:51:13.658593480 +0300 +@@ -219,11 +219,7 @@ + /* {{{ proc_open */ + int proc_open(proc_handler_t *proc, const char *command) { + pid_t child; +- const char *shell; +- +- if (NULL == (shell = getenv(SHELLENV))) { +- shell = "/bin/sh"; +- } ++ const char *shell = "/bin/sh"; + + if (proc_open_pipes(proc) != 0) { + return -1; diff --git a/lighttpd.conf b/lighttpd.conf new file mode 100644 index 0000000..75079f7 --- /dev/null +++ b/lighttpd.conf @@ -0,0 +1,187 @@ +# lighttpd configuration file. + +include_shell "for f in conf.d/*.conf ; do [ -f \"$f\" ] && echo \"include \\"$f\\"\" ; done" + +## a static document-root, for virtual-hosting take look at the +## server.virtual-* options +server.document-root = "/home/services/lighttpd/html/" + +## where to send error-messages to +server.errorlog = "/var/log/lighttpd/error.log" +#server.errorlog-use-syslog = "enable" + +## http://redmine.lighttpd.net/projects/lighttpd/repository/revisions/2550 +## NOTE: It is not reopened in log_error_cycle, so don't setup logrotate to this. +server.breakagelog = "/var/log/lighttpd/breakage.log" + +server.pid-file = "/var/run/lighttpd.pid" + +# mimetype mapping +include "mime.types.conf" +# default mime type +mimetype.assign += ( + "" => "application/octet-stream", +) + +## set the event-handler (read the performance section in the manual) +# Linux 2.4+ rt-signals linux-rtsig +# Linux 2.6+ epoll linux-sysepoll +#server.event-handler = "linux-sysepoll" + +## The basic network interface for all platforms at the syscalls read() +## and write(). Every modern OS provides its own syscall to help network +## servers transfer files as fast as possible +## +## linux-sendfile - is recommended for small files. +## writev - is recommended for sending many large files +## +#server.network-backend = "linux-sendfile" + +# default cames from ulimit -n +#server.max-fds = 8192 + +## +## Stat() call caching. +## +## lighttpd can utilize FAM/Gamin to cache stat call. +## +## possible values are: +## disable, simple or fam. +## +#server.stat-cache-engine = "simple" + +## +## Fine tuning for the request handling +## +## max-connections == max-fds/2 (maybe /3) +## means the other file handles are used for fastcgi/files +## +#server.max-connections = 1024 + +# maximum number of request within a keep-alive session before the server terminates the connection +# default 16 +#server.max-keep-alive-requests = 16 + +# Maximum number of seconds until an idling keep-alive connection is dropped. +# default 30 +#server.max-keep-alive-idle = 30 + +# maximum number of seconds until a waiting, non keep-alive read times out and closes the connection +# default 60 +#server.max-read-idle = 60 + +# maximum number of seconds until a waiting write call times out and closes the connection +# default 360 +#server.max-write-idle = 360 + +## +## Maximum size of a request in kilobytes. +## By default it is unlimited (0). +## +## Uploads to your server can't be larger than this value. +## +#server.max-request-size = 0 + +# Use the "Content-Type" extended attribute to obtain mime type if possible +#mimetype.use-xattr = "enable" + +## +## Should lighttpd follow symlinks? +## +#server.follow-symlink = "enable" + +## +## force all filenames to be lowercase? +## +#server.force-lowercase-filenames = "disable" + +## +## defaults to /var/tmp as we assume it is a local harddisk +## +server.upload-dirs = ( "/var/tmp" ) + +## +## The value for the "Server:" response field. +## +## It would be nice to keep it at "lighttpd". +## +#server.tag = "lighttpd" + +$HTTP["url"] =~ "\.pdf$" { + server.range-requests = "disable" +} + +## Skip responding with 417 for unhandled Expect header for some broken applications +#server.reject-expect-100-with-417 = "disable" + +######### Options that are good to be but not neccesary to be changed ####### + +## bind to port (default: 80) +server.port = 80 + +## Use IPv6? +#server.use-ipv6 = "enable" + +## bind to specific host (default: all interfaces) +## the name is resolved to ip at startup only. +#server.bind = "www.example.org" + +## additionally just bind to localhost:80 +#$SERVER["socket"] == "127.0.0.1:80" {} + +## error-handler for status 404 +#server.error-handler-404 = "/error-handler.html" +#server.error-handler-404 = "/error-handler.php" + +## +## Format: .html +## -> ..../status-404.html for 'File not found' +#server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-" +# +## enable debugging +# http://redmine.lighttpd.net/projects/lighttpd/wiki/DebugVariables +#debug.log-request-header = "enable" +#debug.log-request-header-on-error = "enable" +#debug.log-response-header = "enable" +#debug.log-request-handling = "enable" +#debug.log-file-not-found = "enable" +#debug.log-condition-handling = "enable" +#debug.log-condition-cache-handling = "enable" +#debug.log-timeouts = "enable" +#debug.log-ssl-noise = "enable" + +### only root can use these options +# +# chroot() to directory (default: no chroot() ) +#server.chroot = "/" + +## change uid to (default: don't care) +server.username = "lighttpd" + +## change uid to (default: don't care) +server.groupname = "lighttpd" + +## +## Traffic Shaping +## ----------------- +## +## Values are in kilobyte per second. +## +## Keep in mind that a limit below 32kB/s might actually limit the +## traffic to 32kB/s. This is caused by the size of the TCP send +## buffer. +## +## per server: +## +#server.kbytes-per-second = 128 + +## +## per connection: +## +#connection.kbytes-per-second = 32 + +# webapps configs +include_shell "for f in webapps.d/*.conf ; do [ -f \"$f\" ] && echo \"include \\"$f\\"\" ; done" + +# vhosts config +include_shell "for f in vhosts.d/*.conf ; do [ -f \"$f\" ] && echo \"include \\"$f\\"\" ; done" diff --git a/lighttpd.init b/lighttpd.init new file mode 100755 index 0000000..aaf4d5f --- /dev/null +++ b/lighttpd.init @@ -0,0 +1,226 @@ +#!/bin/sh +# +# lighttpd lighttpd Web Server +# +# chkconfig: 345 85 15 +# description: lighttpd is a World Wide Web server. It is used to serve \ +# HTML files and CGI. +# + +# Source function library +. /etc/rc.d/init.d/functions + +upstart_controlled + +# Get network config +. /etc/sysconfig/network + +# Get service config +[ -f /etc/sysconfig/lighttpd ] && . /etc/sysconfig/lighttpd + +DAEMON=/usr/sbin/lighttpd +ANGEL_DAEMON=/usr/sbin/lighttpd-angel +CONFIGFILE=/etc/lighttpd/lighttpd.conf + +# Check that networking is up. +if is_yes "${NETWORKING}"; then + if [ ! -f /var/lock/subsys/network -a "$1" != stop -a "$1" != status ]; then + msg_network_down "Lighttpd Web Server" + exit 1 + fi +else + exit 0 +fi + +configtest() { + # check for deprecated config options that cause bad side effects + # TODO: should remove the deprecated options in pld after some time being warned out + local out + out=$(env SHELL=/bin/sh $DAEMON -f $CONFIGFILE $HTTPD_OPTS -p 2>&1 | grep -oE '(url.rewrite|url.rewrite-final)[[:space:]]') + if [ -n "$out" ]; then + # make it unique, format nicely + out=$(echo "$out" | sort -u | xargs | sed -e 's/ /, /g') + echo >&2 "WARNING: found deprecated '$out', convert to 'url.rewrite-final' recommented, See http://redmine.lighttpd.net/issues/2379" + fi + + env SHELL=/bin/sh $DAEMON -t -f $CONFIGFILE $HTTPD_OPTS +} + +# wrapper for configtest +checkconfig() { + local details=${1:-0} + + if [ $details = 1 ]; then + # run config test and display report (status action) + show "Checking %s configuration" "Lighttpd Web Server"; busy + local out + out=$(configtest 2>&1) + RETVAL=$? + if [ $RETVAL = 0 ]; then + ok + else + fail + fi + [ "$out" ] && echo >&2 "$out" + else + # run config test and abort with nice message if failed + # (for actions checking status before action). + configtest >/dev/null 2>&1 + RETVAL=$? + if [ $RETVAL != 0 ]; then + show "Checking %s configuration" "Lighttpd Web Server"; fail + nls 'Configuration test failed. See details with %s "checkconfig"' $0 + exit $RETVAL + fi + fi +} + +start() { + # Check if the service is already running? + if [ -f /var/lock/subsys/lighttpd ]; then + msg_already_running "Lighttpd Web Server" + return + fi + + checkconfig + msg_starting "Lighttpd Web Server"; busy + if is_yes "${LIGHT_ANGEL}"; then + daemon --fork --pidfile /var/run/lighttpd-angel.pid --makepid \ + env SHELL=/bin/sh $ANGEL_DAEMON -D -f $CONFIGFILE $HTTPD_OPTS + + else + env SHELL=/bin/sh $DAEMON -f $CONFIGFILE $HTTPD_OPTS + fi + RETVAL=$? + if [ $RETVAL -eq 0 ]; then + ok + touch /var/lock/subsys/lighttpd + else + fail + fi +} + +stop() { + # Stop daemons. + if [ ! -f /var/lock/subsys/lighttpd ]; then + msg_not_running "Lighttpd Web Server" + return + fi + + msg_stopping "Lighttpd Web Server" + killproc --pidfile /var/run/lighttpd.pid lighttpd + rm -f /var/lock/subsys/lighttpd >/dev/null 2>&1 + rm -f /var/run/lighttpd*.pid >/dev/null 2>&1 +} + +restart() { + local pid + + # short circuit to safe reload if pid exists and is alive + if is_yes "${LIGHT_ANGEL}"; then + if [ -f /var/lock/subsys/lighttpd ] && pid=$(pidofproc lighttpd-angel lighttpd-angel.pid) && checkpid $pid; then + reload + return + fi + else + if [ -f /var/lock/subsys/lighttpd ] && pid=$(pidofproc lighttpd lighttpd.pid) && checkpid $pid; then + reload + return + fi + fi + + checkconfig + stop + start +} + +reload() { + # TODO: check if process is running. Start it in this case. + if [ ! -f /var/lock/subsys/lighttpd ]; then + msg_not_running "Lighttpd Web Server" + RETVAL=7 + return + fi + + checkconfig 1 + msg_reloading "Lighttpd Web Server" + + if is_yes "${LIGHT_ANGEL}"; then + # sending HUP signal to angel will make lighttpd close all listening + # sockets and wait for client connections to terminate. After that new + # child will be started + killproc lighttpd-angel -HUP + else + # sending INT signal will make lighttpd close all listening sockets and + # wait for client connections to terminate. + killproc --pidfile /var/run/lighttpd.pid lighttpd -INT + env SHELL=/bin/sh lighttpd -f $CONFIGFILE $HTTPD_OPTS + fi + RETVAL=$? +} + +condrestart() { + if [ ! -f /var/lock/subsys/lighttpd ]; then + msg_not_running "Lighttpd Web Server" + RETVAL=$1 + return + fi + + checkconfig + stop + start +} + +flush-logs() { + if [ ! -f /var/lock/subsys/lighttpd ]; then + msg_not_running "Lighttpd Web Server" + RETVAL=7 + return + fi + + show "Rotating %s logs" lighttpd + # send HUP to main lighttpd (not angel) process to rotate logs: + killproc --pidfile /var/run/lighttpd.pid lighttpd -HUP + RETVAL=$? +} + +RETVAL=0 +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + restart + ;; + try-restart) + condrestart 0 + ;; + reload|force-reload|graceful) + reload + ;; + flush-logs) + flush-logs + ;; + checkconfig|configtest) + checkconfig 1 + ;; + show-config) + env SHELL=/bin/sh $DAEMON -p -f $CONFIGFILE $HTTPD_OPTS + ;; + status) + if is_yes "${LIGHT_ANGEL}"; then + status lighttpd-angel || RETVAL=$? + fi + status lighttpd || RETVAL=$? + ;; + *) + msg_usage "$0 {start|stop|restart|reload|force-reload|graceful|configtest|flush-logs|show-config|status}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/lighttpd.logrotate b/lighttpd.logrotate new file mode 100644 index 0000000..3d5dc28 --- /dev/null +++ b/lighttpd.logrotate @@ -0,0 +1,12 @@ +/var/log/lighttpd/access.log +/var/log/lighttpd/error.log +{ + olddir /var/log/archive/lighttpd + + create 640 lighttpd logs + + sharedscripts + postrotate + /sbin/service lighttpd flush-logs > /dev/null + endscript +} diff --git a/lighttpd.monitrc b/lighttpd.monitrc new file mode 100644 index 0000000..516dcb9 --- /dev/null +++ b/lighttpd.monitrc @@ -0,0 +1,31 @@ +check process lighttpd with pidfile /var/run/lighttpd.pid + group www + start program = "/etc/rc.d/init.d/lighttpd start" + stop program = "/etc/rc.d/init.d/lighttpd stop" + if failed url http://localhost/ timeout 10 seconds then restart +# if failed host 192.168.1.1 port 443 type TCPSSL +# certmd5 12-34-56-78-90-AB-CD-EF-12-34-56-78-90-AB-CD-EF +# protocol HTTP request /monit/token then restart + if 5 restarts within 5 cycles then timeout +# alert root@localhost +# alert 123456@sms on { timeout } + depends on lighttpd_bin + depends on lighttpd_rc + + check file lighttpd_bin with path /usr/sbin/lighttpd + group www + if failed checksum then unmonitor + if failed permission 755 then unmonitor + if failed uid root then unmonitor + if failed gid root then unmonitor +# alert root@localhost + + check file lighttpd_rc with path /etc/rc.d/init.d/lighttpd + group www + if failed checksum then unmonitor + if failed permission 754 then unmonitor + if failed uid root then unmonitor + if failed gid root then unmonitor +# alert root@localhost + + diff --git a/lighttpd.service b/lighttpd.service new file mode 100644 index 0000000..6f4dce9 --- /dev/null +++ b/lighttpd.service @@ -0,0 +1,12 @@ +[Unit] +Description=Lighttpd Daemon +After=network.target + +[Service] +EnvironmentFile=-/etc/sysconfig/lighttpd +ExecStartPre=/usr/sbin/lighttpd-angel -t -f /etc/lighttpd/lighttpd.conf +ExecStart=/usr/sbin/lighttpd-angel -D -f /etc/lighttpd/lighttpd.conf $HTTPD_OPTS +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target diff --git a/lighttpd.spec b/lighttpd.spec new file mode 100644 index 0000000..c2c4894 --- /dev/null +++ b/lighttpd.spec @@ -0,0 +1,1346 @@ + +# TODO: +# - provide or autogenerate self signed cert in post, so after installing +# lighttpd-ssl server will still work +# - patch with mod_websocket: https://github.com/Juniper/lighttpd-for-juise +# +# Conditional build: +%bcond_with tests # build with tests +%bcond_without xattr # support of extended attributes +%bcond_without ipv6 # IPv4-only version (doesn't require IPv6 in kernel) +%bcond_without largefile # largefile support (see notes above) +%bcond_without ssl # ssl support +%bcond_without mysql # mysql support in mod_mysql_vhost +%bcond_without ldap # ldap support in mod_auth +%bcond_without lua # LUA support in mod_cml (needs LUA >= 5.1) +%bcond_with memcache # memcached support in mod_cml / mod_trigger_b4_dl +%bcond_with gamin # gamin for reducing number of stat() calls. + # NOTE: must be enabled in config: server.stat-cache-engine = "fam" +%bcond_with gdbm # gdbm in mod_trigger_b4_dl +%bcond_with webdav_props # properties in mod_webdav (includes extra sqlite3/libxml deps) +%bcond_with webdav_locks # webdav locks with extra efsprogs deps +%bcond_with valgrind # compile code with valgrind support. +%bcond_with deflate # build deflate module (needs patch update with current svn) + +%if %{with webdav_locks} +%define webdav_progs 1 +%endif + +Summary: Fast and light HTTP server +Summary(pl.UTF-8): Szybki i lekki serwer HTTP +Name: lighttpd +Version: 1.4.35 +Release: 6 +License: BSD +Group: Networking/Daemons/HTTP +Source0: http://download.lighttpd.net/lighttpd/releases-1.4.x/%{name}-%{version}.tar.bz2 +# Source0-md5: f7a88130ee9984b421ad8aa80629750a +Source1: %{name}.init +Source2: %{name}.conf +Source3: %{name}.user +Source4: %{name}.logrotate +Source5: %{name}.sysconfig +Source6: %{name}-mime.types.sh +Source7: http://glen.alkohol.ee/pld/lighty/favicon.ico +# Source7-md5: 00fcac5b861a54f5eb147a589504d480 +Source8: light_button.png +# Source8-md5: 3e1008ee1d3d6d390cf81fe3072b4f50 +Source9: light_logo.png +# Source9-md5: cbb7f0676e51ee2e26cf004df293fc62 +Source10: pld_button.png +# Source10-md5: 185afa921e81bd726b9f0f9f0909dc6e +Source11: %{name}-pld.html +Source12: %{name}.monitrc +Source13: branch.sh +Source14: TODO +Source15: %{name}.upstart +Source16: %{name}.tmpfiles +Source17: %{name}.service +Source100: %{name}-mod_access.conf +Source101: %{name}-mod_accesslog.conf +Source102: %{name}-mod_alias.conf +Source103: %{name}-mod_auth.conf +Source104: %{name}-mod_cgi.conf +Source105: %{name}-mod_cml.conf +Source106: %{name}-mod_compress.conf +Source107: %{name}-mod_deflate.conf +Source108: %{name}-mod_dirlisting.conf +Source109: %{name}-mod_evasive.conf +Source110: %{name}-mod_evhost.conf +Source111: %{name}-mod_expire.conf +Source112: %{name}-mod_fastcgi.conf +Source113: %{name}-mod_flv_streaming.conf +Source114: %{name}-mod_indexfile.conf +Source115: %{name}-mod_proxy.conf +Source116: %{name}-mod_redirect.conf +Source117: %{name}-mod_rewrite.conf +Source118: %{name}-mod_rrdtool.conf +Source119: %{name}-mod_scgi.conf +Source120: %{name}-mod_secdownload.conf +Source121: %{name}-mod_setenv.conf +Source122: %{name}-mod_simple_vhost.conf +Source123: %{name}-mod_ssi.conf +Source124: %{name}-mod_staticfile.conf +Source125: %{name}-mod_status.conf +Source126: %{name}-mod_trigger_b4_dl.conf +Source127: %{name}-mod_userdir.conf +Source128: %{name}-mod_usertrack.conf +Source129: %{name}-mod_webdav.conf +Source130: %{name}-php-spawned.conf +Source131: %{name}-php-external.conf +Source132: %{name}-ssl.conf +Source133: %{name}-mod_mysql_vhost.conf +Source134: %{name}-mod_magnet.conf +Source135: %{name}-mod_extforward.conf +Source136: %{name}-mod_h264_streaming.conf +Source137: %{name}-mod_cgi_php.conf +Source138: %{name}-mod_compress.tmpwatch +#Patch100: %{name}-branch.diff +Patch0: %{name}-use_bin_sh.patch +Patch1: %{name}-mod_evasive-status_code.patch +Patch2: %{name}-mod_h264_streaming.patch +Patch3: %{name}-branding.patch +Patch5: %{name}-mod_deflate.patch +Patch6: test-port-setup.patch +Patch7: env-documentroot.patch +#Patch: %{name}-modinit-before-fork.patch +#Patch: %{name}-errorlog-before-fork.patch +URL: http://www.lighttpd.net/ +%{?with_xattr:BuildRequires: attr-devel} +BuildRequires: autoconf >= 2.57 +%if "%{pld_release}" != "ac" +BuildRequires: automake >= 1:1.11.2 +%else +BuildRequires: automake +%endif +BuildRequires: bzip2-devel +BuildRequires: fcgi-devel +%{?with_gamin:BuildRequires: gamin-devel} +%{?with_gdbm:BuildRequires: gdbm-devel} +%{?with_memcache:BuildRequires: libmemcache-devel} +BuildRequires: libtool +BuildRequires: libuuid-devel +%{?with_webdav_props:BuildRequires: libxml2-devel} +%{?with_lua:BuildRequires: lua51-devel} +BuildRequires: mailcap >= 2.1.14-4.4 +%{?with_mysql:BuildRequires: mysql-devel} +%{?with_ldap:BuildRequires: openldap-devel} +%{?with_ssl:BuildRequires: openssl-devel} +BuildRequires: pcre-devel +BuildRequires: pkgconfig +BuildRequires: rpm >= 4.4.9-56 +BuildRequires: rpmbuild(macros) >= 1.647 +%{?with_webdav_props:BuildRequires: sqlite3-devel} +%{?with_valgrind:BuildRequires: valgrind} +BuildRequires: which +BuildRequires: zlib-devel +Requires(post,preun): /sbin/chkconfig +Requires(postun): /usr/sbin/groupdel +Requires(postun): /usr/sbin/userdel +Requires(pre): /bin/id +Requires(pre): /usr/bin/getgid +Requires(pre): /usr/lib/rpm/user_group.sh +Requires(pre): /usr/sbin/groupadd +Requires(pre): /usr/sbin/useradd +Requires(pre): /usr/sbin/usermod +Requires: %{name}-mod_dirlisting = %{version}-%{release} +Requires: %{name}-mod_indexfile = %{version}-%{release} +Requires: %{name}-mod_staticfile = %{version}-%{release} +Requires: rc-scripts >= 0.4.3.0 +Requires: rpm-whiteout >= 1.5 +Requires: systemd-units >= 38 +Suggests: %{name}-mod_accesslog +Provides: group(http) +Provides: group(lighttpd) +Provides: user(lighttpd) +Provides: webserver +Provides: webserver(headers) +Provides: webserver(mime) +Conflicts: logrotate < 3.7-4 +# for the posttrans scriptlet, conflicts because in vserver environment rpm package is not installed. +Conflicts: rpm < 4.4.2-0.2 +BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n) + +%define _libdir %{_prefix}/%{_lib}/%{name} +%define _lighttpddir /home/services/%{name} +%define _sysconfdir /etc/%{name} + +%description +lighttpd is a secure, fast, compliant and very flexible web-server +which has been optimized for high-performance environments. It has a +very low memory footprint compared to other webservers and takes care +of cpu-load. Its advanced feature-set (FastCGI, CGI, Auth, +Output-Compression, URL-Rewriting and many more) make lighttpd the +perfect webserver-software for every server that is suffering load +problems. + +%description -l pl.UTF-8 +lighttpd jest bezpiecznym, szybkim, przyjaznym i bardzo elastycznym +serwerem WWW, który został zoptymalizowany pod kątem +wysokowydajnościowych środowisk. Zajmuje bardzo małą ilość pamięci w +porównaniu do innych serwerów WWW oraz dba o zajętość procesora. +Szeroki zestaw opcji (FastCGI, CGI, uwierzytelnianie, kompresja +wyjścia, przepisywanie URL-i i wiele innych) czynią z lighttpd +doskonałe oprogramowanie web-serwerowe na każdy serwer cierpiący z +powodu problemów z obciążeniem. + +%package mod_access +Summary: lighttpd module for making access restrictions +Summary(pl.UTF-8): Moduł lighttpd ograniczający dostęp +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModAccess +Requires: %{name} = %{version}-%{release} +Provides: webserver(access) + +%description mod_access +The access module is used to deny access to files with given trailing +path names. + +%description mod_access -l pl.UTF-8 +Moduł access służy do ograniczania dostępu do plików o podanych +ścieżkach. + +%package mod_accesslog +Summary: lighttpd module to record access logs +Summary(pl.UTF-8): Moduł lighttpd do zapisu logów dostępu +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModAccessLog +Requires: %{name} = %{version}-%{release} + +%description mod_accesslog +CLF like by default, flexible like Apache. + +%description mod_accesslog -l pl.UTF-8 +Domyślnie podobny do CLF, elastyczny jak Apache. + +%package mod_alias +Summary: lighttpd module for making URL aliasing +Summary(pl.UTF-8): Moduł lighttpd odpowiadający za aliasy URL-i +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModAlias +Requires: %{name} = %{version}-%{release} +Provides: webserver(alias) + +%description mod_alias +The alias module is used to specify a special document-root for a +given URL-subset. + +%description mod_alias -l pl.UTF-8 +Modul alias służy do określania specjalnego drzewa (document-roota) +dla podanego podzbioru URL-i. + +%package mod_auth +Summary: lighttpd module for authentication support +Summary(pl.UTF-8): Moduł lighttpd do obsługi uwierzytelniania +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModAuth +Requires: %{name} = %{version}-%{release} +Provides: webserver(auth) + +%description mod_auth +lighttpd supportes both authentication method described by RFC 2617: +basic and digest. + +%description mod_auth -l pl.UTF-8 +lighttpd obsługuje obie metody uwierzytelniania opisane w RFC 2617: +basic i digest. + +%package mod_cgi +Summary: lighttpd module for CGI handling +Summary(pl.UTF-8): Moduł lighttpd do obsługi CGI +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModCGI +Requires: %{name} = %{version}-%{release} +Requires: %{name}-mod_alias = %{version}-%{release} +Provides: webserver(cgi) + +%description mod_cgi +The cgi module provides a CGI-conforming interface. + +CGI programs allow you to enhance the functionality of the server in a +very straight and simple way. + +%description mod_cgi -l pl.UTF-8 +Moduł cgi udostępnia interfejs zgodny z CGI. + +Programy CGI pozwalają rozszerzać funkcjonalność serwera w bardzo +prosty i naturalny sposób. + +%package mod_cgi_php +Summary: lighttpd module for CGI handling PHP scripts +Summary(pl.UTF-8): Moduł lighttpd do obsługi skryptów PHP przez CGI +Group: Networking/Daemons/HTTP +Requires: %{name}-mod_cgi = %{version}-%{release} +Requires: php(cgi) +Provides: webserver(php) + +%description mod_cgi_php +The cgi module provides a CGI-conforming interface for PHP scripts. + +CGI programs allow you to enhance the functionality of the server in a +very straight and simple way. + +%description mod_cgi_php -l pl.UTF-8 +Moduł cgi udostępnia interfejs zgodny z CGI do wywoływania skryptów +PHP. + +Programy CGI pozwalają rozszerzać funkcjonalność serwera w bardzo +prosty i naturalny sposób. + +%package mod_cml +Summary: lighttpd module for Cache Meta Language +Summary(pl.UTF-8): Moduł Cache Meta Language +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModCML +Requires: %{name} = %{version}-%{release} + +%description mod_cml +CML is a Meta language to describe the dependencies of a page at one +side and building a page from its fragments on the other side using +LUA. + +%description mod_cml -l pl.UTF-8 +CML to metajęzyk służący z jednej strony do opisu zależności strony i +z drugiej strony do budowania strony z fragmentów przy użyciu LUA. + +%package mod_compress +Summary: lighttpd module for output compression +Summary(pl.UTF-8): Moduł lighttpd do kompresji wyjścia +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModCompress +Requires: %{name} = %{version}-%{release} + +%description mod_compress +Output compression reduces the network load and can improve the +overall throughput of the webserver. + +Only static content is supported up to now. + +The server negotiates automatically which compression method is used. +Supported are gzip, deflate, bzip. + +%description mod_compress -l pl.UTF-8 +Kompresja wyjścia zmniejsza obciążenie sieci i może poprawić całkowitą +przepustowość serwera WWW. + +Jak na razie obsługiwana jest tylko statyczna treść. + +Serwer automatycznie negocjuje, która metoda kompresji jest używana. +Obsługiwane są gzip, deflate i bzip. + +%package mod_deflate +Summary: lighttpd module for output compression using deflate method +Summary(pl.UTF-8): Moduł lighttpd do kompresji wyjścia metodą deflate +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Mod_Deflate +Requires: %{name} = %{version}-%{release} + +%description mod_deflate +mod_deflate can compress any output from lighttpd static or dynamic. +It doesn't support caching compressed output like mod_compress. + +%description mod_deflate -l pl.UTF-8 +mod_deflate potrafi kompresować statyczne i dynamiczne wyjście z +lighttpd. Nie obsługuje cache'owania wyniku kompresji, jak robi to +mod_compress. + +%package mod_dirlisting +Summary: lighttpd module for directory listings +Summary(pl.UTF-8): Moduł lighttpd do tworzenia listingów katalogów +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModDirlisting +Requires: %{name} = %{version}-%{release} + +%description mod_dirlisting +mod_dirlisting generates HTML based directory listings with full CSS +control. + +%description mod_dirlisting -l pl.UTF-8 +mod_dirlisting tworzy listingi katalogów w formacie HTML z pełną +kontrolą CSS. + +%package mod_evasive +Summary: lighttpd evasive module +Summary(pl.UTF-8): Moduł evasive dla lighttpd +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModEvasive +Requires: %{name} = %{version}-%{release} + +%description mod_evasive +lighttpd evasive module. + +%description mod_evasive -l pl.UTF-8 +Moduł evasive dla lighttpd. + +%package mod_evhost +Summary: lighttpd module for enhanced virtual-hosting +Summary(pl.UTF-8): Moduł lighttpd rozszerzający obsługę hostów wirtualnych +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModEVhost +Requires: %{name} = %{version}-%{release} + +%description mod_evhost +mod_evhost builds the document-root based on a pattern which contains +wildcards. Those wildcards can represent parts of the submitted +hostname. + +%description mod_evhost -l pl.UTF-8 +mod_evhost tworzy document-root w oparciu o wzorzec zawierający znaki +wieloznaczne (wildcards). Znaki te reprezentują części przekazanej +nazwy hosta. + +%package mod_expire +Summary: lighttpd module for controlling the expiration of content in caches +Summary(pl.UTF-8): Moduł lighttpd sterujący wygasaniem treści w cache'ach +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModExpire +Requires: %{name} = %{version}-%{release} +Provides: webserver(expires) + +%description mod_expire +mod_expire controls the setting of the the Expire response header. + +%description mod_expire -l pl.UTF-8 +mod_expire steruje ustawianiem nagłówka odpowiedzi Expire. + +%package mod_extforward +Summary: lighttpd module to extract the client's "real" IP from X-Forwarded-For header +Summary(pl.UTF-8): Moduł lighttpd wyciągający "prawdziwy" IP klienta z nagłówka X-Forwarded-For +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/DocsModExtForward +Requires: %{name} = %{version}-%{release} + +%description mod_extforward +This module will extract the client's "real" IP from X-Forwarded-For +header which is added by Squid or other proxies. It might be useful +for servers behind reverse proxy servers. + +%description mod_extforward -l pl.UTF-8 +Ten moduł wyciąga "prawdziwy" IP klienta z nagłówka X-Forwarded-For +dodawanego przez Squida czy inne proxy. Może być przydatny dla +serwerów stojących za odwrotnymi serwerami proxy. + +%package mod_fastcgi +Summary: lighttpd module for FastCGI interface +Summary(pl.UTF-8): Moduł lighttpd do interfejsu FastCGI +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModFastCGI +Requires: %{name} = %{version}-%{release} + +%description mod_fastcgi +The FastCGI interface is the fastest and most secure way to interface +external process-handlers like Perl, PHP and your self-written +applications. + +%description mod_fastcgi -l pl.UTF-8 +Interfejs FastCGI to najszybszy i najbezpieczniejszy sposób +komunikacji z zewnętrznymi programami obsługującymi procesy, takimi +jak Perl, PHP czy własne aplikacje. + +%package mod_flv_streaming +Summary: lighttpd module for flv streaming +Summary(pl.UTF-8): Moduł lighttpd do streamingu flv +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModFLVStreaming +Requires: %{name} = %{version}-%{release} + +%description mod_flv_streaming +lighttpd module for flv streaming. + +%description mod_flv_streaming -l pl.UTF-8 +Moduł lighttpd do streamingu flv. + +%package mod_h264_streaming +Summary: lighttpd module for h264 streaming +Summary(pl.UTF-8): Moduł lighttpd do emisji strumieni h264 +License: CC 3.0 BY-NC-SA +Group: Networking/Daemons/HTTP +URL: http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-Lighttpd-Version2 +Requires: %{name} = %{version}-%{release} + +%description mod_h264_streaming +A lighttpd plugin for pseudo-streaming QuickTime/MPEG-4 files. + +%description mod_h264_streaming -l pl.UTF-8 +Moduł lighttpd do pseudostreamingu plików QuickTime/MPEG-4. + +%package mod_indexfile +Summary: lighttpd indexfile module +Summary(pl.UTF-8): Moduł indexfile dla lighttpd +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Index-file-names.Details +Requires: %{name} = %{version}-%{release} +Provides: webserver(indexfile) + +%description mod_indexfile +indexfile module. + +%description mod_indexfile -l pl.UTF-8 +Moduł indexfile. + +%package mod_magnet +Summary: lighttpd powermagnet module +Summary(pl.UTF-8): Moduł powermagnet dla lighttpd +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModMagnet +Requires: %{name} = %{version}-%{release} + +%description mod_magnet +mod_magnet is a module to control the request handling in lighty. + +%description mod_magnet -l pl.UTF-8 +mod_magnet to moduł sterujący obsługą żądań w lighty. + +%package mod_mysql_vhost +Summary: lighttpd module for MySQL based vhosting +Summary(pl.UTF-8): Moduł lighttpd obsługujący vhosty oparte na MySQL-u +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModMySQLVhost +Requires: %{name} = %{version}-%{release} +Conflicts: %{name}-mod_simple_vhost + +%description mod_mysql_vhost +This module provides virtual hosts (vhosts) based on a MySQL table. + +%description mod_mysql_vhost -l pl.UTF-8 +Ten moduł udostępnia wirtualne hosty (vhosty) oparte na tabeli MySQL. + +%package mod_proxy +Summary: lighttpd module for proxying requests +Summary(pl.UTF-8): Moduł lighttpd do przekazywania żądań +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModProxy +Requires: %{name} = %{version}-%{release} + +%description mod_proxy +The proxy module a simplest way to connect lighttpd to Java servers +which have a HTTP-interface. + +%description mod_proxy -l pl.UTF-8 +Moduł proxy to najprostszy sposób łączenia lighttpd z serwerami Javy +mającymi interfejs HTTP. + +%package mod_proxy_core +Summary: lighttpd module for proxying requests +Summary(pl.UTF-8): Moduł lighttpd do przekazywania żądań +Group: Networking/Daemons/HTTP +URL: http://blog.lighttpd.net/articles/2006/07/18/mod_proxy_core-commited-to-svn +Requires: %{name} = %{version}-%{release} + +%description mod_proxy_core +The proxy module a simplest way to connect lighttpd to java servers +which have a HTTP-interface. + +This is the new proxy code. + +%description mod_proxy_core -l pl.UTF-8 +Moduł proxy to najprostszy sposób łączenia lighttpd z serwerami Javy +mającymi interfejs HTTP. + +Ten pakiet zawiera nowy moduł proxy. + +%package mod_redirect +Summary: lighttpd module for URL redirects +Summary(pl.UTF-8): Moduł lighttpd do przekierowań URL-i +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModRedirect +Requires: %{name} = %{version}-%{release} + +%description mod_redirect +With mod_redirect module you can redirect a set of URLs externally. + +%description mod_redirect -l pl.UTF-8 +Przy użyciu modułu mod_redirect można przekierować zbiór URL-i na +zewnątrz. + +%package mod_rewrite +Summary: lighttpd module for internal redirects, URL rewrite +Summary(pl.UTF-8): Moduł lighttpd do wewnętrznych przekierowań i przepisywania URL-i +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModRewrite +Requires: %{name} = %{version}-%{release} +Provides: webserver(rewrite) + +%description mod_rewrite +This module allows you rewrite a set of URLs interally in the +webserver BEFORE they are handled. + +%description mod_rewrite -l pl.UTF-8 +Ten moduł pozwala na przepisywanie zbioru URL-i wewnętrznie w serwerze +WWW _przed_ ich obsługą. + +%package mod_rrdtool +Summary: lighttpd module for monitoring traffic and server load +Summary(pl.UTF-8): Moduł lighttpd do monitorowania ruchu i obciążenia serwera +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModRRDTool +Requires: %{name} = %{version}-%{release} +Requires: rrdtool + +%description mod_rrdtool +RRD is a system to store and display time-series data (i.e. network +bandwidth, machine-room temperature, server load average). + +With this module you can monitor the traffic and load on the +webserver. + +%description mod_rrdtool -l pl.UTF-8 +RRD to system przechowywania i wyświetlania danych zależnych od czasu +(np. obciążenia sieci, temperatury w serwerowni, średniego obciążenia +serwera). + +Przy użyciu tego modułu można monitorować ruch i obciążenie serwera +WWW. + +%package mod_scgi +Summary: lighttpd module for SCGI interface +Summary(pl.UTF-8): Moduł lighttpd do interfejsu SCGI +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModSCGI +Requires: %{name} = %{version}-%{release} + +%description mod_scgi +SCGI is a fast and simplified CGI interface. It is mostly used by +Python + WSGI. + +%description mod_scgi -l pl.UTF-8 +SCGI to szybki i uproszczony interfejs CGI. Jest używany głównie przez +Pythona z WSGI. + +%package mod_secdownload +Summary: lighttpd module for secure and fast downloading +Summary(pl.UTF-8): Moduł lighttpd do bezpiecznego i szybkiego ściągania danych +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModSecDownload +Requires: %{name} = %{version}-%{release} + +%description mod_secdownload +With this module you can easily achieve authenticated file requests +and a countermeasure against deep-linking. + +%description mod_secdownload -l pl.UTF-8 +Przy użyciu tego modułu można łatwo umożliwić ściąganie plików z +uwierzytelnieniem i zapobiec używaniu bezpośrednich odnośników. + +%package mod_setenv +Summary: lighttpd module for setting conditional request headers +Summary(pl.UTF-8): Moduł lighttpd do ustawiania warunkowych nagłówków żądań +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModSetEnv +Requires: %{name} = %{version}-%{release} +Provides: webserver(setenv) + +%description mod_setenv +mod_setenv is used to add request headers. + +%description mod_setenv -l pl.UTF-8 +mod_setenv służy do dodawania nagłówków żądań. + +%package mod_simple_vhost +Summary: lighttpd module for simple virtual-hosting +Summary(pl.UTF-8): Moduł lighttpd do prostych hostów wirtualnych +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModSimpleVhost +Requires: %{name} = %{version}-%{release} +Conflicts: %{name}-mod_mysql_vhost + +%description mod_simple_vhost +lighttpd module for simple virtual-hosting. + +%description mod_simple_vhost -l pl.UTF-8 +Moduł lighttpd do prostych hostów wirtualnych. + +%package mod_ssi +Summary: lighttpd module for server-side includes +Summary(pl.UTF-8): Moduł lighttpd do SSI (server-side includes) +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModSSI +Requires: %{name} = %{version}-%{release} + +%description mod_ssi +The module for server-side includes provides a compatability layer for +NSCA/Apache SSI. + +%description mod_ssi -l pl.UTF-8 +Moduł server-side includes udostępnia warstwę kompatybilności z SSI +znanym z NSCA/Apache'a. + +%package mod_staticfile +Summary: lighttpd module for static file serving +Summary(pl.UTF-8): Moduł lighttpd do serwowania statycznych plików +Group: Networking/Daemons/HTTP +Requires: %{name} = %{version}-%{release} + +%description mod_staticfile +lighttpd module for static file serving. + +%description mod_staticfile -l pl.UTF-8 +Moduł lighttpd do serwowania statycznych plików. + +%package mod_status +Summary: lighttpd module for displaying server status +Summary(pl.UTF-8): Moduł lighttpd do wyświetlania stanu serwera +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModStatus +Requires: %{name} = %{version}-%{release} + +%description mod_status +mod_status displays the server's status and configuration. + +%description mod_status -l pl.UTF-8 +mod_status wyświetla stan i konfigurację serwera. + +%package mod_trigger_b4_dl +Summary: Trigger before Download +Summary(pl.UTF-8): Wyzwalacz przed ściąganiem +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModTriggerBeforeDownload +Requires: %{name} = %{version}-%{release} + +%description mod_trigger_b4_dl +Another anti hot-linking module. + +%description mod_trigger_b4_dl -l pl.UTF-8 +Jeszcze jeden moduł blokujący bezpośrednie linkowanie. + +%package mod_userdir +Summary: lighttpd module for user homedirs +Summary(pl.UTF-8): Moduł lighttpd obsługujący katalogi domowe użytkowników +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModUserDir +Requires: %{name} = %{version}-%{release} + +%description mod_userdir +The userdir module provides a simple way to link user-based +directories into the global namespace of the webserver. + +%description mod_userdir -l pl.UTF-8 +Moduł userdir udostępnia prosty sposób włączenia katalogów +użytkowników do globalnej przestrzeni nazw serwera WWW. + +%package mod_usertrack +Summary: lighttpd usertrack module +Summary(pl.UTF-8): Moduł usertrack dla lighttpd +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModUserTrack +Requires: %{name} = %{version}-%{release} + +%description mod_usertrack +lighttpd usertrack module. + +%description mod_usertrack -l pl.UTF-8 +Moduł usertrack dla lighttpd. + +%package mod_webdav +Summary: WebDAV module for lighttpd +Summary(pl.UTF-8): Moduł WebDAV dla libghttpd +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModWebDAV +Requires: %{name} = %{version}-%{release} + +%description mod_webdav +The WebDAV module is a very minimalistic implementation of RFC 2518. +Minimalistic means that not all operations are implementated yet. + +So far we have +- PROPFIND +- OPTIONS +- MKCOL +- DELETE +- PUT +- LOCK (experimental) + +and the usual GET, POST, HEAD from HTTP/1.1. + +So far mounting a webdav resource into Windows XP works and the basic +litmus tests are passed. + +%description mod_webdav -l pl.UTF-8 +Moduł WebDAV to bardzo minimalistyczna implementacja RFC 2518. +Minimalistyczna oznacza, że jeszcze nie wszystkie operacje są +zaimplementowane. Jak na razie są: +- PROPFIND +- OPTIONS +- MKCOL +- DELETE +- PUT +- LOCK (experimental) + +oraz zwykłe GET, POST, HEAD z HTTP/1.1. + +Jak na razie montowanie zasobu webdav pod Windows XP działa i +podstawowe testy lakmusowe przechodzą. + +%package php-spawned +Summary: PHP support via FastCGI, spawned by lighttpd +Summary(pl.UTF-8): Obsługa PHP przez FastCGI, uruchamiane przez lighttpd +Group: Networking/Daemons/HTTP +Requires: %{name} = %{version}-%{release} +Requires: %{name}-mod_fastcgi = %{version}-%{release} +Requires: php(fcgi) +Provides: webserver(php) +Obsoletes: lighttpd-php-external + +%description php-spawned +PHP support via FastCGI, spawned by lighttpd. + +%description php-spawned -l pl.UTF-8 +Obsługa PHP przez FastCGI, uruchamiane przez lighttpd. + +%package php-external +Summary: PHP support via FastCGI, spawning controlled externally +Summary(pl.UTF-8): Obsługa PHP przez FastCGI, uruchamianie sterowane zewnętrznie +Group: Networking/Daemons/HTTP +Requires: %{name} = %{version}-%{release} +Requires: %{name}-mod_fastcgi = %{version}-%{release} +Suggests: php(fpm) +Suggests: php-fcgi-init +Obsoletes: lighttpd-php-spawned + +%description php-external +PHP support via FastCGI, spawning controlled externally. + +%description php-external -l pl.UTF-8 +Obsługa PHP przez FastCGI, uruchamianie sterowane zewnętrznie. + +%package ssl +Summary: lighttpd support for SSLv2 and SSLv3 +Summary(pl.UTF-8): Obsługa SSLv2 i SSLv3 dla lighttpd +Group: Networking/Daemons/HTTP +URL: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:SSL +Requires: %{name} = %{version}-%{release} +Suggests: ca-certificates + +%description ssl +lighttpd support for SSLv2 and SSLv3. + +%description ssl -l pl.UTF-8 +Obsługa SSLv2 i SSLv3 dla lighttpd. + +%package -n monit-rc-lighttpd +Summary: lighttpd support for monit +Summary(pl.UTF-8): Wsparcie lighttpd dla monit +Group: Applications/System +Requires: %{name} = %{version}-%{release} +Requires: monit + +%description -n monit-rc-lighttpd +monitrc file for monitoring lighttpd web server. + +%description -n monit-rc-lighttpd -l pl.UTF-8 +Plik monitrc do monitorowania serwera www lighttpd. + +%prep +%setup -q +#%patch100 -p0 +#%patch4 -p0 +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%{?with_deflate:%patch5 -p1} +%patch6 -p1 +%patch7 -p0 + +rm -f src/mod_ssi_exprparser.h # bad patching: should be removed by is emptied instead + +# build mime.types.conf +sh %{SOURCE6} /etc/mime.types +cp -p %{SOURCE14} PLD-TODO + +%if "%{pld_release}" == "ac" +%{__sed} -i -e 's/ serial_tests//' configure.ac +%endif + +%build +ver=$(awk '/AC_INIT/{a=$2;gsub(/[\[\],]/, "", a); print a}' configure.ac) +if [ "$ver" != "%{version}" ]; then + : configure.ac specifies wrong version + exit 1 +fi + +%{__libtoolize} +%{__aclocal} +%{__autoconf} +%{__automake} + +%configure \ + %{!?with_ipv6:--disable-ipv6} \ + %{!?with_largefile:--disable-lfs} \ + %{?with_valgrind:--with-valgrind} \ + %{?with_xattr:--with-attr} \ + %{?with_mysql:--with-mysql} \ + %{?with_ldap:--with-ldap} \ + %{?with_ssl:--with-openssl} \ + %{?with_lua:--with-lua=lua51} \ + %{?with_memcache:--with-memcache} \ + %{?with_webdav_props:--with-webdav-props} \ + %{?with_webdav_locks:--with-webdav-locks} \ + %{?with_gamin:--with-gamin} \ + %{?with_gdbm:--with-gdbm} + +# -j1 as src/mod_ssi_exprparser.h regeneration deps are broken +%{__make} -j1 + +%if %{with tests} +export LIGHTTPD_TEST_PORT=$((2048 + RANDOM % 10)) +%{__make} check +%endif + +%install +rm -rf $RPM_BUILD_ROOT +install -d $RPM_BUILD_ROOT{%{_lighttpddir}/{cgi-bin,html},/etc/{logrotate.d,rc.d/init.d,sysconfig,init,monit}} \ + $RPM_BUILD_ROOT%{_sysconfdir}/{conf,vhosts,webapps}.d \ + $RPM_BUILD_ROOT{/var/log/{%{name},archive/%{name}},/var/run/%{name}} \ + $RPM_BUILD_ROOT%{_datadir}/lighttpd/errordocs \ + $RPM_BUILD_ROOT/var/lib/lighttpd \ + $RPM_BUILD_ROOT/var/cache/lighttpd/mod_compress \ + $RPM_BUILD_ROOT{%{systemdtmpfilesdir},%{systemdunitdir}} + +%{__make} install \ + DESTDIR=$RPM_BUILD_ROOT + +install -p %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/%{name} +cp -p %{SOURCE2} %{SOURCE3} mime.types.conf $RPM_BUILD_ROOT%{_sysconfdir} +cp -p %{SOURCE4} $RPM_BUILD_ROOT/etc/logrotate.d/%{name} +cp -p %{SOURCE5} $RPM_BUILD_ROOT/etc/sysconfig/%{name} +cp -p %{SOURCE12} $RPM_BUILD_ROOT/etc/monit/%{name}.monitrc +cp -p %{SOURCE15} $RPM_BUILD_ROOT/etc/init/%{name}.conf +cp -p %{SOURCE16} $RPM_BUILD_ROOT%{systemdtmpfilesdir}/%{name}.conf +cp -p %{SOURCE17} $RPM_BUILD_ROOT%{systemdunitdir}/%{name}.service + +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +# Install lighttpd images +cp -p %{SOURCE7} %{SOURCE8} %{SOURCE9} $RPM_BUILD_ROOT%{_lighttpddir}/html +cp -p %{SOURCE10} $RPM_BUILD_ROOT%{_lighttpddir}/html/pld_button.png +cp -p %{SOURCE11} $RPM_BUILD_ROOT%{_lighttpddir}/html/index.html + +# NOTE: the order of the modules is somewhat important as the modules are +# handled in the way they are specified. mod_rewrite should always be the first +# module, mod_accesslog always the last. + +conf_available=$RPM_BUILD_ROOT%{_sysconfdir}/conf.d +conf_enabled=../ + +cp -p %{SOURCE117} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/10_mod_rewrite.conf +cp -p %{SOURCE116} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/11_mod_redirect.conf + +cp -p %{SOURCE100} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_access.conf +cp -p %{SOURCE102} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_alias.conf +cp -p %{SOURCE103} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_auth.conf +cp -p %{SOURCE104} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_cgi.conf +cp -p %{SOURCE137} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_cgi_php.conf +cp -p %{SOURCE105} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_cml.conf +cp -p %{SOURCE107} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_deflate.conf +cp -p %{SOURCE108} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_dirlisting.conf +cp -p %{SOURCE109} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_evasive.conf +cp -p %{SOURCE110} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_evhost.conf +cp -p %{SOURCE112} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_fastcgi.conf +cp -p %{SOURCE113} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_flv_streaming.conf +cp -p %{SOURCE136} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_h264_streaming.conf +cp -p %{SOURCE114} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_indexfile.conf +cp -p %{SOURCE115} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_proxy.conf +cp -p %{SOURCE118} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_rrdtool.conf +cp -p %{SOURCE119} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_scgi.conf +cp -p %{SOURCE120} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_secdownload.conf +cp -p %{SOURCE121} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_setenv.conf +cp -p %{SOURCE122} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_simple_vhost.conf +cp -p %{SOURCE123} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_ssi.conf +cp -p %{SOURCE124} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_staticfile.conf +cp -p %{SOURCE125} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_status.conf +cp -p %{SOURCE126} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_trigger_b4_dl.conf +cp -p %{SOURCE127} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_userdir.conf +cp -p %{SOURCE128} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_usertrack.conf +cp -p %{SOURCE129} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_webdav.conf +cp -p %{SOURCE133} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/50_mod_mysql_vhost.conf + +cp -p %{SOURCE134} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/55_mod_magnet.conf +cp -p %{SOURCE111} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/55_mod_expire.conf + +cp -p %{SOURCE106} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/60_mod_compress.conf + +cp -p %{SOURCE101} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/90_mod_accesslog.conf +cp -p %{SOURCE135} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/91_mod_extforward.conf + +cp -p %{SOURCE130} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/php-spawned.conf +cp -p %{SOURCE131} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/php-external.conf +cp -p %{SOURCE132} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/ssl.conf + +touch $RPM_BUILD_ROOT/var/lib/lighttpd/lighttpd.rrd + +install -d $RPM_BUILD_ROOT/etc/tmpwatch +cp -p %{SOURCE138} $RPM_BUILD_ROOT/etc/tmpwatch/lighttpd-mod_compress.conf + +%if %{without mysql} +# avoid packaging dummy module +%{__rm} $RPM_BUILD_ROOT%{_libdir}/mod_mysql_vhost.so +%{__rm} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/*_mod_mysql_vhost.conf +%endif +%if %{without deflate} +%{__rm} $RPM_BUILD_ROOT%{_sysconfdir}/conf.d/*_mod_deflate.conf +%endif + +touch $RPM_BUILD_ROOT/var/log/%{name}/{access,error,breakage}.log + +%clean +rm -rf $RPM_BUILD_ROOT + +%pre +%groupadd -g 109 lighttpd +%groupadd -g 51 http +%useradd -u 116 -d %{_lighttpddir} -c "Lighttpd User" -g lighttpd lighttpd +%addusertogroup lighttpd http + +%post +for a in access.log error.log breakage.log; do + if [ ! -f /var/log/%{name}/$a ]; then + touch /var/log/%{name}/$a + chown lighttpd:lighttpd /var/log/%{name}/$a + chmod 644 /var/log/%{name}/$a + fi +done +/sbin/chkconfig --add %{name} +%systemd_post %{name}.service + +%preun +if [ "$1" = "0" ]; then + %service %{name} stop + /sbin/chkconfig --del %{name} +fi +%systemd_preun %{name}.service + +%postun +if [ "$1" = "0" ]; then + %userremove lighttpd + %groupremove lighttpd + %groupremove http +fi +%systemd_reload + +%posttrans +# minimizing lighttpd restarts logics. we restart webserver: +# +# 1. at the end of transaction. (posttrans, feature from rpm 4.4.2) +# 2. first install of module (post: $1 = 1) +# 2. uninstall of module (postun: $1 = 0) +# +# the strict internal deps between lighttpd modules and +# main package are very important for all this to work. +%service %{name} restart "Lighttpd webserver" +exit 0 + +# macro called at module post scriptlet +%define module_post \ +if [ "$1" = "1" ]; then \ + %service -q lighttpd restart \ +fi + +# macro called at module postun scriptlet +%define module_postun \ +if [ "$1" = "0" ]; then \ + %service -q lighttpd restart \ +fi + +# it's sooo annoying to write them +%define module_scripts() \ +%post %1 \ +%module_post \ +\ +%postun %1 \ +%module_postun + +%module_scripts mod_access +%module_scripts mod_accesslog +%module_scripts mod_alias +%module_scripts mod_auth +%module_scripts mod_cgi +%module_scripts mod_cml +%module_scripts mod_compress +%module_scripts mod_deflate +%module_scripts mod_dirlisting +%module_scripts mod_evasive +%module_scripts mod_evhost +%module_scripts mod_expire +%module_scripts mod_extforward +%module_scripts mod_fastcgi +%module_scripts mod_flv_streaming +%module_scripts mod_h264_streaming +%module_scripts mod_indexfile +%module_scripts mod_magnet +%module_scripts mod_mysql_vhost +%module_scripts mod_proxy +%module_scripts mod_redirect +%module_scripts mod_rewrite + +%post mod_rrdtool +if [ ! -f /var/lib/lighttpd/lighttpd.rrd ]; then + touch /var/lib/lighttpd/lighttpd.rrd + chown lighttpd:stats /var/lib/lighttpd/lighttpd.rrd + chmod 640 /var/lib/lighttpd/lighttpd.rrd +fi +%module_post + +%postun mod_rrdtool +%module_postun + +%module_scripts mod_scgi +%module_scripts mod_secdownload +%module_scripts mod_setenv +%module_scripts mod_simple_vhost +%module_scripts mod_ssi +%module_scripts mod_staticfile +%module_scripts mod_status +%module_scripts mod_trigger_b4_dl +%module_scripts mod_userdir +%module_scripts mod_usertrack +%module_scripts mod_webdav + +%module_scripts php-spawned +%module_scripts php-external + +%triggerpostun -- %{name} < 1.4.18-10.1 +if [ -f /etc/lighttpd/conf.d/50_mod_extforward.conf.rpmsave ]; then + cp -f /etc/lighttpd/conf.d/91_mod_extforward.conf{,.rpmnew} + mv -f /etc/lighttpd/conf.d/{50_mod_extforward.conf.rpmsave,91_mod_extforward.conf} +fi + +%files +%defattr(644,root,root,755) +%doc NEWS README PLD-TODO +%dir %attr(751,root,lighttpd) %{_sysconfdir} +%dir %attr(750,root,root) %{_sysconfdir}/conf.d +%dir %attr(750,root,root) %{_sysconfdir}/vhosts.d +%dir %attr(750,root,root) %{_sysconfdir}/webapps.d +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/%{name}.conf +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/mime.types.conf +%attr(640,root,lighttpd) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/*.user +%config(noreplace) %verify(not md5 mtime size) /etc/init/%{name}.conf + +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/%{name} +%attr(750,root,root) %dir /var/log/archive/%{name} +%dir %attr(751,root,root) /var/log/%{name} +%attr(644,lighttpd,lighttpd) %ghost /var/log/%{name}/access.log +%attr(644,lighttpd,lighttpd) %ghost /var/log/%{name}/error.log +%attr(644,lighttpd,lighttpd) %ghost /var/log/%{name}/breakage.log +%dir %attr(770,root,lighttpd) /var/run/%{name} +%{systemdtmpfilesdir}/%{name}.conf +%{systemdunitdir}/%{name}.service +%attr(754,root,root) /etc/rc.d/init.d/%{name} +%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/* +%attr(755,root,root) %{_sbindir}/lighttpd +%attr(755,root,root) %{_sbindir}/lighttpd-angel +%dir %{_libdir} +%{_mandir}/man8/lighttpd.8* +%dir %{_lighttpddir} +%dir %{_lighttpddir}/cgi-bin +%dir %{_lighttpddir}/html +%config(noreplace,missingok) %verify(not md5 mtime size) %{_lighttpddir}/html/index.html +%config(missingok) %verify(not md5 mtime size) %{_lighttpddir}/html/*.png +%config(missingok) %verify(not md5 mtime size) %{_lighttpddir}/html/*.ico + +%dir %{_datadir}/lighttpd +%dir %{_datadir}/lighttpd/errordocs + +# rrdtool database is stored there +%dir %attr(771,root,lighttpd) /var/lib/lighttpd + +# mod_compress can put cached files there +%dir /var/cache/lighttpd + +%files mod_access +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_access.conf +%attr(755,root,root) %{_libdir}/mod_access.so + +%files mod_accesslog +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_accesslog.conf +%attr(755,root,root) %{_libdir}/mod_accesslog.so + +%files mod_alias +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_alias.conf +%attr(755,root,root) %{_libdir}/mod_alias.so + +%files mod_auth +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_auth.conf +%attr(755,root,root) %{_libdir}/mod_auth.so + +%files mod_cgi +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_cgi.conf +%attr(755,root,root) %{_libdir}/mod_cgi.so + +%files mod_cgi_php +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_cgi_php.conf + +%files mod_cml +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_cml.conf +%attr(755,root,root) %{_libdir}/mod_cml.so + +%files mod_compress +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) /etc/tmpwatch/lighttpd-mod_compress.conf +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_compress.conf +%attr(755,root,root) %{_libdir}/mod_compress.so +%dir %attr(775,root,lighttpd) /var/cache/lighttpd/mod_compress + +%if %{with deflate} +%files mod_deflate +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_deflate.conf +%attr(755,root,root) %{_libdir}/mod_deflate.so +%endif + +%files mod_dirlisting +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_dirlisting.conf +%attr(755,root,root) %{_libdir}/mod_dirlisting.so + +%files mod_evasive +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_evasive.conf +%attr(755,root,root) %{_libdir}/mod_evasive.so + +%files mod_evhost +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_evhost.conf +%attr(755,root,root) %{_libdir}/mod_evhost.so + +%files mod_expire +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_expire.conf +%attr(755,root,root) %{_libdir}/mod_expire.so + +%files mod_extforward +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_extforward.conf +%attr(755,root,root) %{_libdir}/mod_extforward.so + +%files mod_fastcgi +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_fastcgi.conf +%attr(755,root,root) %{_libdir}/mod_fastcgi.so + +%files mod_flv_streaming +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_flv_streaming.conf +%attr(755,root,root) %{_libdir}/mod_flv_streaming.so + +%files mod_h264_streaming +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_h264_streaming.conf +%attr(755,root,root) %{_libdir}/mod_h264_streaming.so + +%files mod_indexfile +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_indexfile.conf +%attr(755,root,root) %{_libdir}/mod_indexfile.so + +%files mod_magnet +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_magnet.conf +%attr(755,root,root) %{_libdir}/mod_magnet.so + +%if %{with mysql} +%files mod_mysql_vhost +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_mysql_vhost.conf +%attr(755,root,root) %{_libdir}/mod_mysql_vhost.so +%endif + +%files mod_proxy +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_proxy.conf +%attr(755,root,root) %{_libdir}/mod_proxy.so + +%files mod_redirect +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_redirect.conf +%attr(755,root,root) %{_libdir}/mod_redirect.so + +%files mod_rewrite +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_rewrite.conf +%attr(755,root,root) %{_libdir}/mod_rewrite.so + +%files mod_rrdtool +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_rrdtool.conf +%attr(755,root,root) %{_libdir}/mod_rrdtool.so +%attr(640,lighttpd,stats) %ghost /var/lib/lighttpd/lighttpd.rrd + +%files mod_scgi +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_scgi.conf +%attr(755,root,root) %{_libdir}/mod_scgi.so + +%files mod_secdownload +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_secdownload.conf +%attr(755,root,root) %{_libdir}/mod_secdownload.so + +%files mod_setenv +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_setenv.conf +%attr(755,root,root) %{_libdir}/mod_setenv.so + +%files mod_simple_vhost +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_simple_vhost.conf +%attr(755,root,root) %{_libdir}/mod_simple_vhost.so + +%files mod_ssi +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_ssi.conf +%attr(755,root,root) %{_libdir}/mod_ssi.so + +%files mod_staticfile +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_staticfile.conf +%attr(755,root,root) %{_libdir}/mod_staticfile.so + +%files mod_status +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_status.conf +%attr(755,root,root) %{_libdir}/mod_status.so + +%files mod_trigger_b4_dl +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_trigger_b4_dl.conf +%attr(755,root,root) %{_libdir}/mod_trigger_b4_dl.so + +%files mod_userdir +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_userdir.conf +%attr(755,root,root) %{_libdir}/mod_userdir.so + +%files mod_usertrack +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_usertrack.conf +%attr(755,root,root) %{_libdir}/mod_usertrack.so + +%files mod_webdav +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/*mod_webdav.conf +%attr(755,root,root) %{_libdir}/mod_webdav.so + +%files php-spawned +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/php-spawned.conf + +%files php-external +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/php-external.conf + +%files ssl +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/conf.d/ssl.conf + +%files -n monit-rc-lighttpd +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) /etc/monit/%{name}.monitrc diff --git a/lighttpd.sysconfig b/lighttpd.sysconfig new file mode 100644 index 0000000..27e071f --- /dev/null +++ b/lighttpd.sysconfig @@ -0,0 +1,15 @@ +# Customized settings for lighttpd + +# Define nice level for lighttpd +#SERVICE_RUN_NICE_LEVEL="+0" + +# Use lighttpd-angel +# Allows graceful restart and crash recovery. +# Off by default but consider enabling +#LIGHT_ANGEL="yes" + +# Give it 4096 fd's. +#SERVICE_LIMITS="$DEFAULT_SERVICE_LIMITS -n 4096" + +# Daemon options, for IPV6 set server.use-ipv6 config variable! +#HTTPD_OPTS="" diff --git a/lighttpd.tmpfiles b/lighttpd.tmpfiles new file mode 100644 index 0000000..3918a40 --- /dev/null +++ b/lighttpd.tmpfiles @@ -0,0 +1 @@ +d /var/run/lighttpd 0770 root lighttpd - diff --git a/lighttpd.upstart b/lighttpd.upstart new file mode 100644 index 0000000..8bb9b70 --- /dev/null +++ b/lighttpd.upstart @@ -0,0 +1,16 @@ +description "Lighttpd Web Server" + +start on pld.network-started +stop on pld.shutdown-started + +respawn + +console output + +env SHELL=/bin/sh + +script + # Source old-style service configuration + [ -f /etc/sysconfig/lighttpd ] && . /etc/sysconfig/lighttpd + exec /usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf $HTTPD_OPTS +end script diff --git a/lighttpd.user b/lighttpd.user new file mode 100644 index 0000000..57a29fc --- /dev/null +++ b/lighttpd.user @@ -0,0 +1 @@ +#dummy:test123 diff --git a/test-port-setup.patch b/test-port-setup.patch new file mode 100644 index 0000000..16c3b5d --- /dev/null +++ b/test-port-setup.patch @@ -0,0 +1,11 @@ +--- lighttpd-1.4.30/tests/LightyTest.pm~ 2010-02-02 01:28:20.000000000 +0200 ++++ lighttpd-1.4.30/tests/LightyTest.pm 2011-12-19 14:37:44.255526606 +0200 +@@ -43,7 +43,7 @@ + $self->{MODULES_PATH} = $self->{BASEDIR}.'/build'; + } + $self->{LIGHTTPD_PATH} = $self->{BINDIR}.'/lighttpd'; +- $self->{PORT} = 2048; ++ $self->{PORT} = $ENV{LIGHTTPD_TEST_PORT} ? int($ENV{LIGHTTPD_TEST_PORT}) : 2048; + + my ($name, $aliases, $addrtype, $net) = gethostbyaddr(inet_aton("127.0.0.1"), AF_INET); +