]> TLD Linux GIT Repositories - packages/lighttpd.git/commitdiff
- from PLD
authorMarcin Krol <hawk@tld-linux.org>
Tue, 7 Apr 2015 18:12:29 +0000 (18:12 +0000)
committerMarcin Krol <hawk@tld-linux.org>
Tue, 7 Apr 2015 18:12:29 +0000 (18:12 +0000)
62 files changed:
TODO [new file with mode: 0644]
branch.sh [new file with mode: 0644]
env-documentroot.patch [new file with mode: 0644]
lighttpd-branch.diff [new file with mode: 0644]
lighttpd-branding.patch [new file with mode: 0644]
lighttpd-mime.types.sh [new file with mode: 0644]
lighttpd-mod_access.conf [new file with mode: 0644]
lighttpd-mod_accesslog.conf [new file with mode: 0644]
lighttpd-mod_alias.conf [new file with mode: 0644]
lighttpd-mod_auth.conf [new file with mode: 0644]
lighttpd-mod_cgi.conf [new file with mode: 0644]
lighttpd-mod_cgi_php.conf [new file with mode: 0644]
lighttpd-mod_cml.conf [new file with mode: 0644]
lighttpd-mod_compress.conf [new file with mode: 0644]
lighttpd-mod_compress.tmpwatch [new file with mode: 0644]
lighttpd-mod_deflate.conf [new file with mode: 0644]
lighttpd-mod_deflate.patch [new file with mode: 0644]
lighttpd-mod_dirlisting.conf [new file with mode: 0644]
lighttpd-mod_evasive-status_code.patch [new file with mode: 0644]
lighttpd-mod_evasive.conf [new file with mode: 0644]
lighttpd-mod_evhost.conf [new file with mode: 0644]
lighttpd-mod_expire.conf [new file with mode: 0644]
lighttpd-mod_extforward.conf [new file with mode: 0644]
lighttpd-mod_fastcgi.conf [new file with mode: 0644]
lighttpd-mod_flv_streaming.conf [new file with mode: 0644]
lighttpd-mod_h264_streaming.conf [new file with mode: 0644]
lighttpd-mod_h264_streaming.patch [new file with mode: 0644]
lighttpd-mod_indexfile.conf [new file with mode: 0644]
lighttpd-mod_magnet.conf [new file with mode: 0644]
lighttpd-mod_mysql_vhost.conf [new file with mode: 0644]
lighttpd-mod_proxy.conf [new file with mode: 0644]
lighttpd-mod_redirect.conf [new file with mode: 0644]
lighttpd-mod_rewrite.conf [new file with mode: 0644]
lighttpd-mod_rrdtool.conf [new file with mode: 0644]
lighttpd-mod_scgi.conf [new file with mode: 0644]
lighttpd-mod_secdownload.conf [new file with mode: 0644]
lighttpd-mod_setenv.conf [new file with mode: 0644]
lighttpd-mod_simple_vhost.conf [new file with mode: 0644]
lighttpd-mod_ssi.conf [new file with mode: 0644]
lighttpd-mod_staticfile.conf [new file with mode: 0644]
lighttpd-mod_status.conf [new file with mode: 0644]
lighttpd-mod_trigger_b4_dl.conf [new file with mode: 0644]
lighttpd-mod_userdir.conf [new file with mode: 0644]
lighttpd-mod_usertrack.conf [new file with mode: 0644]
lighttpd-mod_webdav.conf [new file with mode: 0644]
lighttpd-modinit-before-fork.patch [new file with mode: 0644]
lighttpd-php-external.conf [new file with mode: 0644]
lighttpd-php-spawned.conf [new file with mode: 0644]
lighttpd-pld.html [new file with mode: 0644]
lighttpd-ssl.conf [new file with mode: 0644]
lighttpd-use_bin_sh.patch [new file with mode: 0644]
lighttpd.conf [new file with mode: 0644]
lighttpd.init [new file with mode: 0755]
lighttpd.logrotate [new file with mode: 0644]
lighttpd.monitrc [new file with mode: 0644]
lighttpd.service [new file with mode: 0644]
lighttpd.spec [new file with mode: 0644]
lighttpd.sysconfig [new file with mode: 0644]
lighttpd.tmpfiles [new file with mode: 0644]
lighttpd.upstart [new file with mode: 0644]
lighttpd.user [new file with mode: 0644]
test-port-setup.patch [new file with mode: 0644]

diff --git a/TODO b/TODO
new file mode 100644 (file)
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 (file)
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 (file)
index 0000000..eea738e
--- /dev/null
@@ -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 (file)
index 0000000..76f06ce
--- /dev/null
@@ -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 <string.h>
+-
+-#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 <sys/resource.h>
+ #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 <stdlib.h>
+ #include <string.h>
+-#ifdef USE_OPENSSL
+-# include <openssl/md5.h>
+-#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 <openssl/rand.h>
+ #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 <dirent.h>
+ #include <stdio.h>
+-#ifdef USE_OPENSSL
+-# include <openssl/md5.h>
+-#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 <openssl/ssl.h>
+ # include <openssl/err.h>
+-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 <unistd.h>
+ #include <ctype.h>
+-#ifdef USE_OPENSSL
+-# include <openssl/md5.h>
+-#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 <stdlib.h>
+ #include <string.h>
+-#ifdef USE_OPENSSL
+-# include <openssl/md5.h>
+-#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("</td><td class=\"int\">"));
+-              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 <time.h>
+ #include <string.h>
+-#ifdef USE_OPENSSL
+-# include <openssl/md5.h>
+-#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}  = ( <<EOF
+ GET /server-status HTTP/1.0
++Authorization: Basic \x80mFuOmphb
++EOF
++ );
++$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
++ok($tf->handle_http($t) == 0, 'Basic-Auth: Invalid base64 Auth-token');
++
++$t->{REQUEST}  = ( <<EOF
++GET /server-status HTTP/1.0
+ Authorization: Basic amFuOmphb
+ EOF
+  );
+Index: tests/request.t
+===================================================================
+--- tests/request.t    (.../tags/lighttpd-1.4.29)
++++ tests/request.t    (.../branches/lighttpd-1.4.x)
+@@ -8,7 +8,7 @@
+ use strict;
+ use IO::Socket;
+-use Test::More tests => 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}  = ( <<EOF
++GET /image.jpg/index.php HTTP/1.0
++EOF
++ );
++$t->{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}  = ( <<EOF
++GET /image.jpg/index.php HTTP/1.0
++Host: zzz.example.org
++EOF
++ );
++$t->{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 (file)
index 0000000..9fdf8a5
--- /dev/null
@@ -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 (file)
index 0000000..5252638
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Parse /etc/mime.types into lighttpd config format.
+# Copyright (c) 2005 Elan Ruusamäe <glen@pld-linux.org>
+
+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 <<EOF
+# charset used for "text/*" mimetypes
+# Apache's AddCharset equivalent. Leave empty to add no charset.
+# AddCharset "utf-8" would be "; charset=\"utf-8\""
+# See this post about what it affects:
+# http://lists.pld-linux.org/mailman/pipermail/pld-devel-en/2012-February/022499.html
+mimetype_textcharsetheader = ""
+#mimetype_textcharsetheader = "; charset=\"utf-8\""
+
+# mimetype mapping
+mimetype.assign = (
+EOF
+
+# save our hard work
+cat mime.types.conf.tmp >> mime.types.conf
+
+# footer
+cat >> mime.types.conf <<EOF
+)
+EOF
+
+rm -f mime.types.conf.tmp
diff --git a/lighttpd-mod_access.conf b/lighttpd-mod_access.conf
new file mode 100644 (file)
index 0000000..0cf6c79
--- /dev/null
@@ -0,0 +1,20 @@
+# Access module.
+#
+# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModAccess
+
+server.modules += (
+       "mod_access"
+)
+
+## deny access the file-extensions
+#
+# ~    is for backupfiles from vi, emacs, joe, ...
+# .inc is often used for code includes which should in general not be part
+#      of the document-root
+# *,v and *,t - CVS files
+url.access-deny = ( "~", ".inc", ",v", ",t" )
+
+# forbid access to files inside CVS or RCS dirs
+$HTTP["url"] =~ "/(?:CVS|RCS)/" {
+       url.access-deny = ("")
+}
diff --git a/lighttpd-mod_accesslog.conf b/lighttpd-mod_accesslog.conf
new file mode 100644 (file)
index 0000000..fef3a01
--- /dev/null
@@ -0,0 +1,24 @@
+# accesslog module.
+#
+# Documentation: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModAccessLog
+
+server.modules += (
+       "mod_accesslog"
+)
+
+accesslog.filename = "/var/log/lighttpd/access.log"
+
+# Use syslog
+# accesslog.use-syslog = "enable"
+
+# Lighttpd default
+#accesslog.format = "%h %V %u %t \"%r\" %>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 (file)
index 0000000..b790e29
--- /dev/null
@@ -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 (file)
index 0000000..d8af909
--- /dev/null
@@ -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 (file)
index 0000000..75ed293
--- /dev/null
@@ -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 (file)
index 0000000..32c1147
--- /dev/null
@@ -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 (file)
index 0000000..844a069
--- /dev/null
@@ -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 (file)
index 0000000..7bbd6f1
--- /dev/null
@@ -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 (file)
index 0000000..73c4172
--- /dev/null
@@ -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 (file)
index 0000000..ff5a0c0
--- /dev/null
@@ -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 (file)
index 0000000..fd2f545
--- /dev/null
@@ -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 <errno.h>
+ #include <string.h>
++#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 <sys/types.h>
++#include <sys/stat.h>
++
++#include <fcntl.h>
++#include <unistd.h>
++#include <ctype.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <time.h>
++#include <assert.h>
++
++#if defined(HAVE_PCRE_H)
++#include <pcre.h>
++#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 <zlib.h>
++#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 <bzlib.h>
++#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 (file)
index 0000000..ba9cc52
--- /dev/null
@@ -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 (file)
index 0000000..02cbd9e
--- /dev/null
@@ -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 (file)
index 0000000..8ecb17f
--- /dev/null
@@ -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 (file)
index 0000000..744068a
--- /dev/null
@@ -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 (file)
index 0000000..d8f6daa
--- /dev/null
@@ -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 (file)
index 0000000..5ad8a90
--- /dev/null
@@ -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 (file)
index 0000000..fabe29a
--- /dev/null
@@ -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 (file)
index 0000000..898654c
--- /dev/null
@@ -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 (file)
index 0000000..1e137ca
--- /dev/null
@@ -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 (file)
index 0000000..e9430b6
--- /dev/null
@@ -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 <ctype.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++
++#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 <stdlib.h>
++#include <crtdbg.h>
++#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 <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <limits.h>
++#include <stdint.h>
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#ifdef HAVE_STDINT_H
++# include <stdint.h>
++#endif
++#ifdef HAVE_INTTYPES_H
++# include <inttypes.h>
++#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 <zlib.h>
++#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 <inttypes.h>
++#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 (file)
index 0000000..61d7477
--- /dev/null
@@ -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 (file)
index 0000000..3df693f
--- /dev/null
@@ -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 (file)
index 0000000..b54b090
--- /dev/null
@@ -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 (file)
index 0000000..db61021
--- /dev/null
@@ -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 (file)
index 0000000..d511b63
--- /dev/null
@@ -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 (file)
index 0000000..0c9fe5a
--- /dev/null
@@ -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 (file)
index 0000000..0db0f77
--- /dev/null
@@ -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 (file)
index 0000000..1558dab
--- /dev/null
@@ -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 (file)
index 0000000..c916f1d
--- /dev/null
@@ -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 (file)
index 0000000..68763d9
--- /dev/null
@@ -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 (file)
index 0000000..5ffb73e
--- /dev/null
@@ -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 (file)
index 0000000..21a40d7
--- /dev/null
@@ -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 (file)
index 0000000..c20d661
--- /dev/null
@@ -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 (file)
index 0000000..e388e9d
--- /dev/null
@@ -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 (file)
index 0000000..1b63371
--- /dev/null
@@ -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 <download-url>
+#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 <timeout> 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 (file)
index 0000000..bc0e418
--- /dev/null
@@ -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 (file)
index 0000000..eb1aba4
--- /dev/null
@@ -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 (file)
index 0000000..86bc602
--- /dev/null
@@ -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 (file)
index 0000000..2f2c5e5
--- /dev/null
@@ -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 (file)
index 0000000..73741aa
--- /dev/null
@@ -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 (file)
index 0000000..b9869ae
--- /dev/null
@@ -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 (file)
index 0000000..1ff430b
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<!-- $Id$ -->
+<head>
+  <title>Powered by lighttpd</title>
+  <link rel="shortcut icon" href="favicon.ico" />
+  <link rel="icon" href="favicon.ico" />
+  <style type="text/css">
+    <!--
+      body {background: white; color: #666f85; text-align: center}
+      img  {border: none}
+    -->
+  </style>
+</head>
+<body>
+
+<p>
+<img src="light_logo.png" width="249" height="239" alt="LIGHTTPD - fly light." />
+</p>
+
+<p>
+<a href="http://www.lighttpd.net/"><img src="light_button.png" width="80" height="27" alt="Powered by Lighttpd" /></a><br/>
+<a href="http://www.pld-linux.org/"><img src="pld_button.png" width="80" height="15" alt="Powered by PLD Linux" /></a>
+</p>
+
+</body>
+</html>
diff --git a/lighttpd-ssl.conf b/lighttpd-ssl.conf
new file mode 100644 (file)
index 0000000..7e89b24
--- /dev/null
@@ -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 (file)
index 0000000..de08dd3
--- /dev/null
@@ -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 (file)
index 0000000..75079f7
--- /dev/null
@@ -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: <errorfile-prefix><status-code>.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 <uid> (default: don't care)
+server.username  = "lighttpd"
+
+## change uid to <uid> (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 (executable)
index 0000000..aaf4d5f
--- /dev/null
@@ -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 (file)
index 0000000..3d5dc28
--- /dev/null
@@ -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 (file)
index 0000000..516dcb9
--- /dev/null
@@ -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 (file)
index 0000000..6f4dce9
--- /dev/null
@@ -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 (file)
index 0000000..c2c4894
--- /dev/null
@@ -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 (file)
index 0000000..27e071f
--- /dev/null
@@ -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 (file)
index 0000000..3918a40
--- /dev/null
@@ -0,0 +1 @@
+d /var/run/lighttpd 0770 root lighttpd -
diff --git a/lighttpd.upstart b/lighttpd.upstart
new file mode 100644 (file)
index 0000000..8bb9b70
--- /dev/null
@@ -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 (file)
index 0000000..57a29fc
--- /dev/null
@@ -0,0 +1 @@
+#dummy:test123
diff --git a/test-port-setup.patch b/test-port-setup.patch
new file mode 100644 (file)
index 0000000..16c3b5d
--- /dev/null
@@ -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);