aboutsummaryrefslogtreecommitdiffstats
path: root/main/lighttpd
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2015-07-07 14:20:33 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2015-07-07 14:20:33 +0000
commitc1ee7a6e6d21447788c7512e7197d49ebfbc3096 (patch)
treef6dbf52c47e29ab57edc25ed499f7c6f4745ef75 /main/lighttpd
parent77345a923c72d9e8d0a4202d893239ba43b903a3 (diff)
downloadaports-c1ee7a6e6d21447788c7512e7197d49ebfbc3096.tar.bz2
aports-c1ee7a6e6d21447788c7512e7197d49ebfbc3096.tar.xz
main/lighttpd: security fix for CVE-2015-3200
The upstream patch does not apply without applying lot other stuff so we simply apply all since 1.4.35 release. ref #4329
Diffstat (limited to 'main/lighttpd')
-rw-r--r--main/lighttpd/0001-next-is-1.4.36.patch72
-rw-r--r--main/lighttpd/0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch72
-rw-r--r--main/lighttpd/0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch61
-rw-r--r--main/lighttpd/0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch857
-rw-r--r--main/lighttpd/0005-fix-typo-in-NEWS-entry-for-2579.patch31
-rw-r--r--main/lighttpd/0006-add-support-for-Free-BSD-extended-attributes.patch175
-rw-r--r--main/lighttpd/0007-build-use-fortify-flags-with-extra-warnings.patch88
-rw-r--r--main/lighttpd/0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch163
-rw-r--r--main/lighttpd/0009-ssl-disable-SSL3.0-by-default.patch44
-rw-r--r--main/lighttpd/0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch38
-rw-r--r--main/lighttpd/0011-add-NEWS-entry-for-previous-commit.patch30
-rw-r--r--main/lighttpd/0012-network-fix-compile-break-in-calculation-of-sockaddr.patch66
-rw-r--r--main/lighttpd/0013-connections-fix-bug-in-connection-state-handling.patch69
-rw-r--r--main/lighttpd/0014-print-backtrace-in-assert-logging-with-libunwind.patch187
-rw-r--r--main/lighttpd/0015-fix-buffer-chunk-and-http_chunk-API.patch6095
-rw-r--r--main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch1537
-rw-r--r--main/lighttpd/0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch1182
-rw-r--r--main/lighttpd/0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch79
-rw-r--r--main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch4346
-rw-r--r--main/lighttpd/0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch117
-rw-r--r--main/lighttpd/0021-buffer-constify-some-parameters.patch98
-rw-r--r--main/lighttpd/0022-bitset-unused-remove.patch170
-rw-r--r--main/lighttpd/0023-remove-unused-stuff-from-server.h.patch38
-rw-r--r--main/lighttpd/0024-crc32-fix-method-signature-const-pointer.patch44
-rw-r--r--main/lighttpd/0025-tests-fix-undefined-index-warning-in-sendfile.php.patch31
-rw-r--r--main/lighttpd/0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch102
-rw-r--r--main/lighttpd/0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch49
-rw-r--r--main/lighttpd/0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch447
-rw-r--r--main/lighttpd/0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch174
-rw-r--r--main/lighttpd/APKBUILD119
30 files changed, 16580 insertions, 1 deletions
diff --git a/main/lighttpd/0001-next-is-1.4.36.patch b/main/lighttpd/0001-next-is-1.4.36.patch
new file mode 100644
index 0000000000..88512bbf3e
--- /dev/null
+++ b/main/lighttpd/0001-next-is-1.4.36.patch
@@ -0,0 +1,72 @@
+From e1b1c52028b446fdef837d26341dd1431780e0f6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Wed, 2 Apr 2014 10:04:09 +0000
+Subject: [PATCH 01/29] - next is 1.4.36
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2961 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ CMakeLists.txt | 2 +-
+ NEWS | 7 +++++--
+ SConstruct | 2 +-
+ configure.ac | 2 +-
+ 4 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 9f4c04a..b9bd48f 100644
+--- a/NEWS
++++ b/NEWS
+@@ -3,7 +3,10 @@
+ NEWS
+ ====
+
+-- 1.4.35
++- 1.4.36
++ *
++
++- 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+ * [mod_fastcgi] fix use after free (only triggered if fastcgi debug is active)
+ * [mod_rrdtool] fix invalid read (string not null terminated)
+@@ -23,7 +26,7 @@ NEWS
+ * check length of unix domain socket filenames
+ * fix SQL injection / host name validation (thx Jann Horn)
+
+-- 1.4.34
++- 1.4.34 - 2014-01-20
+ * [mod_auth] explicitly link ssl for SHA1 (fixes #2517)
+ * [mod_extforward] fix compilation without IPv6, (not) using undefined var (fixes #2515, thx mm)
+ * [ssl] fix SNI handling; only use key+cert from SNI specific config (fixes #2525, CVE-2013-4508)
+diff --git a/SConstruct b/SConstruct
+index cb2a58f..d8bd98a 100644
+--- a/SConstruct
++++ b/SConstruct
+@@ -5,7 +5,7 @@ import string
+ from stat import *
+
+ package = 'lighttpd'
+-version = '1.4.35'
++version = '1.4.36'
+
+ def checkCHeaders(autoconf, hdrs):
+ p = re.compile('[^A-Z0-9]')
+diff --git a/configure.ac b/configure.ac
+index 682023b..ae35234 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,7 +1,7 @@
+ dnl -*- Autoconf -*-
+ dnl Process this file with autoconf to produce a configure script.
+ AC_PREREQ(2.57)
+-AC_INIT([lighttpd], [1.4.35], [contact@lighttpd.net])
++AC_INIT([lighttpd], [1.4.36], [contact@lighttpd.net])
+ AC_CONFIG_SRCDIR([src/server.c])
+ AC_CONFIG_HEADER([config.h])
+ AC_CONFIG_MACRO_DIR([m4])
+--
+2.4.5
+
diff --git a/main/lighttpd/0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch b/main/lighttpd/0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch
new file mode 100644
index 0000000000..13774eb4e6
--- /dev/null
+++ b/main/lighttpd/0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch
@@ -0,0 +1,72 @@
+From 3605a3bec31f5e1bc79fdfb830b84e188f060982 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Wed, 2 Apr 2014 10:04:11 +0000
+Subject: [PATCH 02/29] use keep-alive timeout while waiting for HTTP headers;
+ use always the read timeout while waiting for the HTTP body
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2962 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 2 +-
+ src/server.c | 20 +++++++++++---------
+ 2 files changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index b9bd48f..e82b90b 100644
+--- a/NEWS
++++ b/NEWS
+@@ -4,7 +4,7 @@ NEWS
+ ====
+
+ - 1.4.36
+- *
++ * use keep-alive timeout while waiting for HTTP headers; use always the read timeout while waiting for the HTTP body
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/server.c b/src/server.c
+index 5691921..d47fd62 100644
+--- a/src/server.c
++++ b/src/server.c
+@@ -1296,23 +1296,25 @@ int main (int argc, char **argv) {
+
+ if (con->state == CON_STATE_READ ||
+ con->state == CON_STATE_READ_POST) {
+- if (con->request_count == 1) {
++ if (con->request_count == 1 || con->state == CON_STATE_READ_POST) {
+ if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
+ /* time - out */
+-#if 0
+- log_error_write(srv, __FILE__, __LINE__, "sd",
+- "connection closed - read-timeout:", con->fd);
+-#endif
++ if (con->conf.log_request_handling) {
++ log_error_write(srv, __FILE__, __LINE__, "sd",
++ "connection closed - read timeout:", con->fd);
++ }
++
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ changed = 1;
+ }
+ } else {
+ if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) {
+ /* time - out */
+-#if 0
+- log_error_write(srv, __FILE__, __LINE__, "sd",
+- "connection closed - read-timeout:", con->fd);
+-#endif
++ if (con->conf.log_request_handling) {
++ log_error_write(srv, __FILE__, __LINE__, "sd",
++ "connection closed - keep-alive timeout:", con->fd);
++ }
++
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ changed = 1;
+ }
+--
+2.4.5
+
diff --git a/main/lighttpd/0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch b/main/lighttpd/0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch
new file mode 100644
index 0000000000..0a3b51f342
--- /dev/null
+++ b/main/lighttpd/0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch
@@ -0,0 +1,61 @@
+From f8f335150675ed8f5d1cf3edadf74f7f6685f606 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Mon, 14 Apr 2014 16:12:11 +0000
+Subject: [PATCH 03/29] fix bad shift in conditional netmask ".../0" handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+config conditionals like $HTTP["remoteip"] == "a.b.c.d/0" (or completely
+broken netmasks) triggered bad shifts. Matching against "/0" is not very
+useful though - it is always true.
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2963 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/configfile-glue.c | 8 +++++++-
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/NEWS b/NEWS
+index e82b90b..780f4c6 100644
+--- a/NEWS
++++ b/NEWS
+@@ -5,6 +5,7 @@ NEWS
+
+ - 1.4.36
+ * use keep-alive timeout while waiting for HTTP headers; use always the read timeout while waiting for the HTTP body
++ * fix bad shift in conditional netmask ".../0" handling
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/configfile-glue.c b/src/configfile-glue.c
+index 3efa46a..9f24dcb 100644
+--- a/src/configfile-glue.c
++++ b/src/configfile-glue.c
+@@ -357,6 +357,12 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
+ return COND_RESULT_FALSE;
+ }
+
++ if (nm_bits > 32 || nm_bits < 0) {
++ log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask:", dc->string, err);
++
++ return COND_RESULT_FALSE;
++ }
++
+ /* take IP convert to the native */
+ buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
+ #ifdef __WIN32
+@@ -375,7 +381,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
+ #endif
+
+ /* build netmask */
+- nm = htonl(~((1 << (32 - nm_bits)) - 1));
++ nm = nm_bits ? htonl(~((1 << (32 - nm_bits)) - 1)) : 0;
+
+ if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
+ return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
+--
+2.4.5
+
diff --git a/main/lighttpd/0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch b/main/lighttpd/0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch
new file mode 100644
index 0000000000..7803f68370
--- /dev/null
+++ b/main/lighttpd/0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch
@@ -0,0 +1,857 @@
+From 3b23130ea2c1dff470da0970ee8a75c7dafc90fe Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Tue, 13 May 2014 10:34:46 +0000
+Subject: [PATCH 04/29] add more mime types and a script to generate mime.conf
+ (fxies #2579)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2964 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ doc/config/conf.d/mime.conf | 603 +++++++++++++++++++++++++++++++++++-----
+ doc/scripts/create-mime.conf.pl | 197 +++++++++++++
+ 3 files changed, 735 insertions(+), 66 deletions(-)
+ create mode 100755 doc/scripts/create-mime.conf.pl
+
+diff --git a/NEWS b/NEWS
+index 780f4c6..8c34545 100644
+--- a/NEWS
++++ b/NEWS
+@@ -6,6 +6,7 @@ NEWS
+ - 1.4.36
+ * use keep-alive timeout while waiting for HTTP headers; use always the read timeout while waiting for the HTTP body
+ * fix bad shift in conditional netmask ".../0" handling
++ * add more mime types and a script to generate mime.conf (fxies #2579)
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/doc/config/conf.d/mime.conf b/doc/config/conf.d/mime.conf
+index 8cfdfe7..f65a02c 100644
+--- a/doc/config/conf.d/mime.conf
++++ b/doc/config/conf.d/mime.conf
+@@ -1,78 +1,549 @@
++# created by create-mime.conf.pl
++
+ #######################################################################
+ ##
+ ## MimeType handling
+ ## -------------------
+ ##
+-## http://www.lighttpd.net/documentation/configuration.html#mimetypes
++## https://redmine.lighttpd.net/projects/lighttpd/wiki/Mimetype_assignDetails
++
+ ##
+-## Use the "Content-Type" extended attribute to obtain mime type if
++## Use the "Content-Type" extended file attribute to obtain mime type if
+ ## possible
+ ##
+-mimetype.use-xattr = "disable"
++## Disabled by default
++##
++#mimetype.use-xattr = "enable"
+
+ ##
+-## mimetype mapping
++## mimetype ("Content-Type" HTTP header) mapping for static file handling
+ ##
+-mimetype.assign = (
+- ".pdf" => "application/pdf",
+- ".sig" => "application/pgp-signature",
+- ".spl" => "application/futuresplash",
+- ".class" => "application/octet-stream",
+- ".ps" => "application/postscript",
+- ".torrent" => "application/x-bittorrent",
+- ".dvi" => "application/x-dvi",
+- ".gz" => "application/x-gzip",
+- ".pac" => "application/x-ns-proxy-autoconfig",
+- ".swf" => "application/x-shockwave-flash",
+- ".tar.gz" => "application/x-tgz",
+- ".tgz" => "application/x-tgz",
+- ".tar" => "application/x-tar",
+- ".zip" => "application/zip",
+- ".mp3" => "audio/mpeg",
+- ".m3u" => "audio/x-mpegurl",
+- ".wma" => "audio/x-ms-wma",
+- ".wax" => "audio/x-ms-wax",
+- ".ogg" => "application/ogg",
+- ".wav" => "audio/x-wav",
+- ".gif" => "image/gif",
+- ".jpg" => "image/jpeg",
+- ".jpeg" => "image/jpeg",
+- ".png" => "image/png",
+- ".xbm" => "image/x-xbitmap",
+- ".xpm" => "image/x-xpixmap",
+- ".xwd" => "image/x-xwindowdump",
+- ".css" => "text/css",
+- ".html" => "text/html",
+- ".htm" => "text/html",
+- ".js" => "text/javascript",
+- ".asc" => "text/plain",
+- ".c" => "text/plain",
+- ".cpp" => "text/plain",
+- ".log" => "text/plain",
+- ".conf" => "text/plain",
+- ".text" => "text/plain",
+- ".txt" => "text/plain",
+- ".spec" => "text/plain",
+- ".dtd" => "text/xml",
+- ".xml" => "text/xml",
+- ".mpeg" => "video/mpeg",
+- ".mpg" => "video/mpeg",
+- ".mov" => "video/quicktime",
+- ".qt" => "video/quicktime",
+- ".avi" => "video/x-msvideo",
+- ".asf" => "video/x-ms-asf",
+- ".asx" => "video/x-ms-asf",
+- ".wmv" => "video/x-ms-wmv",
+- ".bz2" => "application/x-bzip",
+- ".tbz" => "application/x-bzip-compressed-tar",
+- ".tar.bz2" => "application/x-bzip-compressed-tar",
+- ".rpm" => "application/x-rpm",
+- ".json" => "application/json",
+- # make the default mime type application/octet-stream.
+- "" => "application/octet-stream",
+- )
+-
+-
+-#
+-#######################################################################
++## The first matching suffix is used. If no mapping is found
++## 'application/octet-stream' is used, and caching (etag/last-modified handling)
++## is disabled to prevent clients from caching "unknown" mime types.
++##
++## Therefore the last mapping is:
++## "" => "application/octet-stream"
++## This matches all extensions and acts as default mime type, and enables
++## caching for those.
++mimetype.assign = (
++ ".tar.bz2" => "application/x-gtar-compressed",
++ ".tar.gz" => "application/x-gtar-compressed",
++ ".ez" => "application/andrew-inset",
++ ".anx" => "application/annodex",
++ ".atom" => "application/atom+xml",
++ ".atomcat" => "application/atomcat+xml",
++ ".atomsrv" => "application/atomserv+xml",
++ ".lin" => "application/bbolin",
++ ".cu" => "application/cu-seeme",
++ ".davmount" => "application/davmount+xml",
++ ".dcm" => "application/dicom",
++ ".tsp" => "application/dsptype",
++ ".es" => "application/ecmascript",
++ ".spl" => "application/futuresplash",
++ ".hta" => "application/hta",
++ ".jar" => "application/java-archive",
++ ".ser" => "application/java-serialized-object",
++ ".class" => "application/java-vm",
++ ".js" => "application/javascript",
++ ".json" => "application/json",
++ ".m3g" => "application/m3g",
++ ".hqx" => "application/mac-binhex40",
++ ".cpt" => "application/mac-compactpro",
++ ".nb" => "application/mathematica",
++ ".nbp" => "application/mathematica",
++ ".mbox" => "application/mbox",
++ ".mdb" => "application/msaccess",
++ ".doc" => "application/msword",
++ ".dot" => "application/msword",
++ ".mxf" => "application/mxf",
++ ".asn" => "application/octet-stream",
++ ".bin" => "application/octet-stream",
++ ".ent" => "application/octet-stream",
++ ".oda" => "application/oda",
++ ".ogx" => "application/ogg",
++ ".one" => "application/onenote",
++ ".onepkg" => "application/onenote",
++ ".onetmp" => "application/onenote",
++ ".onetoc2" => "application/onenote",
++ ".pdf" => "application/pdf",
++ ".pgp" => "application/pgp-encrypted",
++ ".key" => "application/pgp-keys",
++ ".sig" => "application/pgp-signature",
++ ".prf" => "application/pics-rules",
++ ".ai" => "application/postscript",
++ ".eps" => "application/postscript",
++ ".eps2" => "application/postscript",
++ ".eps3" => "application/postscript",
++ ".epsf" => "application/postscript",
++ ".epsi" => "application/postscript",
++ ".ps" => "application/postscript",
++ ".rar" => "application/rar",
++ ".rdf" => "application/rdf+xml",
++ ".rtf" => "application/rtf",
++ ".stl" => "application/sla",
++ ".smi" => "application/smil+xml",
++ ".smil" => "application/smil+xml",
++ ".xht" => "application/xhtml+xml",
++ ".xhtml" => "application/xhtml+xml",
++ ".xml" => "application/xml",
++ ".xsd" => "application/xml",
++ ".dtd" => "application/xml-dtd",
++ ".xsl" => "application/xslt+xml",
++ ".xslt" => "application/xslt+xml",
++ ".xspf" => "application/xspf+xml",
++ ".zip" => "application/zip",
++ ".apk" => "application/vnd.android.package-archive",
++ ".cdy" => "application/vnd.cinderella",
++ ".kml" => "application/vnd.google-earth.kml+xml",
++ ".kmz" => "application/vnd.google-earth.kmz",
++ ".xul" => "application/vnd.mozilla.xul+xml",
++ ".xlb" => "application/vnd.ms-excel",
++ ".xls" => "application/vnd.ms-excel",
++ ".xlt" => "application/vnd.ms-excel",
++ ".eot" => "application/vnd.ms-fontobject",
++ ".thmx" => "application/vnd.ms-officetheme",
++ ".cat" => "application/vnd.ms-pki.seccat",
++ ".pps" => "application/vnd.ms-powerpoint",
++ ".ppt" => "application/vnd.ms-powerpoint",
++ ".odc" => "application/vnd.oasis.opendocument.chart",
++ ".odb" => "application/vnd.oasis.opendocument.database",
++ ".odf" => "application/vnd.oasis.opendocument.formula",
++ ".odg" => "application/vnd.oasis.opendocument.graphics",
++ ".otg" => "application/vnd.oasis.opendocument.graphics-template",
++ ".odi" => "application/vnd.oasis.opendocument.image",
++ ".odp" => "application/vnd.oasis.opendocument.presentation",
++ ".otp" => "application/vnd.oasis.opendocument.presentation-template",
++ ".ods" => "application/vnd.oasis.opendocument.spreadsheet",
++ ".ots" => "application/vnd.oasis.opendocument.spreadsheet-template",
++ ".odt" => "application/vnd.oasis.opendocument.text",
++ ".odm" => "application/vnd.oasis.opendocument.text-master",
++ ".ott" => "application/vnd.oasis.opendocument.text-template",
++ ".oth" => "application/vnd.oasis.opendocument.text-web",
++ ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
++ ".sldx" => "application/vnd.openxmlformats-officedocument.presentationml.slide",
++ ".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
++ ".potx" => "application/vnd.openxmlformats-officedocument.presentationml.template",
++ ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
++ ".xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
++ ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
++ ".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
++ ".cod" => "application/vnd.rim.cod",
++ ".mmf" => "application/vnd.smaf",
++ ".sdc" => "application/vnd.stardivision.calc",
++ ".sds" => "application/vnd.stardivision.chart",
++ ".sda" => "application/vnd.stardivision.draw",
++ ".sdd" => "application/vnd.stardivision.impress",
++ ".sdf" => "application/vnd.stardivision.math",
++ ".sdw" => "application/vnd.stardivision.writer",
++ ".sgl" => "application/vnd.stardivision.writer-global",
++ ".sxc" => "application/vnd.sun.xml.calc",
++ ".stc" => "application/vnd.sun.xml.calc.template",
++ ".sxd" => "application/vnd.sun.xml.draw",
++ ".std" => "application/vnd.sun.xml.draw.template",
++ ".sxi" => "application/vnd.sun.xml.impress",
++ ".sti" => "application/vnd.sun.xml.impress.template",
++ ".sxm" => "application/vnd.sun.xml.math",
++ ".sxw" => "application/vnd.sun.xml.writer",
++ ".sxg" => "application/vnd.sun.xml.writer.global",
++ ".stw" => "application/vnd.sun.xml.writer.template",
++ ".sis" => "application/vnd.symbian.install",
++ ".cap" => "application/vnd.tcpdump.pcap",
++ ".pcap" => "application/vnd.tcpdump.pcap",
++ ".vsd" => "application/vnd.visio",
++ ".wbxml" => "application/vnd.wap.wbxml",
++ ".wmlc" => "application/vnd.wap.wmlc",
++ ".wmlsc" => "application/vnd.wap.wmlscriptc",
++ ".wpd" => "application/vnd.wordperfect",
++ ".wp5" => "application/vnd.wordperfect5.1",
++ ".wk" => "application/x-123",
++ ".7z" => "application/x-7z-compressed",
++ ".abw" => "application/x-abiword",
++ ".dmg" => "application/x-apple-diskimage",
++ ".bcpio" => "application/x-bcpio",
++ ".torrent" => "application/x-bittorrent",
++ ".bz2" => "application/x-bzip",
++ ".cab" => "application/x-cab",
++ ".cbr" => "application/x-cbr",
++ ".cbz" => "application/x-cbz",
++ ".cda" => "application/x-cdf",
++ ".cdf" => "application/x-cdf",
++ ".vcd" => "application/x-cdlink",
++ ".pgn" => "application/x-chess-pgn",
++ ".mph" => "application/x-comsol",
++ ".cpio" => "application/x-cpio",
++ ".deb" => "application/x-debian-package",
++ ".udeb" => "application/x-debian-package",
++ ".dcr" => "application/x-director",
++ ".dir" => "application/x-director",
++ ".dxr" => "application/x-director",
++ ".dms" => "application/x-dms",
++ ".wad" => "application/x-doom",
++ ".dvi" => "application/x-dvi",
++ ".woff" => "application/x-font-woff",
++ ".mm" => "application/x-freemind",
++ ".gan" => "application/x-ganttproject",
++ ".gnumeric" => "application/x-gnumeric",
++ ".sgf" => "application/x-go-sgf",
++ ".gcf" => "application/x-graphing-calculator",
++ ".gtar" => "application/x-gtar",
++ ".taz" => "application/x-gtar-compressed",
++ ".tbz" => "application/x-gtar-compressed",
++ ".tgz" => "application/x-gtar-compressed",
++ ".gz" => "application/x-gzip",
++ ".hdf" => "application/x-hdf",
++ ".hwp" => "application/x-hwp",
++ ".ica" => "application/x-ica",
++ ".info" => "application/x-info",
++ ".ins" => "application/x-internet-signup",
++ ".isp" => "application/x-internet-signup",
++ ".iii" => "application/x-iphone",
++ ".iso" => "application/x-iso9660-image",
++ ".jam" => "application/x-jam",
++ ".jnlp" => "application/x-java-jnlp-file",
++ ".jmz" => "application/x-jmol",
++ ".chrt" => "application/x-kchart",
++ ".kil" => "application/x-killustrator",
++ ".skd" => "application/x-koan",
++ ".skm" => "application/x-koan",
++ ".skp" => "application/x-koan",
++ ".skt" => "application/x-koan",
++ ".kpr" => "application/x-kpresenter",
++ ".kpt" => "application/x-kpresenter",
++ ".ksp" => "application/x-kspread",
++ ".kwd" => "application/x-kword",
++ ".kwt" => "application/x-kword",
++ ".latex" => "application/x-latex",
++ ".lha" => "application/x-lha",
++ ".lyx" => "application/x-lyx",
++ ".lzh" => "application/x-lzh",
++ ".lzx" => "application/x-lzx",
++ ".book" => "application/x-maker",
++ ".fb" => "application/x-maker",
++ ".fbdoc" => "application/x-maker",
++ ".fm" => "application/x-maker",
++ ".frame" => "application/x-maker",
++ ".frm" => "application/x-maker",
++ ".maker" => "application/x-maker",
++ ".md5" => "application/x-md5",
++ ".mif" => "application/x-mif",
++ ".wmd" => "application/x-ms-wmd",
++ ".wmz" => "application/x-ms-wmz",
++ ".bat" => "application/x-msdos-program",
++ ".com" => "application/x-msdos-program",
++ ".dll" => "application/x-msdos-program",
++ ".exe" => "application/x-msdos-program",
++ ".msi" => "application/x-msi",
++ ".nc" => "application/x-netcdf",
++ ".dat" => "application/x-ns-proxy-autoconfig",
++ ".pac" => "application/x-ns-proxy-autoconfig",
++ ".nwc" => "application/x-nwc",
++ ".o" => "application/x-object",
++ ".oza" => "application/x-oz-application",
++ ".p7r" => "application/x-pkcs7-certreqresp",
++ ".crl" => "application/x-pkcs7-crl",
++ ".pyc" => "application/x-python-code",
++ ".pyo" => "application/x-python-code",
++ ".qgs" => "application/x-qgis",
++ ".shp" => "application/x-qgis",
++ ".shx" => "application/x-qgis",
++ ".qtl" => "application/x-quicktimeplayer",
++ ".rdp" => "application/x-rdp",
++ ".rpm" => "application/x-redhat-package-manager",
++ ".rss" => "application/x-rss+xml",
++ ".rb" => "application/x-ruby",
++ ".sce" => "application/x-scilab",
++ ".sci" => "application/x-scilab",
++ ".xcos" => "application/x-scilab-xcos",
++ ".sha1" => "application/x-sha1",
++ ".shar" => "application/x-shar",
++ ".swf" => "application/x-shockwave-flash",
++ ".swfl" => "application/x-shockwave-flash",
++ ".scr" => "application/x-silverlight",
++ ".sql" => "application/x-sql",
++ ".sit" => "application/x-stuffit",
++ ".sitx" => "application/x-stuffit",
++ ".sv4cpio" => "application/x-sv4cpio",
++ ".sv4crc" => "application/x-sv4crc",
++ ".tar" => "application/x-tar",
++ ".gf" => "application/x-tex-gf",
++ ".pk" => "application/x-tex-pk",
++ ".texi" => "application/x-texinfo",
++ ".texinfo" => "application/x-texinfo",
++ ".roff" => "application/x-troff",
++ ".t" => "application/x-troff",
++ ".tr" => "application/x-troff",
++ ".man" => "application/x-troff-man",
++ ".me" => "application/x-troff-me",
++ ".ms" => "application/x-troff-ms",
++ ".ustar" => "application/x-ustar",
++ ".src" => "application/x-wais-source",
++ ".wz" => "application/x-wingz",
++ ".crt" => "application/x-x509-ca-cert",
++ ".xcf" => "application/x-xcf",
++ ".fig" => "application/x-xfig",
++ ".xpi" => "application/x-xpinstall",
++ ".amr" => "audio/amr",
++ ".awb" => "audio/amr-wb",
++ ".axa" => "audio/annodex",
++ ".au" => "audio/basic",
++ ".snd" => "audio/basic",
++ ".csd" => "audio/csound",
++ ".orc" => "audio/csound",
++ ".sco" => "audio/csound",
++ ".flac" => "audio/flac",
++ ".kar" => "audio/midi",
++ ".mid" => "audio/midi",
++ ".midi" => "audio/midi",
++ ".m4a" => "audio/mpeg",
++ ".mp2" => "audio/mpeg",
++ ".mp3" => "audio/mpeg",
++ ".mpega" => "audio/mpeg",
++ ".mpga" => "audio/mpeg",
++ ".m3u" => "audio/mpegurl",
++ ".oga" => "audio/ogg",
++ ".ogg" => "audio/ogg",
++ ".opus" => "audio/ogg",
++ ".spx" => "audio/ogg",
++ ".sid" => "audio/prs.sid",
++ ".aif" => "audio/x-aiff",
++ ".aifc" => "audio/x-aiff",
++ ".aiff" => "audio/x-aiff",
++ ".gsm" => "audio/x-gsm",
++ ".wax" => "audio/x-ms-wax",
++ ".wma" => "audio/x-ms-wma",
++ ".ra" => "audio/x-realaudio",
++ ".ram" => "audio/x-realaudio",
++ ".rm" => "audio/x-realaudio",
++ ".pls" => "audio/x-scpls",
++ ".sd2" => "audio/x-sd2",
++ ".wav" => "audio/x-wav",
++ ".alc" => "chemical/x-alchemy",
++ ".cac" => "chemical/x-cache",
++ ".cache" => "chemical/x-cache",
++ ".csf" => "chemical/x-cache-csf",
++ ".cascii" => "chemical/x-cactvs-binary",
++ ".cbin" => "chemical/x-cactvs-binary",
++ ".ctab" => "chemical/x-cactvs-binary",
++ ".cdx" => "chemical/x-cdx",
++ ".cer" => "chemical/x-cerius",
++ ".c3d" => "chemical/x-chem3d",
++ ".chm" => "chemical/x-chemdraw",
++ ".cif" => "chemical/x-cif",
++ ".cmdf" => "chemical/x-cmdf",
++ ".cml" => "chemical/x-cml",
++ ".cpa" => "chemical/x-compass",
++ ".bsd" => "chemical/x-crossfire",
++ ".csm" => "chemical/x-csml",
++ ".csml" => "chemical/x-csml",
++ ".ctx" => "chemical/x-ctx",
++ ".cef" => "chemical/x-cxf",
++ ".cxf" => "chemical/x-cxf",
++ ".emb" => "chemical/x-embl-dl-nucleotide",
++ ".embl" => "chemical/x-embl-dl-nucleotide",
++ ".spc" => "chemical/x-galactic-spc",
++ ".gam" => "chemical/x-gamess-input",
++ ".gamin" => "chemical/x-gamess-input",
++ ".inp" => "chemical/x-gamess-input",
++ ".fch" => "chemical/x-gaussian-checkpoint",
++ ".fchk" => "chemical/x-gaussian-checkpoint",
++ ".cub" => "chemical/x-gaussian-cube",
++ ".gau" => "chemical/x-gaussian-input",
++ ".gjc" => "chemical/x-gaussian-input",
++ ".gjf" => "chemical/x-gaussian-input",
++ ".gal" => "chemical/x-gaussian-log",
++ ".gcg" => "chemical/x-gcg8-sequence",
++ ".gen" => "chemical/x-genbank",
++ ".hin" => "chemical/x-hin",
++ ".ist" => "chemical/x-isostar",
++ ".istr" => "chemical/x-isostar",
++ ".dx" => "chemical/x-jcamp-dx",
++ ".jdx" => "chemical/x-jcamp-dx",
++ ".kin" => "chemical/x-kinemage",
++ ".mcm" => "chemical/x-macmolecule",
++ ".mmd" => "chemical/x-macromodel-input",
++ ".mmod" => "chemical/x-macromodel-input",
++ ".mol" => "chemical/x-mdl-molfile",
++ ".rd" => "chemical/x-mdl-rdfile",
++ ".rxn" => "chemical/x-mdl-rxnfile",
++ ".sd" => "chemical/x-mdl-sdfile",
++ ".tgf" => "chemical/x-mdl-tgf",
++ ".mcif" => "chemical/x-mmcif",
++ ".mol2" => "chemical/x-mol2",
++ ".gpt" => "chemical/x-mopac-graph",
++ ".mop" => "chemical/x-mopac-input",
++ ".mopcrt" => "chemical/x-mopac-input",
++ ".mpc" => "chemical/x-mopac-input",
++ ".zmt" => "chemical/x-mopac-input",
++ ".moo" => "chemical/x-mopac-out",
++ ".mvb" => "chemical/x-mopac-vib",
++ ".prt" => "chemical/x-ncbi-asn1-ascii",
++ ".aso" => "chemical/x-ncbi-asn1-binary",
++ ".val" => "chemical/x-ncbi-asn1-binary",
++ ".pdb" => "chemical/x-pdb",
++ ".ros" => "chemical/x-rosdal",
++ ".sw" => "chemical/x-swissprot",
++ ".vms" => "chemical/x-vamas-iso14976",
++ ".vmd" => "chemical/x-vmd",
++ ".xtel" => "chemical/x-xtel",
++ ".xyz" => "chemical/x-xyz",
++ ".gif" => "image/gif",
++ ".ief" => "image/ief",
++ ".jp2" => "image/jp2",
++ ".jpg2" => "image/jp2",
++ ".jpe" => "image/jpeg",
++ ".jpeg" => "image/jpeg",
++ ".jpg" => "image/jpeg",
++ ".jpm" => "image/jpm",
++ ".jpf" => "image/jpx",
++ ".jpx" => "image/jpx",
++ ".pcx" => "image/pcx",
++ ".png" => "image/png",
++ ".svg" => "image/svg+xml",
++ ".svgz" => "image/svg+xml",
++ ".tif" => "image/tiff",
++ ".tiff" => "image/tiff",
++ ".djv" => "image/vnd.djvu",
++ ".djvu" => "image/vnd.djvu",
++ ".ico" => "image/vnd.microsoft.icon",
++ ".wbmp" => "image/vnd.wap.wbmp",
++ ".cr2" => "image/x-canon-cr2",
++ ".crw" => "image/x-canon-crw",
++ ".ras" => "image/x-cmu-raster",
++ ".cdr" => "image/x-coreldraw",
++ ".pat" => "image/x-coreldrawpattern",
++ ".cdt" => "image/x-coreldrawtemplate",
++ ".erf" => "image/x-epson-erf",
++ ".art" => "image/x-jg",
++ ".jng" => "image/x-jng",
++ ".bmp" => "image/x-ms-bmp",
++ ".nef" => "image/x-nikon-nef",
++ ".orf" => "image/x-olympus-orf",
++ ".psd" => "image/x-photoshop",
++ ".pnm" => "image/x-portable-anymap",
++ ".pbm" => "image/x-portable-bitmap",
++ ".pgm" => "image/x-portable-graymap",
++ ".ppm" => "image/x-portable-pixmap",
++ ".rgb" => "image/x-rgb",
++ ".xbm" => "image/x-xbitmap",
++ ".xpm" => "image/x-xpixmap",
++ ".xwd" => "image/x-xwindowdump",
++ ".eml" => "message/rfc822",
++ ".iges" => "model/iges",
++ ".igs" => "model/iges",
++ ".mesh" => "model/mesh",
++ ".msh" => "model/mesh",
++ ".silo" => "model/mesh",
++ ".vrml" => "model/vrml",
++ ".wrl" => "model/vrml",
++ ".x3db" => "model/x3d+binary",
++ ".x3dv" => "model/x3d+vrml",
++ ".x3d" => "model/x3d+xml",
++ ".appcache" => "text/cache-manifest",
++ ".ics" => "text/calendar",
++ ".icz" => "text/calendar",
++ ".css" => "text/css; charset=utf-8",
++ ".csv" => "text/csv; charset=utf-8",
++ ".323" => "text/h323",
++ ".htm" => "text/html",
++ ".html" => "text/html",
++ ".shtml" => "text/html",
++ ".uls" => "text/iuls",
++ ".mml" => "text/mathml",
++ ".asc" => "text/plain; charset=utf-8",
++ ".brf" => "text/plain; charset=utf-8",
++ ".conf" => "text/plain; charset=utf-8",
++ ".log" => "text/plain; charset=utf-8",
++ ".pot" => "text/plain; charset=utf-8",
++ ".spec" => "text/plain; charset=utf-8",
++ ".srt" => "text/plain; charset=utf-8",
++ ".text" => "text/plain; charset=utf-8",
++ ".txt" => "text/plain; charset=utf-8",
++ ".rtx" => "text/richtext",
++ ".sct" => "text/scriptlet",
++ ".wsc" => "text/scriptlet",
++ ".tsv" => "text/tab-separated-values",
++ ".tm" => "text/texmacs",
++ ".ttl" => "text/turtle",
++ ".jad" => "text/vnd.sun.j2me.app-descriptor",
++ ".wml" => "text/vnd.wap.wml",
++ ".wmls" => "text/vnd.wap.wmlscript",
++ ".bib" => "text/x-bibtex; charset=utf-8",
++ ".boo" => "text/x-boo; charset=utf-8",
++ ".h++" => "text/x-c++hdr; charset=utf-8",
++ ".hh" => "text/x-c++hdr; charset=utf-8",
++ ".hpp" => "text/x-c++hdr; charset=utf-8",
++ ".hxx" => "text/x-c++hdr; charset=utf-8",
++ ".c++" => "text/x-c++src; charset=utf-8",
++ ".cc" => "text/x-c++src; charset=utf-8",
++ ".cpp" => "text/x-c++src; charset=utf-8",
++ ".cxx" => "text/x-c++src; charset=utf-8",
++ ".h" => "text/x-chdr; charset=utf-8",
++ ".htc" => "text/x-component",
++ ".csh" => "text/x-csh; charset=utf-8",
++ ".c" => "text/x-csrc; charset=utf-8",
++ ".diff" => "text/x-diff; charset=utf-8",
++ ".patch" => "text/x-diff; charset=utf-8",
++ ".d" => "text/x-dsrc; charset=utf-8",
++ ".hs" => "text/x-haskell; charset=utf-8",
++ ".java" => "text/x-java; charset=utf-8",
++ ".ly" => "text/x-lilypond; charset=utf-8",
++ ".lhs" => "text/x-literate-haskell; charset=utf-8",
++ ".moc" => "text/x-moc; charset=utf-8",
++ ".p" => "text/x-pascal; charset=utf-8",
++ ".pas" => "text/x-pascal; charset=utf-8",
++ ".gcd" => "text/x-pcs-gcd",
++ ".pl" => "text/x-perl; charset=utf-8",
++ ".pm" => "text/x-perl; charset=utf-8",
++ ".py" => "text/x-python; charset=utf-8",
++ ".scala" => "text/x-scala; charset=utf-8",
++ ".etx" => "text/x-setext",
++ ".sfv" => "text/x-sfv",
++ ".sh" => "text/x-sh; charset=utf-8",
++ ".tcl" => "text/x-tcl; charset=utf-8",
++ ".tk" => "text/x-tcl; charset=utf-8",
++ ".cls" => "text/x-tex; charset=utf-8",
++ ".ltx" => "text/x-tex; charset=utf-8",
++ ".sty" => "text/x-tex; charset=utf-8",
++ ".tex" => "text/x-tex; charset=utf-8",
++ ".vcs" => "text/x-vcalendar",
++ ".vcf" => "text/x-vcard",
++ ".3gp" => "video/3gpp",
++ ".axv" => "video/annodex",
++ ".dl" => "video/dl",
++ ".dif" => "video/dv",
++ ".dv" => "video/dv",
++ ".fli" => "video/fli",
++ ".gl" => "video/gl",
++ ".mp4" => "video/mp4",
++ ".mpe" => "video/mpeg",
++ ".mpeg" => "video/mpeg",
++ ".mpg" => "video/mpeg",
++ ".ogv" => "video/ogg",
++ ".mov" => "video/quicktime",
++ ".qt" => "video/quicktime",
++ ".webm" => "video/webm",
++ ".mxu" => "video/vnd.mpegurl",
++ ".flv" => "video/x-flv",
++ ".lsf" => "video/x-la-asf",
++ ".lsx" => "video/x-la-asf",
++ ".mkv" => "video/x-matroska",
++ ".mpv" => "video/x-matroska",
++ ".mng" => "video/x-mng",
++ ".asf" => "video/x-ms-asf",
++ ".asx" => "video/x-ms-asf",
++ ".wm" => "video/x-ms-wm",
++ ".wmv" => "video/x-ms-wmv",
++ ".wmx" => "video/x-ms-wmx",
++ ".wvx" => "video/x-ms-wvx",
++ ".avi" => "video/x-msvideo",
++ ".movie" => "video/x-sgi-movie",
++ ".ice" => "x-conference/x-cooltalk",
++ ".sisx" => "x-epoc/x-sisx-app",
++ ".vrm" => "x-world/x-vrml",
++ "README" => "text/plain; charset=utf-8",
++ "Makefile" => "text/x-makefile; charset=utf-8",
+
++ # enable caching for unknown mime types:
++ "" => "application/octet-stream"
++)
+diff --git a/doc/scripts/create-mime.conf.pl b/doc/scripts/create-mime.conf.pl
+new file mode 100755
+index 0000000..7c9e378
+--- /dev/null
++++ b/doc/scripts/create-mime.conf.pl
+@@ -0,0 +1,197 @@
++#!/usr/bin/perl -w
++
++# Based on create-mime.assign.pl in debian lighttpd (1.4.x) package
++# Creates an example mime.conf from /etc/mime.types
++
++use strict;
++
++# text/* subtypes to serve as "text/...; charset=utf-8"
++# text/html IS NOT INCLUDED: html has its own method for defining charset
++# (<meta>), but the standards specify that content-type in HTTP wins over
++# the setting in the html document.
++my %text_utf8 = map { $_ => 1 } qw(
++ css
++ csv
++ plain
++ x-bibtex
++ x-boo
++ x-c++hdr
++ x-c++src
++ x-chdr
++ x-csh
++ x-csrc
++ x-dsrc
++ x-diff
++ x-haskell
++ x-java
++ x-lilypond
++ x-literate-haskell
++ x-makefile
++ x-moc
++ x-pascal
++ x-perl
++ x-python
++ x-scala
++ x-sh
++ x-tcl
++ x-tex
++);
++
++# map extension to hash which maps types to the type they should be replaced with
++my %manual_conflicts_resolve = (
++ '.ra' => {
++ 'audio/x-pn-realaudio' => 'audio/x-realaudio',
++ },
++);
++
++open MIMETYPES, "/etc/mime.types" or die "Can't open /etc/mime.types: $!";
++
++my %extensions;
++sub set {
++ my ($extension, $mimetype) = @_;
++ $extensions{$extension} = $mimetype;
++}
++sub add {
++ my ($extension, $mimetype) = @_;
++ my $have = $extensions{$extension};
++
++ my $r = $manual_conflicts_resolve{$extension};
++ # update @_ too for calls to set
++ $_[1] = $mimetype = $r->{$mimetype} if $r && $r->{$mimetype};
++
++ # mime.types can have same extension for different mime types
++ if ($have) {
++ # application/octet-stream means we couldn't resolve another conflict
++ return if $have eq $mimetype || $have eq 'application/octet-stream';
++
++ my ($have_type, $have_subtype) = split /\//, $have, 2;
++ my ($type, $subtype) = split /\//, $mimetype, 2;
++
++ my $have_x = ($have_type =~ /^x-/ || $have_subtype =~ /^x-/);
++ my $x = ($type =~ /^x-/ || $subtype =~ /^x-/);
++
++ # entries without x- prefix in type/subtype win:
++ if ($have_x && !$x) {
++ return set @_; # overwrite
++ } elsif ($x && !$have_x) {
++ return; # ignore
++ }
++
++ # text/ wins over application/ for same subtype
++ if ($subtype eq $have_subtype) {
++ if ($type eq "text" && $have_type eq "application") {
++ return set @_; # overwrite
++ } elsif ($have_type eq "text" && $type eq "application") {
++ return; # ignore
++ }
++ }
++
++ print STDERR "Duplicate mimetype: '${extension}' => '${mimetype}' (already have '${have}'), merging to 'application/octet-stream'\n";
++ set ($extension, 'application/octet-stream');
++ } else {
++ set @_;
++ }
++}
++
++sub print_type {
++ my ($extension, $mimetype) = @_;
++ if ($mimetype =~ /^text\/(.*)$/) {
++ $mimetype .= "; charset=utf-8" if $text_utf8{$1};
++ }
++
++ print "\t\"${extension}\" => \"${mimetype}\",\n";
++}
++
++while (<MIMETYPES>) {
++ chomp;
++ s/\#.*//;
++ next if /^\w*$/;
++ if (/^([a-z0-9\/+-.]+)\s+((?:[a-z0-9.+-]+[ ]?)+)$/) {
++ my $mimetype = $1;
++ my @extensions = split / /, $2;
++
++ foreach my $ext (@extensions) {
++ add(".${ext}", $mimetype);
++ }
++ }
++}
++
++# missing in /etc/mime.types;
++# from http://www.iana.org/assignments/media-types/media-types.xhtml
++add(".dtd", "application/xml-dtd");
++
++# other useful mappings
++my %useful = (
++ ".tar.gz" => "application/x-gtar-compressed",
++ ".gz" => "application/x-gzip",
++ ".tbz" => "application/x-gtar-compressed",
++ ".tar.bz2" => "application/x-gtar-compressed",
++ ".bz2" => "application/x-bzip",
++ ".log" => "text/plain",
++ ".conf" => "text/plain",
++ ".spec" => "text/plain",
++ "README" => "text/plain",
++ "Makefile" => "text/x-makefile",
++);
++
++while (my ($ext, $mimetype) = each %useful) {
++ add($ext, $mimetype) unless $extensions{$ext};
++}
++
++
++print <<EOF;
++# created by create-mime.conf.pl
++
++#######################################################################
++##
++## MimeType handling
++## -------------------
++##
++## https://redmine.lighttpd.net/projects/lighttpd/wiki/Mimetype_assignDetails
++
++##
++## Use the "Content-Type" extended file attribute to obtain mime type if
++## possible
++##
++## Disabled by default
++##
++#mimetype.use-xattr = "enable"
++
++##
++## mimetype ("Content-Type" HTTP header) mapping for static file handling
++##
++## The first matching suffix is used. If no mapping is found
++## 'application/octet-stream' is used, and caching (etag/last-modified handling)
++## is disabled to prevent clients from caching "unknown" mime types.
++##
++## Therefore the last mapping is:
++## "" => "application/octet-stream"
++## This matches all extensions and acts as default mime type, and enables
++## caching for those.
++mimetype.assign = (
++EOF
++
++# sort "x-" and "vnd." prefixed names after everything else
++sub mimecmpvalue {
++ my ($mimetype) = @_;
++ $mimetype =~ s/(^|\/)(x-|vnd\.)/~$1$2/g;
++ return $mimetype;
++}
++sub countdots {
++ my ($s) = @_;
++ return scalar(() = $s =~ /\./g);
++}
++# the first matching suffix wins, so we have to sort by "length"
++# as all extensions start with "." we use the number of "."s as length
++# the exceptions are "README" and "Makefile" which are assumed not to conflict
++# (i.e. are not a suffix of any other extension)
++for my $ext (sort { countdots($b) <=> countdots($a) || mimecmpvalue($extensions{$a}) cmp mimecmpvalue($extensions{$b}) || $a cmp $b } keys(%extensions)) {
++ print_type($ext, $extensions{$ext});
++}
++
++print <<EOF;
++
++ # enable caching for unknown mime types:
++ "" => "application/octet-stream"
++)
++EOF
+--
+2.4.5
+
diff --git a/main/lighttpd/0005-fix-typo-in-NEWS-entry-for-2579.patch b/main/lighttpd/0005-fix-typo-in-NEWS-entry-for-2579.patch
new file mode 100644
index 0000000000..9f252e5306
--- /dev/null
+++ b/main/lighttpd/0005-fix-typo-in-NEWS-entry-for-2579.patch
@@ -0,0 +1,31 @@
+From 059a5a67ddff848385773162f90d6477b450d391 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Tue, 13 May 2014 13:04:35 +0000
+Subject: [PATCH 05/29] fix typo in NEWS entry for #2579
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2965 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/NEWS b/NEWS
+index 8c34545..0bf0313 100644
+--- a/NEWS
++++ b/NEWS
+@@ -6,7 +6,7 @@ NEWS
+ - 1.4.36
+ * use keep-alive timeout while waiting for HTTP headers; use always the read timeout while waiting for the HTTP body
+ * fix bad shift in conditional netmask ".../0" handling
+- * add more mime types and a script to generate mime.conf (fxies #2579)
++ * add more mime types and a script to generate mime.conf (fixes #2579)
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+--
+2.4.5
+
diff --git a/main/lighttpd/0006-add-support-for-Free-BSD-extended-attributes.patch b/main/lighttpd/0006-add-support-for-Free-BSD-extended-attributes.patch
new file mode 100644
index 0000000000..f3affb9119
--- /dev/null
+++ b/main/lighttpd/0006-add-support-for-Free-BSD-extended-attributes.patch
@@ -0,0 +1,175 @@
+From 4d55d4ada3ebbdd6b99855fe0767d26490955a22 Mon Sep 17 00:00:00 2001
+From: Moritz Wilhelmy <mw@barfooze.de>
+Date: Thu, 22 May 2014 08:30:13 +0000
+Subject: [PATCH 06/29] add support for (Free)BSD extended attributes
+
+enable with `./configure --with-attr` and `mimetype.use-xattr =
+"enable"` in the config.
+
+set attribute with:
+
+ setextattr user Content-Type text/plain path/to/www/file
+
+From: Moritz Wilhelmy <mw@barfooze.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2966 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ configure.ac | 25 +++++++++++++++++--------
+ src/mod_dirlisting.c | 17 ++++++++++++++---
+ src/stat_cache.c | 21 +++++++++++++++++++--
+ 4 files changed, 51 insertions(+), 13 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 0bf0313..84a1c80 100644
+--- a/NEWS
++++ b/NEWS
+@@ -7,6 +7,7 @@ NEWS
+ * use keep-alive timeout while waiting for HTTP headers; use always the read timeout while waiting for the HTTP body
+ * fix bad shift in conditional netmask ".../0" handling
+ * add more mime types and a script to generate mime.conf (fixes #2579)
++ * add support for (Free)BSD extended attributes
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/configure.ac b/configure.ac
+index ae35234..48e6b52 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -218,14 +218,23 @@ AC_ARG_WITH(attr, AC_HELP_STRING([--with-attr],[enable extended attribute suppor
+ [WITH_ATTR=$withval],[WITH_ATTR=no])
+ AC_MSG_RESULT($withval)
+ if test "$WITH_ATTR" != "no"; then
+- AC_CHECK_LIB(attr, attr_get, [
+- AC_CHECK_HEADERS([attr/attributes.h],[
+- ATTR_LIB=-lattr
+- AC_DEFINE([HAVE_XATTR], [1], [libattr])
+- AC_DEFINE([HAVE_ATTR_ATTRIBUTES_H], [1])
+- ])
+- ])
+- AC_SUBST(ATTR_LIB)
++ # libattr (linux only?)
++ AC_CHECK_LIB(attr, attr_get, [
++ AC_CHECK_HEADERS([attr/attributes.h],[
++ ATTR_LIB=-lattr
++ AC_DEFINE([HAVE_XATTR], [1], [libattr])
++ AC_DEFINE([HAVE_ATTR_ATTRIBUTES_H], [1])
++ ])
++ ])
++ AC_SUBST(ATTR_LIB)
++
++ # (Free)BSD extattr
++ AC_CHECK_FUNC([extattr_get_file], [
++ AC_CHECK_HEADERS([sys/extattr.h],[
++ AC_DEFINE([HAVE_EXTATTR], [1], [BSD extended attributes])
++ AC_DEFINE([HAVE_SYS_EXTATTR_H], [1])
++ ])
++ ])
+ fi
+
+ dnl openssl on solaris needs -lsocket -lnsl
+diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
+index cd5809e..6aba403 100644
+--- a/src/mod_dirlisting.c
++++ b/src/mod_dirlisting.c
+@@ -31,6 +31,10 @@
+ #include <attr/attributes.h>
+ #endif
+
++#ifdef HAVE_SYS_EXTATTR_H
++#include <sys/extattr.h>
++#endif
++
+ #include "version.h"
+
+ /* plugin config for all request/connections */
+@@ -644,7 +648,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ size_t k;
+ const char *content_type;
+ long name_max;
+-#ifdef HAVE_XATTR
++#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ char attrval[128];
+ int attrlen;
+ #endif
+@@ -820,8 +824,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ tmp = files.ent[i];
+
+ content_type = NULL;
+-#ifdef HAVE_XATTR
+-
++#if defined(HAVE_XATTR)
+ if (con->conf.use_xattr) {
+ memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
+ attrlen = sizeof(attrval) - 1;
+@@ -830,6 +833,14 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ content_type = attrval;
+ }
+ }
++#elif defined(HAVE_EXTATTR)
++ if (con->conf.use_xattr) {
++ memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
++ if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, "Content-Type", attrval, sizeof(attrval)-1))) {
++ attrval[attrlen] = '\0';
++ content_type = attrval;
++ }
++ }
+ #endif
+
+ if (content_type == NULL) {
+diff --git a/src/stat_cache.c b/src/stat_cache.c
+index 480aae4..9007325 100644
+--- a/src/stat_cache.c
++++ b/src/stat_cache.c
+@@ -18,6 +18,10 @@
+ # include <attr/attributes.h>
+ #endif
+
++#ifdef HAVE_SYS_EXTATTR_H
++# include <sys/extattr.h>
++#endif
++
+ #ifdef HAVE_FAM_H
+ # include <fam.h>
+ #endif
+@@ -210,7 +214,7 @@ void stat_cache_free(stat_cache *sc) {
+ free(sc);
+ }
+
+-#ifdef HAVE_XATTR
++#if defined(HAVE_XATTR)
+ static int stat_cache_attr_get(buffer *buf, char *name) {
+ int attrlen;
+ int ret;
+@@ -224,6 +228,19 @@ static int stat_cache_attr_get(buffer *buf, char *name) {
+ }
+ return ret;
+ }
++#elif defined(HAVE_EXTATTR)
++static int stat_cache_attr_get(buffer *buf, char *name) {
++ ssize_t attrlen = 1024;
++
++ buffer_prepare_copy(buf, attrlen);
++
++ if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, "Content-Type", buf->ptr, attrlen-1))) {
++ buf->used = attrlen + 1;
++ buf->ptr[attrlen] = '\0';
++ return 0;
++ }
++ return -1;
++}
+ #endif
+
+ /* the famous DJB hash function for strings */
+@@ -592,7 +609,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ if (S_ISREG(st.st_mode)) {
+ /* determine mimetype */
+ buffer_reset(sce->content_type);
+-#ifdef HAVE_XATTR
++#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ if (con->conf.use_xattr) {
+ stat_cache_attr_get(sce->content_type, name->ptr);
+ }
+--
+2.4.5
+
diff --git a/main/lighttpd/0007-build-use-fortify-flags-with-extra-warnings.patch b/main/lighttpd/0007-build-use-fortify-flags-with-extra-warnings.patch
new file mode 100644
index 0000000000..13db16ac19
--- /dev/null
+++ b/main/lighttpd/0007-build-use-fortify-flags-with-extra-warnings.patch
@@ -0,0 +1,88 @@
+From c4f214584aeaa30214d5364ef8bc2171dbd7bb3c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 16 Oct 2014 17:52:10 +0000
+Subject: [PATCH 07/29] [build] use fortify flags with "extra-warnings"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2967 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ configure.ac | 27 ++++++++++++++++++++++++---
+ src/CMakeLists.txt | 2 +-
+ 3 files changed, 26 insertions(+), 4 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 84a1c80..115e638 100644
+--- a/NEWS
++++ b/NEWS
+@@ -8,6 +8,7 @@ NEWS
+ * fix bad shift in conditional netmask ".../0" handling
+ * add more mime types and a script to generate mime.conf (fixes #2579)
+ * add support for (Free)BSD extended attributes
++ * [build] use fortify flags with "extra-warnings"
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/configure.ac b/configure.ac
+index 48e6b52..e804030 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -23,6 +23,26 @@ AM_INIT_AUTOMAKE([-Wall -Wno-portability -Wno-override foreign dist-bzip2 tar-us
+ dnl enable with --enable-silent-rules or make V=0 (needs automake >= 1.11)
+ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
+
++
++dnl @synopsis TRY_CFLAGS [compiler flags]
++dnl @summary check whether compiler supports given C flags and adds them to CFLAGS
++AC_DEFUN([TRY_CFLAGS],
++[dnl
++ AC_MSG_CHECKING([if $CC supports $1])
++ AC_LANG_PUSH([C])
++ ac_try_cflags_saved_cflags="${CFLAGS}"
++ CFLAGS="${CFLAGS} $1"
++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
++ [AC_MSG_RESULT([yes])],
++ [
++ AC_MSG_ERROR([no])
++ CFLAGS="${ac_try_cflags_saved_cflags}"
++ ]
++ )
++ AC_LANG_POP([C])
++])
++
++
+ dnl Checks for programs.
+ AC_PROG_CC
+ AM_PROG_CC_C_O
+@@ -394,7 +414,7 @@ if test "$WITH_FAM" != "no"; then
+ LIBS=$FAM_LIBS
+ AC_CHECK_FUNCS([FAMNoExists])
+ LIBS=$OLD_LIBS
+-
++
+ if test x$FAM_LIBS = x; then
+ AC_MSG_ERROR([fam/gamin-headers and/or libs where not found, install them or build with --without-fam])
+ fi
+@@ -622,7 +642,8 @@ AM_CONDITIONAL(CHECK_WITH_FASTCGI, test "x$fastcgi_found" = xyes)
+
+ dnl check for extra compiler options (warning options)
+ if test "${GCC}" = "yes"; then
+- CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99"
++ TRY_CFLAGS([-Wall -W -Wshadow -pedantic])
++ TRY_CFLAGS([-std=gnu99])
+ fi
+
+ AC_ARG_ENABLE(extra-warnings,
+@@ -634,7 +655,7 @@ AC_ARG_ENABLE(extra-warnings,
+ esac],[extrawarnings=false])
+
+ if test x$extrawarnings = xtrue; then
+- CFLAGS="${CFLAGS} -g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wno-pointer-sign -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -Wformat-security"
++ TRY_CFLAGS([-g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security])
+ fi
+
+ dnl build version-id
diff --git a/main/lighttpd/0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch b/main/lighttpd/0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch
new file mode 100644
index 0000000000..637f1721d0
--- /dev/null
+++ b/main/lighttpd/0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch
@@ -0,0 +1,163 @@
+From 4a6838103d8a6de025dcce1adfa6f508f17b3c16 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 16 Oct 2014 17:52:12 +0000
+Subject: [PATCH 08/29] [mod_dirlisting,mod_redirect,mod_rewrite] abort config
+ parsing if pcre-compile fails or isn't available
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2968 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/mod_dirlisting.c | 80 +++++++++++++++++++++++++---------------------------
+ src/mod_redirect.c | 1 +
+ src/mod_rewrite.c | 1 +
+ 4 files changed, 41 insertions(+), 42 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 115e638..7260fc5 100644
+--- a/NEWS
++++ b/NEWS
+@@ -9,6 +9,7 @@ NEWS
+ * add more mime types and a script to generate mime.conf (fixes #2579)
+ * add support for (Free)BSD extended attributes
+ * [build] use fortify flags with "extra-warnings"
++ * [mod_dirlisting,mod_redirect,mod_rewrite] abort config parsing if pcre-compile fails or isn't available
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
+index 6aba403..6a2b139 100644
+--- a/src/mod_dirlisting.c
++++ b/src/mod_dirlisting.c
+@@ -198,47 +198,6 @@ FREE_FUNC(mod_dirlisting_free) {
+ return HANDLER_GO_ON;
+ }
+
+-static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option) {
+- data_unset *du;
+-
+- if (NULL != (du = array_get_element(ca, option))) {
+- data_array *da;
+- size_t j;
+-
+- if (du->type != TYPE_ARRAY) {
+- log_error_write(srv, __FILE__, __LINE__, "sss",
+- "unexpected type for key: ", option, "array of strings");
+-
+- return HANDLER_ERROR;
+- }
+-
+- da = (data_array *)du;
+-
+- for (j = 0; j < da->value->used; j++) {
+- if (da->value->data[j]->type != TYPE_STRING) {
+- log_error_write(srv, __FILE__, __LINE__, "sssbs",
+- "unexpected type for key: ", option, "[",
+- da->value->data[j]->key, "](string)");
+-
+- return HANDLER_ERROR;
+- }
+-
+- if (0 != excludes_buffer_append(s->excludes,
+- ((data_string *)(da->value->data[j]))->value)) {
+-#ifdef HAVE_PCRE_H
+- log_error_write(srv, __FILE__, __LINE__, "sb",
+- "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
+-#else
+- log_error_write(srv, __FILE__, __LINE__, "s",
+- "pcre support is missing, please install libpcre and the headers");
+-#endif
+- }
+- }
+- }
+-
+- return 0;
+-}
+-
+ /* handle plugin config and check values */
+
+ #define CONFIG_EXCLUDE "dir-listing.exclude"
+@@ -287,6 +246,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+ array *ca;
++ data_unset *du_excludes;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->excludes = excludes_buffer_init();
+@@ -326,7 +286,43 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- parse_config_entry(srv, s, ca, CONFIG_EXCLUDE);
++ if (NULL != (du_excludes = array_get_element(ca, CONFIG_EXCLUDE))) {
++ array *excludes_list;
++ size_t j;
++
++ if (du_excludes->type != TYPE_ARRAY) {
++ log_error_write(srv, __FILE__, __LINE__, "sss",
++ "unexpected type for key: ", CONFIG_EXCLUDE, "array of strings");
++ return HANDLER_ERROR;
++ }
++
++ excludes_list = ((data_array*)du_excludes)->value;
++
++#ifndef HAVE_PCRE_H
++ if (excludes_list->used > 0) {
++ log_error_write(srv, __FILE__, __LINE__, "sss",
++ "pcre support is missing for: ", CONFIG_EXCLUDE, ", please install libpcre and the headers");
++ return HANDLER_ERROR;
++ }
++#else
++ for (j = 0; j < excludes_list->used; j++) {
++ data_unset *du_exclude = excludes_list->data[j];
++
++ if (du_exclude->type != TYPE_STRING) {
++ log_error_write(srv, __FILE__, __LINE__, "sssbs",
++ "unexpected type for key: ", CONFIG_EXCLUDE, "[",
++ du_exclude->key, "](string)");
++ return HANDLER_ERROR;
++ }
++
++ if (0 != excludes_buffer_append(s->excludes, ((data_string*)(du_exclude))->value)) {
++ log_error_write(srv, __FILE__, __LINE__, "sb",
++ "pcre-compile failed for", ((data_string*)(du_exclude))->value);
++ return HANDLER_ERROR;
++ }
++ }
++#endif
++ }
+ }
+
+ return HANDLER_GO_ON;
+diff --git a/src/mod_redirect.c b/src/mod_redirect.c
+index 3fdb4e3..bfc00d7 100644
+--- a/src/mod_redirect.c
++++ b/src/mod_redirect.c
+@@ -129,6 +129,7 @@ SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre-compile failed for", da->value->data[j]->key);
++ return HANDLER_ERROR;
+ }
+ }
+ }
+diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
+index 988dfd7..381f0ed 100644
+--- a/src/mod_rewrite.c
++++ b/src/mod_rewrite.c
+@@ -191,6 +191,7 @@ static int parse_config_entry(server *srv, array *ca, rewrite_rule_buffer *kvb,
+ once)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre-compile failed for", da->value->data[j]->key);
++ return HANDLER_ERROR;
+ }
+ }
+ }
+--
+2.4.5
+
diff --git a/main/lighttpd/0009-ssl-disable-SSL3.0-by-default.patch b/main/lighttpd/0009-ssl-disable-SSL3.0-by-default.patch
new file mode 100644
index 0000000000..6980a19497
--- /dev/null
+++ b/main/lighttpd/0009-ssl-disable-SSL3.0-by-default.patch
@@ -0,0 +1,44 @@
+From 084df7e99a8738be79f83e330415a8963280dc4a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 16 Oct 2014 17:52:14 +0000
+Subject: [PATCH 09/29] [ssl] disable SSL3.0 by default
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2969 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/configfile.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/NEWS b/NEWS
+index 7260fc5..a702941 100644
+--- a/NEWS
++++ b/NEWS
+@@ -10,6 +10,7 @@ NEWS
+ * add support for (Free)BSD extended attributes
+ * [build] use fortify flags with "extra-warnings"
+ * [mod_dirlisting,mod_redirect,mod_rewrite] abort config parsing if pcre-compile fails or isn't available
++ * [ssl] disable SSL3.0 by default
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/configfile.c b/src/configfile.c
+index 1e96ce0..bf9a34d 100644
+--- a/src/configfile.c
++++ b/src/configfile.c
+@@ -182,7 +182,7 @@ static int config_insert(server *srv) {
+ s->ssl_honor_cipher_order = 1;
+ s->ssl_empty_fragments = 0;
+ s->ssl_use_sslv2 = 0;
+- s->ssl_use_sslv3 = 1;
++ s->ssl_use_sslv3 = 0;
+ s->use_ipv6 = 0;
+ s->set_v6only = 1;
+ s->defer_accept = 0;
+--
+2.4.5
+
diff --git a/main/lighttpd/0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch b/main/lighttpd/0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch
new file mode 100644
index 0000000000..9f95d3ee41
--- /dev/null
+++ b/main/lighttpd/0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch
@@ -0,0 +1,38 @@
+From e1aab1c420e8d291299d1024e1c3450d85bec772 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marcus=20R=C3=BCckert?= <darix@opensu.se>
+Date: Thu, 5 Feb 2015 15:29:01 +0000
+Subject: [PATCH 10/29] Fixed typo found by openSUSE user (boo# 907709)
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2970 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ doc/config/vhosts.d/vhosts.template | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/doc/config/vhosts.d/vhosts.template b/doc/config/vhosts.d/vhosts.template
+index 2c443aa..efd441f 100644
+--- a/doc/config/vhosts.d/vhosts.template
++++ b/doc/config/vhosts.d/vhosts.template
+@@ -8,17 +8,17 @@ $HTTP["host"] == "download.example.com" {
+ var.server_name = "download.example.com"
+
+ server.name = server_name
+- ##
++ ## example how to include another config:
+ ## use trigger before download
+ ##
+- include "conf.d/trigger_b4_dl.conf"
++ # include "conf.d/trigger_b4_dl.conf"
+
+ server.document-root = vhosts_dir + "/example.com/download/htdocs"
+ ##
+ ## use a seperate access log file
+ ## At the moment you cant have different error log files.
+ ##
+- accesslog.filename = log_root + "/" + server_name "/access.log"
++ accesslog.filename = log_root + "/" + server_name + "/access.log"
+ }
+
+ $SERVER["socket"] == "127.0.0.1:443" {
+--
+2.4.5
+
diff --git a/main/lighttpd/0011-add-NEWS-entry-for-previous-commit.patch b/main/lighttpd/0011-add-NEWS-entry-for-previous-commit.patch
new file mode 100644
index 0000000000..791eafaf90
--- /dev/null
+++ b/main/lighttpd/0011-add-NEWS-entry-for-previous-commit.patch
@@ -0,0 +1,30 @@
+From 76870cfef1ae3a39c792ce9839e6191e0696c1cb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sat, 7 Feb 2015 11:33:28 +0000
+Subject: [PATCH 11/29] add NEWS entry for previous commit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2971 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/NEWS b/NEWS
+index a702941..7347012 100644
+--- a/NEWS
++++ b/NEWS
+@@ -11,6 +11,7 @@ NEWS
+ * [build] use fortify flags with "extra-warnings"
+ * [mod_dirlisting,mod_redirect,mod_rewrite] abort config parsing if pcre-compile fails or isn't available
+ * [ssl] disable SSL3.0 by default
++ * fixed typo in example config found by openSUSE user (boo# 907709)
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+--
+2.4.5
+
diff --git a/main/lighttpd/0012-network-fix-compile-break-in-calculation-of-sockaddr.patch b/main/lighttpd/0012-network-fix-compile-break-in-calculation-of-sockaddr.patch
new file mode 100644
index 0000000000..9aa38e537d
--- /dev/null
+++ b/main/lighttpd/0012-network-fix-compile-break-in-calculation-of-sockaddr.patch
@@ -0,0 +1,66 @@
+From b0a632f253737463138c182a3fb9c8be04caef5d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sat, 7 Feb 2015 11:33:30 +0000
+Subject: [PATCH 12/29] [network] fix compile break in calculation of
+ sockaddr_un size if SUN_LEN is not defined (fixes #2609)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2972 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/network.c | 13 +++++++------
+ 2 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 7347012..bf8984f 100644
+--- a/NEWS
++++ b/NEWS
+@@ -12,6 +12,7 @@ NEWS
+ * [mod_dirlisting,mod_redirect,mod_rewrite] abort config parsing if pcre-compile fails or isn't available
+ * [ssl] disable SSL3.0 by default
+ * fixed typo in example config found by openSUSE user (boo# 907709)
++ * [network] fix compile break in calculation of sockaddr_un size if SUN_LEN is not defined (fixes #2609)
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/network.c b/src/network.c
+index ebde43b..776a86c 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -349,6 +349,8 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
+
+ break;
+ case AF_UNIX:
++ memset(&srv_socket->addr, 0, sizeof(struct sockaddr_un));
++ srv_socket->addr.un.sun_family = AF_UNIX;
+ {
+ size_t hostlen = strlen(host) + 1;
+ if (hostlen > sizeof(srv_socket->addr.un.sun_path)) {
+@@ -356,15 +358,14 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
+ goto error_free_socket;
+ }
+ memcpy(srv_socket->addr.un.sun_path, host, hostlen);
+- }
+- srv_socket->addr.un.sun_family = AF_UNIX;
+
+-#ifdef SUN_LEN
+- addr_len = SUN_LEN(&srv_socket->addr.un);
++#if defined(SUN_LEN)
++ addr_len = SUN_LEN(&srv_socket->addr.un);
+ #else
+- /* stevens says: */
+- addr_len = hostlen + sizeof(srv_socket->addr.un.sun_family);
++ /* stevens says: */
++ addr_len = hostlen + sizeof(srv_socket->addr.un.sun_family);
+ #endif
++ }
+
+ /* check if the socket exists and try to connect to it. */
+ if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
+--
+2.4.5
+
diff --git a/main/lighttpd/0013-connections-fix-bug-in-connection-state-handling.patch b/main/lighttpd/0013-connections-fix-bug-in-connection-state-handling.patch
new file mode 100644
index 0000000000..1567759899
--- /dev/null
+++ b/main/lighttpd/0013-connections-fix-bug-in-connection-state-handling.patch
@@ -0,0 +1,69 @@
+From d00e1e79b94e0f4da35292d2293595dac02993c7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sat, 7 Feb 2015 13:32:54 +0000
+Subject: [PATCH 13/29] [connections] fix bug in connection state handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ if a request was finished (con->file_finished = 1) and the state
+ machine was triggered, but the write queue was empty, it didn't
+ actually finish the request.
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2973 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/connections.c | 22 +++++++++-------------
+ 2 files changed, 10 insertions(+), 13 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index bf8984f..9c579de 100644
+--- a/NEWS
++++ b/NEWS
+@@ -13,6 +13,7 @@ NEWS
+ * [ssl] disable SSL3.0 by default
+ * fixed typo in example config found by openSUSE user (boo# 907709)
+ * [network] fix compile break in calculation of sockaddr_un size if SUN_LEN is not defined (fixes #2609)
++ * [connections] fix bug in connection state handling
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/connections.c b/src/connections.c
+index bbaa632..fe683a2 100644
+--- a/src/connections.c
++++ b/src/connections.c
+@@ -1632,20 +1632,16 @@ int connection_state_machine(server *srv, connection *con) {
+
+ /* only try to write if we have something in the queue */
+ if (!chunkqueue_is_empty(con->write_queue)) {
+-#if 0
+- log_error_write(srv, __FILE__, __LINE__, "dsd",
+- con->fd,
+- "packets to write:",
+- con->write_queue->used);
+-#endif
+- }
+- if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
+- if (-1 == connection_handle_write(srv, con)) {
+- log_error_write(srv, __FILE__, __LINE__, "ds",
+- con->fd,
+- "handle write failed.");
+- connection_set_state(srv, con, CON_STATE_ERROR);
++ if (con->is_writable) {
++ if (-1 == connection_handle_write(srv, con)) {
++ log_error_write(srv, __FILE__, __LINE__, "ds",
++ con->fd,
++ "handle write failed.");
++ connection_set_state(srv, con, CON_STATE_ERROR);
++ }
+ }
++ } else if (con->file_finished) {
++ connection_set_state(srv, con, CON_STATE_RESPONSE_END);
+ }
+
+ break;
+--
+2.4.5
+
diff --git a/main/lighttpd/0014-print-backtrace-in-assert-logging-with-libunwind.patch b/main/lighttpd/0014-print-backtrace-in-assert-logging-with-libunwind.patch
new file mode 100644
index 0000000000..ff6ef06902
--- /dev/null
+++ b/main/lighttpd/0014-print-backtrace-in-assert-logging-with-libunwind.patch
@@ -0,0 +1,187 @@
+From 3521be8b8599ae2cc12361c8f600fc58a473de91 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sat, 7 Feb 2015 13:32:56 +0000
+Subject: [PATCH 14/29] print backtrace in assert logging with libunwind
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2974 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ configure.ac | 11 +++++++++
+ src/CMakeLists.txt | 11 +++++++++
+ src/Makefile.am | 5 ++--
+ src/buffer.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/buffer.h | 2 ++
+ src/config.h.cmake | 3 +++
+ 7 files changed, 102 insertions(+), 2 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 9c579de..fd537e8 100644
+--- a/NEWS
++++ b/NEWS
+@@ -14,6 +14,7 @@ NEWS
+ * fixed typo in example config found by openSUSE user (boo# 907709)
+ * [network] fix compile break in calculation of sockaddr_un size if SUN_LEN is not defined (fixes #2609)
+ * [connections] fix bug in connection state handling
++ * print backtrace in assert logging with libunwind
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/configure.ac b/configure.ac
+index e804030..63261ca 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -285,6 +285,17 @@ if test "$WITH_VALGRIND" != "no"; then
+ AC_CHECK_HEADERS([valgrind/valgrind.h])
+ fi
+
++dnl Checking for libunwind
++AC_MSG_CHECKING(for libunwind)
++AC_ARG_WITH(libunwind,
++ AC_HELP_STRING([--with-libunwind],[Include libunwind support for backtraces on assert failures]),
++ [WITH_LIBUNWIND=$withval],[WITH_LIBUNWIND=no])
++
++if test "$WITH_LIBUNWIND" != "no"; then
++ PKG_CHECK_MODULES(LIBUNWIND, libunwind)
++ AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
++fi
++
+ dnl Check for openssl
+ AC_MSG_CHECKING(for OpenSSL)
+ AC_ARG_WITH(openssl,
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 4afdcc6..a5471ff 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,4 +1,4 @@
+-AM_CFLAGS = $(FAM_CFLAGS)
++AM_CFLAGS = $(FAM_CFLAGS) $(LIBUNWIND_CFLAGS)
+
+ noinst_PROGRAMS=proc_open lemon # simple-fcgi #graphic evalo bench ajp ssl error_test adserver gen-license
+ sbin_PROGRAMS=lighttpd lighttpd-angel
+@@ -284,11 +284,12 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
+ DEFS= @DEFS@ -DHAVE_VERSION_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
+
+ lighttpd_SOURCES = $(src)
+-lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS)
++lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS) $(LIBUNWIND_LIBS)
+ lighttpd_LDFLAGS = -export-dynamic
+ lighttpd_CCPFLAGS = $(FAM_CFLAGS) $(LIBEV_CFLAGS)
+
+ proc_open_SOURCES = proc_open.c buffer.c
++proc_open_LDADD = $(LIBUNWIND_LIBS)
+ proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN
+
+ #gen_license_SOURCES = license.c md5.c buffer.c gen_license.c
+diff --git a/src/buffer.c b/src/buffer.c
+index 1199164..b4bd415 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -1059,9 +1059,80 @@ int buffer_to_upper(buffer *b) {
+ return 0;
+ }
+
++#ifdef HAVE_LIBUNWIND
++# define UNW_LOCAL_ONLY
++# include <libunwind.h>
++
++void print_backtrace(FILE *file) {
++ unw_cursor_t cursor;
++ unw_context_t context;
++ int ret;
++ unsigned int frame = 0;
++
++ if (0 != (ret = unw_getcontext(&context))) goto error;
++ if (0 != (ret = unw_init_local(&cursor, &context))) goto error;
++
++ fprintf(file, "Backtrace:\n");
++
++ while (0 < (ret = unw_step(&cursor))) {
++ unw_word_t proc_ip = 0;
++ unw_proc_info_t procinfo;
++ char procname[256];
++ unw_word_t proc_offset = 0;
++
++ if (0 != (ret = unw_get_reg(&cursor, UNW_REG_IP, &proc_ip))) goto error;
++
++ if (0 == proc_ip) {
++ /* without an IP the other functions are useless; unw_get_proc_name would return UNW_EUNSPEC */
++ ++frame;
++ fprintf(file, "%u: (nil)\n", frame);
++ continue;
++ }
++
++ if (0 != (ret = unw_get_proc_info(&cursor, &procinfo))) goto error;
++
++ if (0 != (ret = unw_get_proc_name(&cursor, procname, sizeof(procname), &proc_offset))) {
++ switch (-ret) {
++ case UNW_ENOMEM:
++ memset(procname + sizeof(procname) - 4, '.', 3);
++ procname[sizeof(procname) - 1] = '\0';
++ break;
++ case UNW_ENOINFO:
++ procname[0] = '?';
++ procname[1] = '\0';
++ proc_offset = 0;
++ break;
++ default:
++ snprintf(procname, sizeof(procname), "?? (unw_get_proc_name error %d)", -ret);
++ break;
++ }
++ }
++
++ ++frame;
++ fprintf(file, "%u: %s (+0x%x) [%p]\n",
++ frame,
++ procname,
++ (unsigned int) proc_offset,
++ (void*)(uintptr_t)proc_ip);
++ }
++
++ if (0 != ret) goto error;
++
++ return;
++
++error:
++ fprintf(file, "Error while generating backtrace: unwind error %i\n", (int) -ret);
++}
++#else
++void print_backtrace(FILE *file) {
++ UNUSED(file);
++}
++#endif
++
+ void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
+ /* can't use buffer here; could lead to recursive assertions */
+ fprintf(stderr, "%s.%d: %s\n", filename, line, msg);
++ print_backtrace(stderr);
+ fflush(stderr);
+ abort();
+ }
+diff --git a/src/buffer.h b/src/buffer.h
+index 20635e2..d2f5985 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -9,6 +9,7 @@
+
+ #include <stdlib.h>
+ #include <sys/types.h>
++#include <stdio.h>
+
+ typedef struct {
+ char *ptr;
+@@ -128,6 +129,7 @@ int light_isalnum(int c);
+
+ #define UNUSED(x) ( (void)(x) )
+
++void print_backtrace(FILE *file);
+ void log_failed_assert(const char *filename, unsigned int line, const char *msg) LI_NORETURN;
+ #define force_assert(x) do { if (!(x)) log_failed_assert(__FILE__, __LINE__, "assertion failed: " #x); } while(0)
+ #define SEGFAULT() log_failed_assert(__FILE__, __LINE__, "aborted");
+--
+2.4.5
+
diff --git a/main/lighttpd/0015-fix-buffer-chunk-and-http_chunk-API.patch b/main/lighttpd/0015-fix-buffer-chunk-and-http_chunk-API.patch
new file mode 100644
index 0000000000..7380ce5ce8
--- /dev/null
+++ b/main/lighttpd/0015-fix-buffer-chunk-and-http_chunk-API.patch
@@ -0,0 +1,6095 @@
+From 6afad87d2ed66a48cda2a7c01dbcc59023774b73 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 12:37:10 +0000
+Subject: [PATCH 15/29] fix buffer, chunk and http_chunk API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ * remove unused structs and functions
+ (buffer_array, read_buffer)
+ * change return type from int to void for many functions,
+ as the return value (indicating error/success) was never checked,
+ and the function would only fail on programming errors and not on
+ invalid input; changed functions to use force_assert instead of
+ returning an error.
+ * all "len" parameters now are the real size of the memory to be read.
+ the length of strings is given always without the terminating 0.
+ * the "buffer" struct still counts the terminating 0 in ->used,
+ provide buffer_string_length() to get the length of a string in a
+ buffer.
+ unset config "strings" have used == 0, which is used in some places
+ to distinguish unset values from "" (empty string) values.
+ * most buffer usages should now use it as string container.
+ * optimise some buffer copying by "moving" data to other buffers
+ * use (u)intmax_t for generic int-to-string functions
+ * remove unused enum values: UNUSED_CHUNK, ENCODING_UNSET
+ * converted BUFFER_APPEND_SLASH to inline function (no macro feature
+ needed)
+ * refactor: create chunkqueue_steal: moving (partial) chunks into another
+ queue
+ * http_chunk: added separate function to terminate chunked body instead of
+ magic handling in http_chunk_append_mem().
+ http_chunk_append_* now handle empty chunks, and never terminate the
+ chunked body.
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2975 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/array.c | 2 +-
+ src/buffer.c | 752 ++++++++++++++++++----------------------------
+ src/buffer.h | 170 ++++++-----
+ src/chunk.c | 244 +++++++--------
+ src/chunk.h | 18 +-
+ src/configfile-glue.c | 16 +-
+ src/configfile.c | 26 +-
+ src/configparser.y | 26 +-
+ src/connections.c | 28 +-
+ src/data_array.c | 2 +-
+ src/data_config.c | 4 +-
+ src/data_count.c | 2 +-
+ src/data_fastcgi.c | 4 +-
+ src/data_integer.c | 2 +-
+ src/data_string.c | 8 +-
+ src/etag.c | 10 +-
+ src/http-header-glue.c | 6 +-
+ src/http_auth.c | 14 +-
+ src/http_chunk.c | 71 ++---
+ src/http_chunk.h | 8 +-
+ src/log.c | 16 +-
+ src/mod_access.c | 2 +-
+ src/mod_accesslog.c | 22 +-
+ src/mod_alias.c | 6 +-
+ src/mod_auth.c | 6 +-
+ src/mod_cgi.c | 49 ++-
+ src/mod_cml.c | 10 +-
+ src/mod_cml_lua.c | 14 +-
+ src/mod_compress.c | 20 +-
+ src/mod_dirlisting.c | 17 +-
+ src/mod_evhost.c | 8 +-
+ src/mod_expire.c | 2 +-
+ src/mod_fastcgi.c | 219 ++++----------
+ src/mod_flv_streaming.c | 4 +-
+ src/mod_indexfile.c | 6 +-
+ src/mod_magnet.c | 8 +-
+ src/mod_magnet_cache.c | 4 +-
+ src/mod_mysql_vhost.c | 18 +-
+ src/mod_proxy.c | 77 +----
+ src/mod_redirect.c | 2 +-
+ src/mod_rewrite.c | 4 +-
+ src/mod_rrdtool.c | 12 +-
+ src/mod_scgi.c | 135 +++------
+ src/mod_secure_download.c | 14 +-
+ src/mod_setenv.c | 8 +-
+ src/mod_simple_vhost.c | 26 +-
+ src/mod_ssi.c | 33 +-
+ src/mod_ssi_expr.c | 4 +-
+ src/mod_staticfile.c | 16 +-
+ src/mod_status.c | 50 +--
+ src/mod_trigger_b4_dl.c | 10 +-
+ src/mod_uploadprogress.c | 10 +-
+ src/mod_userdir.c | 20 +-
+ src/mod_usertrack.c | 16 +-
+ src/mod_webdav.c | 62 ++--
+ src/network.c | 28 +-
+ src/plugin.c | 2 +-
+ src/request.c | 6 +-
+ src/response.c | 32 +-
+ src/server.c | 2 +-
+ src/stat_cache.c | 26 +-
+ 62 files changed, 1044 insertions(+), 1396 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index fd537e8..ddb370d 100644
+--- a/NEWS
++++ b/NEWS
+@@ -15,6 +15,7 @@ NEWS
+ * [network] fix compile break in calculation of sockaddr_un size if SUN_LEN is not defined (fixes #2609)
+ * [connections] fix bug in connection state handling
+ * print backtrace in assert logging with libunwind
++ * major refactoring of internal buffer/chunk handling
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/array.c b/src/array.c
+index c9af995..9a15abd 100644
+--- a/src/array.c
++++ b/src/array.c
+@@ -188,7 +188,7 @@ int array_insert_unique(array *a, data_unset *str) {
+
+ /* generate unique index if neccesary */
+ if (str->key->used == 0 || str->is_index_key) {
+- buffer_copy_long(str->key, a->unique_ndx++);
++ buffer_copy_int(str->key, a->unique_ndx++);
+ str->is_index_key = 1;
+ }
+
+diff --git a/src/buffer.c b/src/buffer.c
+index b4bd415..caaa5bb 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -7,12 +7,6 @@
+ #include <assert.h>
+ #include <ctype.h>
+
+-#if defined HAVE_STDINT_H
+-# include <stdint.h>
+-#elif defined HAVE_INTTYPES_H
+-# include <inttypes.h>
+-#endif
+-
+ static const char hex_chars[] = "0123456789abcdef";
+
+
+@@ -34,177 +28,160 @@ buffer* buffer_init(void) {
+ return b;
+ }
+
+-buffer *buffer_init_buffer(buffer *src) {
++buffer *buffer_init_buffer(const buffer *src) {
+ buffer *b = buffer_init();
+- buffer_copy_string_buffer(b, src);
++ buffer_copy_buffer(b, src);
+ return b;
+ }
+
+-/**
+- * free the buffer
+- *
+- */
++buffer *buffer_init_string(const char *str) {
++ buffer *b = buffer_init();
++ buffer_copy_string(b, str);
++ return b;
++}
+
+ void buffer_free(buffer *b) {
+- if (!b) return;
++ if (NULL == b) return;
+
+ free(b->ptr);
+ free(b);
+ }
+
+ void buffer_reset(buffer *b) {
+- if (!b) return;
++ if (NULL == b) return;
+
+ /* limit don't reuse buffer larger than ... bytes */
+ if (b->size > BUFFER_MAX_REUSE_SIZE) {
+ free(b->ptr);
+ b->ptr = NULL;
+ b->size = 0;
+- } else if (b->size) {
++ } else if (b->size > 0) {
+ b->ptr[0] = '\0';
+ }
+
+ b->used = 0;
+ }
+
++void buffer_move(buffer *b, buffer *src) {
++ buffer tmp;
+
+-/**
+- *
+- * allocate (if neccessary) enough space for 'size' bytes and
+- * set the 'used' counter to 0
+- *
+- */
++ if (NULL == b) {
++ buffer_reset(src);
++ return;
++ }
++ buffer_reset(b);
++ if (NULL == src) return;
++
++ tmp = *src; *src = *b; *b = tmp;
++}
+
+ #define BUFFER_PIECE_SIZE 64
++static size_t buffer_align_size(size_t size) {
++ size_t align = BUFFER_PIECE_SIZE - (size % BUFFER_PIECE_SIZE);
++ /* overflow on unsinged size_t is defined to wrap around */
++ if (size + align < size) return size;
++ return size + align;
++}
+
+-int buffer_prepare_copy(buffer *b, size_t size) {
+- if (!b) return -1;
++char* buffer_prepare_copy(buffer *b, size_t size) {
++ force_assert(NULL != b);
+
+- if ((0 == b->size) ||
+- (size > b->size)) {
+- if (b->size) free(b->ptr);
++ /* also allocate space for terminating 0 */
++ /* check for overflow: unsigned overflow is defined to wrap around */
++ force_assert(1 + size > size);
++ ++size;
+
+- b->size = size;
++ if (0 == b->size || size > b->size) {
++ if (NULL != b->ptr) free(b->ptr);
++ b->ptr = NULL;
+
+- /* always allocate a multiply of BUFFER_PIECE_SIZE */
+- b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
++ b->size = buffer_align_size(size);
++ force_assert(b->size > 0);
+
+ b->ptr = malloc(b->size);
+- force_assert(b->ptr);
++ force_assert(NULL != b->ptr);
+ }
+- b->used = 0;
+- return 0;
+-}
+-
+-/**
+- *
+- * increase the internal buffer (if neccessary) to append another 'size' byte
+- * ->used isn't changed
+- *
+- */
+
+-int buffer_prepare_append(buffer *b, size_t size) {
+- if (!b) return -1;
+-
+- if (0 == b->size) {
+- b->size = size;
+-
+- /* always allocate a multiply of BUFFER_PIECE_SIZE */
+- b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
++ /* reset */
++ b->used = 0;
++ b->ptr[0] = '\0';
+
+- b->ptr = malloc(b->size);
+- b->used = 0;
+- force_assert(b->ptr);
+- } else if (b->used + size > b->size) {
+- b->size += size;
++ return b->ptr;
++}
+
+- /* always allocate a multiply of BUFFER_PIECE_SIZE */
+- b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
++char* buffer_prepare_append(buffer *b, size_t size) {
++ size_t req_size;
++ force_assert(NULL != b);
+
+- b->ptr = realloc(b->ptr, b->size);
+- force_assert(b->ptr);
++ if (buffer_string_is_empty(b)) {
++ size_t old_used = b->used; /* either 0 or 1 */
++ /* just prepare copy (free+malloc instead of realloc) */
++ buffer_prepare_copy(b, size);
++ b->used = old_used; /* buffer_prepare_append mustn't modify b->used */
++ return b->ptr;
+ }
+- return 0;
+-}
+
+-int buffer_copy_string(buffer *b, const char *s) {
+- size_t s_len;
++ /* not empty, b->used already includes a terminating 0 */
++ req_size = b->used + size;
+
+- if (!s || !b) return -1;
++ /* check for overflow: unsigned overflow is defined to wrap around */
++ force_assert(req_size >= b->used);
+
+- s_len = strlen(s) + 1;
+- buffer_prepare_copy(b, s_len);
++ if (req_size > b->size) {
++ char *ptr;
++ b->size = buffer_align_size(req_size);
+
+- memcpy(b->ptr, s, s_len);
+- b->used = s_len;
++ ptr = realloc(b->ptr, b->size);
++ force_assert(NULL != ptr);
++ b->ptr = ptr;
++ }
+
+- return 0;
++ return b->ptr + b->used - 1;
+ }
+
+-int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
+- if (!s || !b) return -1;
+-#if 0
+- /* removed optimization as we have to keep the empty string
+- * in some cases for the config handling
+- *
+- * url.access-deny = ( "" )
+- */
+- if (s_len == 0) return 0;
+-#endif
+- buffer_prepare_copy(b, s_len + 1);
+-
+- memcpy(b->ptr, s, s_len);
+- b->ptr[s_len] = '\0';
+- b->used = s_len + 1;
++void buffer_commit(buffer *b, size_t size)
++{
++ force_assert(NULL != b);
++ force_assert(b->size > 0);
+
+- return 0;
+-}
++ if (0 == b->used) b->used = 1;
+
+-int buffer_copy_string_buffer(buffer *b, const buffer *src) {
+- if (!src) return -1;
++ if (size > 0) {
++ /* check for overflow: unsigned overflow is defined to wrap around */
++ force_assert(b->used + size > b->used);
+
+- if (src->used == 0) {
+- buffer_reset(b);
+- return 0;
++ force_assert(b->used + size <= b->size);
++ b->used += size;
+ }
+- return buffer_copy_string_len(b, src->ptr, src->used - 1);
++
++ b->ptr[b->used - 1] = '\0';
+ }
+
+-int buffer_append_string(buffer *b, const char *s) {
+- size_t s_len;
++void buffer_copy_string(buffer *b, const char *s) {
++ buffer_copy_string_len(b, s, NULL != s ? strlen(s) : 0);
++}
+
+- if (!s || !b) return -1;
++void buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
++ force_assert(NULL != b);
++ force_assert(NULL != s || s_len == 0);
+
+- s_len = strlen(s);
+- buffer_prepare_append(b, s_len + 1);
+- if (b->used == 0)
+- b->used++;
++ buffer_prepare_copy(b, s_len);
+
+- memcpy(b->ptr + b->used - 1, s, s_len + 1);
+- b->used += s_len;
++ if (0 != s_len) memcpy(b->ptr, s, s_len);
+
+- return 0;
++ buffer_commit(b, s_len);
+ }
+
+-int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
+- size_t s_len;
+-
+- if (!s || !b) return -1;
+-
+- s_len = strlen(s);
+- if (s_len > maxlen) s_len = maxlen;
+- buffer_prepare_append(b, maxlen + 1);
+- if (b->used == 0)
+- b->used++;
+-
+- memcpy(b->ptr + b->used - 1, s, s_len);
+- if (maxlen > s_len) {
+- memset(b->ptr + b->used - 1 + s_len, ' ', maxlen - s_len);
++void buffer_copy_buffer(buffer *b, const buffer *src) {
++ if (NULL == src || 0 == src->used) {
++ buffer_prepare_copy(b, 0);
++ } else {
++ buffer_copy_string_len(b, src->ptr, buffer_string_length(src));
+ }
++}
+
+- b->used += maxlen;
+- b->ptr[b->used - 1] = '\0';
+- return 0;
++void buffer_append_string(buffer *b, const char *s) {
++ buffer_append_string_len(b, s, NULL != s ? strlen(s) : 0);
+ }
+
+ /**
+@@ -218,176 +195,138 @@ int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
+ * @param s_len size of the string (without the terminating \0)
+ */
+
+-int buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
+- if (!s || !b) return -1;
+- if (s_len == 0) return 0;
+-
+- buffer_prepare_append(b, s_len + 1);
+- if (b->used == 0)
+- b->used++;
+-
+- memcpy(b->ptr + b->used - 1, s, s_len);
+- b->used += s_len;
+- b->ptr[b->used - 1] = '\0';
+-
+- return 0;
+-}
++void buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
++ char *target_buf;
+
+-int buffer_append_string_buffer(buffer *b, const buffer *src) {
+- if (!src) return -1;
+- if (src->used == 0) return 0;
++ force_assert(NULL != b);
++ force_assert(NULL != s || s_len == 0);
+
+- return buffer_append_string_len(b, src->ptr, src->used - 1);
+-}
++ target_buf = buffer_prepare_append(b, s_len);
+
+-int buffer_append_memory(buffer *b, const char *s, size_t s_len) {
+- if (!s || !b) return -1;
+- if (s_len == 0) return 0;
++ /* only append to 0-terminated string */
++ force_assert('\0' == *target_buf);
+
+- buffer_prepare_append(b, s_len);
+- memcpy(b->ptr + b->used, s, s_len);
+- b->used += s_len;
++ if (s_len > 0) memcpy(target_buf, s, s_len);
+
+- return 0;
++ buffer_commit(b, s_len);
+ }
+
+-int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
+- if (!s || !b) return -1;
+-
+- b->used = 0;
+-
+- return buffer_append_memory(b, s, s_len);
++void buffer_append_string_buffer(buffer *b, const buffer *src) {
++ if (NULL == src) {
++ buffer_append_string_len(b, NULL, 0);
++ } else {
++ buffer_append_string_len(b, src->ptr, buffer_string_length(src));
++ }
+ }
+
+-int buffer_append_long_hex(buffer *b, unsigned long value) {
++void buffer_append_long_hex(buffer *b, unsigned long value) {
+ char *buf;
+ int shift = 0;
+- unsigned long copy = value;
+
+- while (copy) {
+- copy >>= 4;
+- shift++;
++ {
++ unsigned long copy = value;
++ do {
++ copy >>= 8;
++ shift += 2; /* counting nibbles (4 bits) */
++ } while (0 != copy);
+ }
+- if (shift == 0)
+- shift++;
+- if (shift & 0x01)
+- shift++;
+-
+- buffer_prepare_append(b, shift + 1);
+- if (b->used == 0)
+- b->used++;
+- buf = b->ptr + (b->used - 1);
+- b->used += shift;
+-
+- shift <<= 2;
++
++ buf = buffer_prepare_append(b, shift);
++ buffer_commit(b, shift); /* will fill below */
++
++ shift <<= 2; /* count bits now */
+ while (shift > 0) {
+ shift -= 4;
+ *(buf++) = hex_chars[(value >> shift) & 0x0F];
+ }
+- *buf = '\0';
+-
+- return 0;
+ }
+
+-int LI_ltostr(char *buf, long val) {
+- char swap;
+- char *end;
+- int len = 1;
+-
+- if (val < 0) {
+- len++;
+- *(buf++) = '-';
+- val = -val;
+- }
+-
+- end = buf;
+- while (val > 9) {
+- *(end++) = '0' + (val % 10);
+- val = val / 10;
+- }
+- *(end) = '0' + val;
+- *(end + 1) = '\0';
+- len += end - buf;
++static char* utostr(char * const buf_end, uintmax_t val) {
++ char *cur = buf_end;
++ do {
++ int mod = val % 10;
++ val /= 10;
++ /* prepend digit mod */
++ *(--cur) = (char) ('0' + mod);
++ } while (0 != val);
++ return cur;
++}
+
+- while (buf < end) {
+- swap = *end;
+- *end = *buf;
+- *buf = swap;
++static char* itostr(char * const buf_end, intmax_t val) {
++ char *cur = buf_end;
++ if (val >= 0) return utostr(buf_end, (uintmax_t) val);
+
+- buf++;
+- end--;
+- }
++ /* can't take absolute value, as it isn't defined for INTMAX_MIN */
++ do {
++ int mod = val % 10;
++ val /= 10;
++ /* val * 10 + mod == orig val, -10 < mod < 10 */
++ /* we want a negative mod */
++ if (mod > 0) {
++ mod -= 10;
++ val += 1;
++ }
++ /* prepend digit abs(mod) */
++ *(--cur) = (char) ('0' + (-mod));
++ } while (0 != val);
++ *(--cur) = '-';
+
+- return len;
++ return cur;
+ }
+
+-int buffer_append_long(buffer *b, long val) {
+- if (!b) return -1;
++void buffer_append_int(buffer *b, intmax_t val) {
++ char buf[LI_ITOSTRING_LENGTH];
++ char* const buf_end = buf + sizeof(buf);
++ char *str;
+
+- buffer_prepare_append(b, 32);
+- if (b->used == 0)
+- b->used++;
++ force_assert(NULL != b);
+
+- b->used += LI_ltostr(b->ptr + (b->used - 1), val);
+- return 0;
++ str = itostr(buf_end, val);
++ force_assert(buf_end > str && str >= buf);
++
++ buffer_append_string_len(b, str, buf_end - str);
+ }
+
+-int buffer_copy_long(buffer *b, long val) {
+- if (!b) return -1;
++void buffer_copy_int(buffer *b, intmax_t val) {
++ force_assert(NULL != b);
+
+ b->used = 0;
+- return buffer_append_long(b, val);
++ buffer_append_int(b, val);
+ }
+
+-#if !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T)
+-int buffer_append_off_t(buffer *b, off_t val) {
+- char swap;
+- char *end;
+- char *start;
+- int len = 1;
+-
+- if (!b) return -1;
++void li_itostrn(char *buf, size_t buf_len, intmax_t val) {
++ char p_buf[LI_ITOSTRING_LENGTH];
++ char* const p_buf_end = p_buf + sizeof(p_buf);
++ char* str = p_buf_end - 1;
++ *str = '\0';
+
+- buffer_prepare_append(b, 32);
+- if (b->used == 0)
+- b->used++;
++ str = itostr(str, val);
++ force_assert(p_buf_end > str && str >= p_buf);
+
+- start = b->ptr + (b->used - 1);
+- if (val < 0) {
+- len++;
+- *(start++) = '-';
+- val = -val;
+- }
++ force_assert(buf_len >= (size_t) (p_buf_end - str));
++ memcpy(buf, str, p_buf_end - str);
++}
+
+- end = start;
+- while (val > 9) {
+- *(end++) = '0' + (val % 10);
+- val = val / 10;
+- }
+- *(end) = '0' + val;
+- *(end + 1) = '\0';
+- len += end - start;
++void li_itostr(char *buf, intmax_t val) {
++ li_itostrn(buf, LI_ITOSTRING_LENGTH, val);
++}
+
+- while (start < end) {
+- swap = *end;
+- *end = *start;
+- *start = swap;
++void li_utostrn(char *buf, size_t buf_len, uintmax_t val) {
++ char p_buf[LI_ITOSTRING_LENGTH];
++ char* const p_buf_end = p_buf + sizeof(p_buf);
++ char* str = p_buf_end - 1;
++ *str = '\0';
+
+- start++;
+- end--;
+- }
++ str = utostr(str, val);
++ force_assert(p_buf_end > str && str >= p_buf);
+
+- b->used += len;
+- return 0;
++ force_assert(buf_len >= (size_t) (p_buf_end - str));
++ memcpy(buf, str, p_buf_end - str);
+ }
+
+-int buffer_copy_off_t(buffer *b, off_t val) {
+- if (!b) return -1;
+-
+- b->used = 0;
+- return buffer_append_off_t(b, val);
++void li_utostr(char *buf, uintmax_t val) {
++ li_utostrn(buf, LI_ITOSTRING_LENGTH, val);
+ }
+-#endif /* !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T) */
+
+ char int2hex(char c) {
+ return hex_chars[(c & 0x0F)];
+@@ -397,99 +336,21 @@ char int2hex(char c) {
+ * returns 0xFF on invalid input.
+ */
+ char hex2int(unsigned char hex) {
+- hex = hex - '0';
+- if (hex > 9) {
+- hex = (hex + '0' - 1) | 0x20;
+- hex = hex - 'a' + 11;
++ unsigned char value = hex - '0';
++ if (value > 9) {
++ hex |= 0x20; /* to lower case */
++ value = hex - 'a' + 10;
++ if (value < 10) value = 0xff;
+ }
+- if (hex > 15)
+- hex = 0xFF;
++ if (value > 15) value = 0xff;
+
+- return hex;
++ return value;
+ }
+
+-
+-/**
+- * init the buffer
+- *
+- */
+-
+-buffer_array* buffer_array_init(void) {
+- buffer_array *b;
+-
+- b = malloc(sizeof(*b));
+-
+- force_assert(b);
+- b->ptr = NULL;
+- b->size = 0;
+- b->used = 0;
+-
+- return b;
+-}
+-
+-void buffer_array_reset(buffer_array *b) {
+- size_t i;
+-
+- if (!b) return;
+-
+- /* if they are too large, reduce them */
+- for (i = 0; i < b->used; i++) {
+- buffer_reset(b->ptr[i]);
+- }
+-
+- b->used = 0;
+-}
+-
+-
+-/**
+- * free the buffer_array
+- *
+- */
+-
+-void buffer_array_free(buffer_array *b) {
+- size_t i;
+- if (!b) return;
+-
+- for (i = 0; i < b->size; i++) {
+- if (b->ptr[i]) buffer_free(b->ptr[i]);
+- }
+- free(b->ptr);
+- free(b);
+-}
+-
+-buffer *buffer_array_append_get_buffer(buffer_array *b) {
+- size_t i;
+-
+- if (b->size == 0) {
+- b->size = 16;
+- b->ptr = malloc(sizeof(*b->ptr) * b->size);
+- force_assert(b->ptr);
+- for (i = 0; i < b->size; i++) {
+- b->ptr[i] = NULL;
+- }
+- } else if (b->size == b->used) {
+- b->size += 16;
+- b->ptr = realloc(b->ptr, sizeof(*b->ptr) * b->size);
+- force_assert(b->ptr);
+- for (i = b->used; i < b->size; i++) {
+- b->ptr[i] = NULL;
+- }
+- }
+-
+- if (b->ptr[b->used] == NULL) {
+- b->ptr[b->used] = buffer_init();
+- }
+-
+- b->ptr[b->used]->used = 0;
+-
+- return b->ptr[b->used++];
+-}
+-
+-
+ char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
+ size_t i;
+- if (len == 0) return NULL;
+- if (needle == NULL) return NULL;
++ force_assert(NULL != b);
++ force_assert(0 != len && NULL != needle); /* empty needles not allowed */
+
+ if (b->used < len) return NULL;
+
+@@ -502,17 +363,12 @@ char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
+ return NULL;
+ }
+
+-buffer *buffer_init_string(const char *str) {
+- buffer *b = buffer_init();
+-
+- buffer_copy_string(b, str);
+-
+- return b;
++int buffer_is_empty(buffer *b) {
++ return NULL == b || 0 == b->used;
+ }
+
+-int buffer_is_empty(buffer *b) {
+- if (!b) return 1;
+- return (b->used == 0);
++int buffer_string_is_empty(buffer *b) {
++ return 0 == buffer_string_length(b);
+ }
+
+ /**
+@@ -523,24 +379,30 @@ int buffer_is_empty(buffer *b) {
+ */
+
+ int buffer_is_equal(buffer *a, buffer *b) {
++ force_assert(NULL != a && NULL != b);
++
+ if (a->used != b->used) return 0;
+ if (a->used == 0) return 1;
+
+- return (0 == strcmp(a->ptr, b->ptr));
++ return (0 == memcmp(a->ptr, b->ptr, a->used));
+ }
+
+ int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
+- buffer b;
++ force_assert(NULL != a && NULL != s);
++ force_assert(b_len + 1 > b_len);
+
+- b.ptr = (char *)s;
+- b.used = b_len + 1;
++ if (a->used != b_len + 1) return 0;
++ if (0 != memcmp(a->ptr, s, b_len)) return 0;
++ if ('\0' != a->ptr[a->used-1]) return 0;
+
+- return buffer_is_equal(a, &b);
++ return 1;
+ }
+
+ /* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */
+ int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len) {
++ force_assert(NULL != a);
+ if (a->used != b_len + 1) return 0;
++ force_assert('\0' == a->ptr[a->used - 1]);
+
+ return (0 == strcasecmp(a->ptr, s));
+ }
+@@ -554,30 +416,18 @@ int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b
+ if (ca == cb) continue;
+
+ /* always lowercase for transitive results */
+-#if 1
+ if (ca >= 'A' && ca <= 'Z') ca |= 32;
+ if (cb >= 'A' && cb <= 'Z') cb |= 32;
+-#else
+- /* try to produce code without branching (jumps) */
+- ca |= ((unsigned char)(ca - (unsigned char)'A') <= (unsigned char)('Z' - 'A')) ? 32 : 0;
+- cb |= ((unsigned char)(cb - (unsigned char)'A') <= (unsigned char)('Z' - 'A')) ? 32 : 0;
+-#endif
+
+ if (ca == cb) continue;
+ return ca - cb;
+ }
+ if (a_len == b_len) return 0;
+- return a_len - b_len;
++ return a_len < b_len ? -1 : 1;
+ }
+
+-/**
+- * check if the rightmost bytes of the string are equal.
+- *
+- *
+- */
+-
+ int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
+- /* no, len -> equal */
++ /* no len -> equal */
+ if (len == 0) return 1;
+
+ /* len > 0, but empty buffers -> not equal */
+@@ -586,29 +436,23 @@ int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
+ /* buffers too small -> not equal */
+ if (b1->used - 1 < len || b2->used - 1 < len) return 0;
+
+- if (0 == strncmp(b1->ptr + b1->used - 1 - len,
+- b2->ptr + b2->used - 1 - len, len)) {
+- return 1;
+- }
+-
+- return 0;
++ return 0 == memcmp(b1->ptr + b1->used - 1 - len, b2->ptr + b2->used - 1 - len, len);
+ }
+
+-int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
++void buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
+ size_t i;
+
+- /* BO protection */
+- if (in_len * 2 < in_len) return -1;
++ /* overflow protection */
++ force_assert(in_len * 2 + 1 > in_len);
+
+- buffer_prepare_copy(b, in_len * 2 + 1);
++ buffer_prepare_copy(b, in_len * 2);
+
++ b->used = 0;
+ for (i = 0; i < in_len; i++) {
+ b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
+ b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
+ }
+ b->ptr[b->used++] = '\0';
+-
+- return 0;
+ }
+
+ /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
+@@ -747,18 +591,15 @@ static const char encoded_chars_http_header[] = {
+
+
+
+-int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
++void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
+ unsigned char *ds, *d;
+ size_t d_len, ndx;
+ const char *map = NULL;
+
+- if (!s || !b) return -1;
+-
+- if (b->ptr[b->used - 1] != '\0') {
+- SEGFAULT();
+- }
++ force_assert(NULL != b);
++ force_assert(NULL != s || 0 == s_len);
+
+- if (s_len == 0) return 0;
++ if (0 == s_len) return;
+
+ switch(encoding) {
+ case ENCODING_REL_URI:
+@@ -779,11 +620,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
+ case ENCODING_HTTP_HEADER:
+ map = encoded_chars_http_header;
+ break;
+- case ENCODING_UNSET:
+- break;
+ }
+
+- force_assert(map != NULL);
++ force_assert(NULL != map);
+
+ /* count to-be-encoded-characters */
+ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
+@@ -801,17 +640,17 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
+ case ENCODING_HEX:
+ d_len += 2;
+ break;
+- case ENCODING_UNSET:
+- break;
+ }
+ } else {
+- d_len ++;
++ d_len++;
+ }
+ }
+
+- buffer_prepare_append(b, d_len);
++ d = (unsigned char*) buffer_prepare_append(b, d_len);
++ buffer_commit(b, d_len); /* fill below */
++ force_assert('\0' == *d);
+
+- for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
++ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
+ if (map[*ds]) {
+ switch(encoding) {
+ case ENCODING_REL_URI:
+@@ -837,20 +676,11 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
+ d[d_len++] = *ds;
+ d[d_len++] = '\t';
+ break;
+- case ENCODING_UNSET:
+- break;
+ }
+ } else {
+ d[d_len++] = *ds;
+ }
+ }
+-
+- /* terminate buffer and calculate new length */
+- b->ptr[b->used + d_len - 1] = '\0';
+-
+- b->used += d_len;
+-
+- return 0;
+ }
+
+
+@@ -858,26 +688,35 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
+ * replaces non-printable characters with '_'
+ */
+
+-static int buffer_urldecode_internal(buffer *url, int is_query) {
++static void buffer_urldecode_internal(buffer *url, int is_query) {
+ unsigned char high, low;
+- const char *src;
++ char *src;
+ char *dst;
+
+- if (!url || !url->ptr) return -1;
++ force_assert(NULL != url);
++ if (buffer_string_is_empty(url)) return;
++
++ force_assert('\0' == url->ptr[url->used-1]);
+
+- src = (const char*) url->ptr;
+- dst = (char*) url->ptr;
++ src = (char*) url->ptr;
+
+- while ((*src) != '\0') {
++ while ('\0' != *src) {
++ if ('%' == *src) break;
++ if (is_query && '+' == *src) *src = ' ';
++ src++;
++ }
++ dst = src;
++
++ while ('\0' != *src) {
+ if (is_query && *src == '+') {
+ *dst = ' ';
+ } else if (*src == '%') {
+ *dst = '%';
+
+ high = hex2int(*(src + 1));
+- if (high != 0xFF) {
++ if (0xFF != high) {
+ low = hex2int(*(src + 2));
+- if (low != 0xFF) {
++ if (0xFF != low) {
+ high = (high << 4) | low;
+
+ /* map control-characters out */
+@@ -897,19 +736,19 @@ static int buffer_urldecode_internal(buffer *url, int is_query) {
+
+ *dst = '\0';
+ url->used = (dst - url->ptr) + 1;
+-
+- return 0;
+ }
+
+-int buffer_urldecode_path(buffer *url) {
+- return buffer_urldecode_internal(url, 0);
++void buffer_urldecode_path(buffer *url) {
++ buffer_urldecode_internal(url, 0);
+ }
+
+-int buffer_urldecode_query(buffer *url) {
+- return buffer_urldecode_internal(url, 1);
++void buffer_urldecode_query(buffer *url) {
++ buffer_urldecode_internal(url, 1);
+ }
+
+-/* Remove "/../", "//", "/./" parts from path.
++/* Remove "/../", "//", "/./" parts from path,
++ * strips leading spaces,
++ * prepends "/" if not present already
+ *
+ * /blah/.. gets /
+ * /blah/../foo gets /foo
+@@ -920,20 +759,38 @@ int buffer_urldecode_query(buffer *url) {
+ * the operation is performed in-place.
+ */
+
+-int buffer_path_simplify(buffer *dest, buffer *src)
++void buffer_path_simplify(buffer *dest, buffer *src)
+ {
+ int toklen;
+ char c, pre1;
+ char *start, *slash, *walk, *out;
+ unsigned short pre;
+
+- if (src == NULL || src->ptr == NULL || dest == NULL)
+- return -1;
++ force_assert(NULL != dest && NULL != src);
+
+- if (src == dest)
++ if (buffer_string_is_empty(src)) {
++ buffer_copy_string_len(dest, NULL, 0);
++ return;
++ }
++
++ force_assert('\0' == src->ptr[src->used-1]);
++
++ /* might need one character more for the '/' prefix */
++ if (src == dest) {
+ buffer_prepare_append(dest, 1);
+- else
+- buffer_prepare_copy(dest, src->used + 1);
++ } else {
++ buffer_prepare_copy(dest, buffer_string_length(src) + 1);
++ }
++
++#if defined(__WIN32) || defined(__CYGWIN__)
++ /* cygwin is treating \ and / the same, so we have to that too */
++ {
++ char *p;
++ for (p = src->ptr; *p; p++) {
++ if (*p == '\\') *p = '/';
++ }
++ }
++#endif
+
+ walk = src->ptr;
+ start = dest->ptr;
+@@ -941,16 +798,6 @@ int buffer_path_simplify(buffer *dest, buffer *src)
+ slash = dest->ptr;
+
+
+-#if defined(__WIN32) || defined(__CYGWIN__)
+- /* cygwin is treating \ and / the same, so we have to that too
+- */
+-
+- for (walk = src->ptr; *walk; walk++) {
+- if (*walk == '\\') *walk = '/';
+- }
+- walk = src->ptr;
+-#endif
+-
+ while (*walk == ' ') {
+ walk++;
+ }
+@@ -966,34 +813,29 @@ int buffer_path_simplify(buffer *dest, buffer *src)
+
+ if (pre1 == '\0') {
+ dest->used = (out - start) + 1;
+- return 0;
++ return;
+ }
+
+- while (1) {
++ for (;;) {
+ if (c == '/' || c == '\0') {
+ toklen = out - slash;
+ if (toklen == 3 && pre == (('.' << 8) | '.')) {
+ out = slash;
+ if (out > start) {
+ out--;
+- while (out > start && *out != '/') {
+- out--;
+- }
++ while (out > start && *out != '/') out--;
+ }
+
+- if (c == '\0')
+- out++;
++ if (c == '\0') out++;
+ } else if (toklen == 1 || pre == (('/' << 8) | '.')) {
+ out = slash;
+- if (c == '\0')
+- out++;
++ if (c == '\0') out++;
+ }
+
+ slash = out;
+ }
+
+- if (c == '\0')
+- break;
++ if (c == '\0') break;
+
+ pre1 = c;
+ pre = (pre << 8) | pre1;
+@@ -1006,8 +848,6 @@ int buffer_path_simplify(buffer *dest, buffer *src)
+
+ *out = '\0';
+ dest->used = (out - start) + 1;
+-
+- return 0;
+ }
+
+ int light_isdigit(int c) {
+@@ -1030,33 +870,23 @@ int light_isalnum(int c) {
+ return light_isdigit(c) || light_isalpha(c);
+ }
+
+-int buffer_to_lower(buffer *b) {
+- char *c;
+-
+- if (b->used == 0) return 0;
++void buffer_to_lower(buffer *b) {
++ size_t i;
+
+- for (c = b->ptr; *c; c++) {
+- if (*c >= 'A' && *c <= 'Z') {
+- *c |= 32;
+- }
++ for (i = 0; i < b->used; ++i) {
++ char c = b->ptr[i];
++ if (c >= 'A' && c <= 'Z') b->ptr[i] |= 0x20;
+ }
+-
+- return 0;
+ }
+
+
+-int buffer_to_upper(buffer *b) {
+- char *c;
+-
+- if (b->used == 0) return 0;
++void buffer_to_upper(buffer *b) {
++ size_t i;
+
+- for (c = b->ptr; *c; c++) {
+- if (*c >= 'a' && *c <= 'z') {
+- *c &= ~32;
+- }
++ for (i = 0; i < b->used; ++i) {
++ char c = b->ptr[i];
++ if (c >= 'A' && c <= 'Z') b->ptr[i] &= ~0x20;
+ }
+-
+- return 0;
+ }
+
+ #ifdef HAVE_LIBUNWIND
+diff --git a/src/buffer.h b/src/buffer.h
+index d2f5985..ff57d68 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -11,74 +11,96 @@
+ #include <sys/types.h>
+ #include <stdio.h>
+
++#if defined HAVE_STDINT_H
++# include <stdint.h>
++#elif defined HAVE_INTTYPES_H
++# include <inttypes.h>
++#endif
++
++/* generic string + binary data container; contains a terminating 0 in both
++ * cases
++ *
++ * used == 0 indicates a special "empty" state (unset config values); ptr
++ * might be NULL too then. otherwise an empty string has used == 1 (and ptr[0]
++ * == 0);
++ *
++ * copy/append functions will ensure used >= 1 (i.e. never leave it in the
++ * special empty state); only buffer_copy_buffer will copy the special empty
++ * state.
++ */
+ typedef struct {
+ char *ptr;
+
++ /* "used" includes a terminating 0 */
+ size_t used;
++ /* size of allocated buffer at *ptr */
+ size_t size;
+ } buffer;
+
+-typedef struct {
+- buffer **ptr;
+-
+- size_t used;
+- size_t size;
+-} buffer_array;
+-
+-typedef struct {
+- char *ptr;
+-
+- size_t offset; /* input-pointer */
+-
+- size_t used; /* output-pointer */
+- size_t size;
+-} read_buffer;
+-
+-buffer_array* buffer_array_init(void);
+-void buffer_array_free(buffer_array *b);
+-void buffer_array_reset(buffer_array *b);
+-buffer *buffer_array_append_get_buffer(buffer_array *b);
+-
++/* create new buffer; either empty or copy given data */
+ buffer* buffer_init(void);
+-buffer* buffer_init_buffer(buffer *b);
+-buffer* buffer_init_string(const char *str);
+-void buffer_free(buffer *b);
+-void buffer_reset(buffer *b);
+-
+-int buffer_prepare_copy(buffer *b, size_t size);
+-int buffer_prepare_append(buffer *b, size_t size);
+-
+-int buffer_copy_string(buffer *b, const char *s);
+-int buffer_copy_string_len(buffer *b, const char *s, size_t s_len);
+-int buffer_copy_string_buffer(buffer *b, const buffer *src);
+-int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len);
+-
+-int buffer_copy_long(buffer *b, long val);
+-
+-int buffer_copy_memory(buffer *b, const char *s, size_t s_len);
+-
+-int buffer_append_string(buffer *b, const char *s);
+-int buffer_append_string_len(buffer *b, const char *s, size_t s_len);
+-int buffer_append_string_buffer(buffer *b, const buffer *src);
+-int buffer_append_string_lfill(buffer *b, const char *s, size_t maxlen);
+-int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen);
+-
+-int buffer_append_long_hex(buffer *b, unsigned long len);
+-int buffer_append_long(buffer *b, long val);
+-
+-#if defined(SIZEOF_LONG) && (SIZEOF_LONG == SIZEOF_OFF_T)
+-#define buffer_copy_off_t(x, y) buffer_copy_long(x, y)
+-#define buffer_append_off_t(x, y) buffer_append_long(x, y)
+-#else
+-int buffer_copy_off_t(buffer *b, off_t val);
+-int buffer_append_off_t(buffer *b, off_t val);
+-#endif
+-
+-int buffer_append_memory(buffer *b, const char *s, size_t s_len);
++buffer* buffer_init_buffer(const buffer *src); /* src can be NULL */
++buffer* buffer_init_string(const char *str); /* str can be NULL */
++
++void buffer_free(buffer *b); /* b can be NULL */
++/* truncates to used == 0; frees large buffers, might keep smaller ones for reuse */
++void buffer_reset(buffer *b); /* b can be NULL */
++
++/* reset b. if NULL != b && NULL != src, move src content to b. reset src. */
++void buffer_move(buffer *b, buffer *src);
++
++/* prepare for size bytes in the buffer (b->size > size), destroys content
++ * (sets used = 0 and ptr[0] = 0). allocates storage for terminating 0.
++ * @return b->ptr
++ */
++char* buffer_prepare_copy(buffer *b, size_t size);
++
++/* prepare for appending size bytes to the buffer
++ * allocates storage for terminating 0; if used > 0 assumes ptr[used-1] == 0,
++ * i.e. doesn't allocate another byte for terminating 0.
++ * @return (b->used > 0 ? b->ptr + b->used - 1 : b->ptr) - first new character
++ */
++char* buffer_prepare_append(buffer *b, size_t size);
++
++/* use after prepare_(copy,append) when you have written data to the buffer
++ * to increase the buffer length by size. also sets the terminating zero.
++ * requires enough space is present for the terminating zero (prepare with the
++ * same size to be sure).
++ */
++void buffer_commit(buffer *b, size_t size);
++
++void buffer_copy_string(buffer *b, const char *s);
++void buffer_copy_string_len(buffer *b, const char *s, size_t s_len);
++void buffer_copy_buffer(buffer *b, const buffer *src);
++/* convert input to hex and store in buffer */
++void buffer_copy_string_hex(buffer *b, const char *in, size_t in_len);
++
++void buffer_append_string(buffer *b, const char *s);
++void buffer_append_string_len(buffer *b, const char *s, size_t s_len);
++void buffer_append_string_buffer(buffer *b, const buffer *src);
++
++void buffer_append_long_hex(buffer *b, unsigned long len);
++void buffer_append_int(buffer *b, intmax_t val);
++void buffer_copy_int(buffer *b, intmax_t val);
++
++/* '-', log_10 (2^bits) = bits * log 2 / log 10 < bits * 0.31, terminating 0 */
++#define LI_ITOSTRING_LENGTH (2 + (8 * sizeof(intmax_t) * 31 + 99) / 100)
++
++void li_itostrn(char *buf, size_t buf_len, intmax_t val);
++void li_itostr(char *buf, intmax_t val); /* buf must have at least LI_ITOSTRING_LENGTH bytes */
++void li_utostrn(char *buf, size_t buf_len, uintmax_t val);
++void li_utostr(char *buf, uintmax_t val); /* buf must have at least LI_ITOSTRING_LENGTH bytes */
+
+ char * buffer_search_string_len(buffer *b, const char *needle, size_t len);
+
++/* NULL buffer or empty buffer (used == 0);
++ * unset "string" (buffer) config options are initialized to used == 0,
++ * while setting an empty string leads to used == 1
++ */
+ int buffer_is_empty(buffer *b);
++/* NULL buffer, empty buffer (used == 0) or empty string (used == 1) */
++int buffer_string_is_empty(buffer *b);
++
+ int buffer_is_equal(buffer *a, buffer *b);
+ int buffer_is_equal_right_len(buffer *a, buffer *b, size_t len);
+ int buffer_is_equal_string(buffer *a, const char *s, size_t b_len);
+@@ -86,7 +108,6 @@ int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len);
+ int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len);
+
+ typedef enum {
+- ENCODING_UNSET,
+ ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
+ ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
+ ENCODING_HTML, /* & becomes &amp; and so on */
+@@ -95,17 +116,17 @@ typedef enum {
+ ENCODING_HTTP_HEADER /* encode \n with \t\n */
+ } buffer_encoding_t;
+
+-int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
++void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
++
++void buffer_urldecode_path(buffer *url);
++void buffer_urldecode_query(buffer *url);
++void buffer_path_simplify(buffer *dest, buffer *src);
+
+-int buffer_urldecode_path(buffer *url);
+-int buffer_urldecode_query(buffer *url);
+-int buffer_path_simplify(buffer *dest, buffer *src);
++void buffer_to_lower(buffer *b);
++void buffer_to_upper(buffer *b);
+
+-int buffer_to_lower(buffer *b);
+-int buffer_to_upper(buffer *b);
+
+ /** deprecated */
+-int LI_ltostr(char *buf, long val);
+ char hex2int(unsigned char c);
+ char int2hex(char i);
+
+@@ -114,17 +135,17 @@ int light_isxdigit(int c);
+ int light_isalpha(int c);
+ int light_isalnum(int c);
+
++static inline size_t buffer_string_length(const buffer *b); /* buffer string length without terminating 0 */
++static inline void buffer_append_slash(buffer *b); /* append '/' no non-empty strings not ending in '/' */
++
+ #define BUFFER_APPEND_STRING_CONST(x, y) \
+ buffer_append_string_len(x, y, sizeof(y) - 1)
+
+ #define BUFFER_COPY_STRING_CONST(x, y) \
+ buffer_copy_string_len(x, y, sizeof(y) - 1)
+
+-#define BUFFER_APPEND_SLASH(x) \
+- if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
+-
+-#define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
+-#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
++#define CONST_STR_LEN(x) x, (x) ? sizeof(x) - 1 : 0
++#define CONST_BUF_LEN(x) (x)->ptr, buffer_string_length(x)
+
+
+ #define UNUSED(x) ( (void)(x) )
+@@ -134,4 +155,15 @@ void log_failed_assert(const char *filename, unsigned int line, const char *msg)
+ #define force_assert(x) do { if (!(x)) log_failed_assert(__FILE__, __LINE__, "assertion failed: " #x); } while(0)
+ #define SEGFAULT() log_failed_assert(__FILE__, __LINE__, "aborted");
+
++/* inline implementations */
++
++static inline size_t buffer_string_length(const buffer *b) {
++ return NULL != b && 0 != b->used ? b->used - 1 : 0;
++}
++
++static inline void buffer_append_slash(buffer *b) {
++ size_t len = buffer_string_length(b);
++ if (len > 0 && '/' != b->ptr[len-1]) BUFFER_APPEND_STRING_CONST(b, "/");
++}
++
+ #endif
+diff --git a/src/chunk.c b/src/chunk.c
+index 7583db6..c991b82 100644
+--- a/src/chunk.c
++++ b/src/chunk.c
+@@ -36,30 +36,28 @@ static chunk *chunk_init(void) {
+
+ c = calloc(1, sizeof(*c));
+
++ c->type = MEM_CHUNK;
+ c->mem = buffer_init();
+ c->file.name = buffer_init();
++ c->file.start = c->file.length = c->file.mmap.offset = 0;
+ c->file.fd = -1;
+ c->file.mmap.start = MAP_FAILED;
++ c->file.mmap.length = 0;
++ c->file.is_temp = 0;
++ c->offset = 0;
+ c->next = NULL;
+
+ return c;
+ }
+
+-static void chunk_free(chunk *c) {
+- if (!c) return;
+-
+- buffer_free(c->mem);
+- buffer_free(c->file.name);
+-
+- free(c);
+-}
+-
+ static void chunk_reset(chunk *c) {
+- if (!c) return;
++ if (NULL == c) return;
++
++ c->type = MEM_CHUNK;
+
+ buffer_reset(c->mem);
+
+- if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
++ if (c->file.is_temp && !buffer_string_is_empty(c->file.name)) {
+ unlink(c->file.name->ptr);
+ }
+
+@@ -73,13 +71,28 @@ static void chunk_reset(chunk *c) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ }
++ c->file.start = c->file.length = c->file.mmap.offset = 0;
++ c->file.mmap.length = 0;
++ c->file.is_temp = 0;
++ c->offset = 0;
++ c->next = NULL;
+ }
+
++static void chunk_free(chunk *c) {
++ if (NULL == c) return;
++
++ chunk_reset(c);
++
++ buffer_free(c->mem);
++ buffer_free(c->file.name);
++
++ free(c);
++}
+
+ void chunkqueue_free(chunkqueue *cq) {
+ chunk *c, *pc;
+
+- if (!cq) return;
++ if (NULL == cq) return;
+
+ for (c = cq->first; c; ) {
+ pc = c;
+@@ -96,11 +109,27 @@ void chunkqueue_free(chunkqueue *cq) {
+ free(cq);
+ }
+
++static void chunkqueue_push_unused_chunk(chunkqueue *cq, chunk *c) {
++ force_assert(NULL != cq && NULL != c);
++
++ /* keep at max 4 chunks in the 'unused'-cache */
++ if (cq->unused_chunks > 4) {
++ chunk_free(c);
++ } else {
++ chunk_reset(c);
++ c->next = cq->unused;
++ cq->unused = c;
++ cq->unused_chunks++;
++ }
++}
++
+ static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
+ chunk *c;
+
++ force_assert(NULL != cq);
++
+ /* check if we have a unused chunk */
+- if (!cq->unused) {
++ if (0 == cq->unused) {
+ c = chunk_init();
+ } else {
+ /* take the first element from the list (a stack) */
+@@ -113,130 +142,95 @@ static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
+ return c;
+ }
+
+-static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
++static void chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
+ c->next = cq->first;
+ cq->first = c;
+
+- if (cq->last == NULL) {
++ if (NULL == cq->last) {
+ cq->last = c;
+ }
+-
+- return 0;
+ }
+
+-static int chunkqueue_append_chunk(chunkqueue *cq, chunk *c) {
++static void chunkqueue_append_chunk(chunkqueue *cq, chunk *c) {
+ if (cq->last) {
+ cq->last->next = c;
+ }
+ cq->last = c;
+
+- if (cq->first == NULL) {
++ if (NULL == cq->first) {
+ cq->first = c;
+ }
+-
+- return 0;
+ }
+
+ void chunkqueue_reset(chunkqueue *cq) {
+- chunk *c;
+- /* move everything to the unused queue */
++ chunk *cur = cq->first;
+
+- /* mark all read written */
+- for (c = cq->first; c; c = c->next) {
+- switch(c->type) {
+- case MEM_CHUNK:
+- c->offset = c->mem->used - 1;
+- break;
+- case FILE_CHUNK:
+- c->offset = c->file.length;
+- break;
+- default:
+- break;
+- }
++ cq->first = cq->last = NULL;
++
++ while (NULL != cur) {
++ chunk *next = cur->next;
++ chunkqueue_push_unused_chunk(cq, cur);
++ cur = next;
+ }
+
+- chunkqueue_remove_finished_chunks(cq);
+ cq->bytes_in = 0;
+ cq->bytes_out = 0;
+ }
+
+-int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
++void chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
+ chunk *c;
+
+- if (len == 0) return 0;
++ if (0 == len) return;
+
+ c = chunkqueue_get_unused_chunk(cq);
+
+ c->type = FILE_CHUNK;
+
+- buffer_copy_string_buffer(c->file.name, fn);
++ buffer_copy_buffer(c->file.name, fn);
+ c->file.start = offset;
+ c->file.length = len;
+ c->offset = 0;
+
+ chunkqueue_append_chunk(cq, c);
+-
+- return 0;
+ }
+
+-int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
++void chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
+ chunk *c;
+
+- if (mem->used == 0) return 0;
+-
+- c = chunkqueue_get_unused_chunk(cq);
+- c->type = MEM_CHUNK;
+- c->offset = 0;
+- buffer_copy_string_buffer(c->mem, mem);
+-
+- chunkqueue_append_chunk(cq, c);
+-
+- return 0;
+-}
+-
+-int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) {
+- chunk *c;
++ if (buffer_string_is_empty(mem)) return;
+
+ c = chunkqueue_get_unused_chunk(cq);
+ c->type = MEM_CHUNK;
+- c->offset = 0;
+- if (c->mem) buffer_free(c->mem);
+- c->mem = mem;
++ force_assert(NULL != c->mem);
++ buffer_move(c->mem, mem);
+
+ chunkqueue_append_chunk(cq, c);
+-
+- return 0;
+ }
+
+-int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
++void chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
+ chunk *c;
+
+- if (mem->used == 0) return 0;
++ if (buffer_string_is_empty(mem)) return;
+
+ c = chunkqueue_get_unused_chunk(cq);
+ c->type = MEM_CHUNK;
+- c->offset = 0;
+- buffer_copy_string_buffer(c->mem, mem);
++ force_assert(NULL != c->mem);
++ buffer_move(c->mem, mem);
+
+ chunkqueue_prepend_chunk(cq, c);
+-
+- return 0;
+ }
+
+
+-int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
++void chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
+ chunk *c;
+
+- if (len == 0) return 0;
++ if (0 == len) return;
+
+ c = chunkqueue_get_unused_chunk(cq);
+ c->type = MEM_CHUNK;
+- c->offset = 0;
+- buffer_copy_string_len(c->mem, mem, len - 1);
++ buffer_copy_string_len(c->mem, mem, len);
+
+ chunkqueue_append_chunk(cq, c);
+-
+- return 0;
+ }
+
+ buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
+@@ -245,8 +239,6 @@ buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
+ c = chunkqueue_get_unused_chunk(cq);
+
+ c->type = MEM_CHUNK;
+- c->offset = 0;
+- buffer_reset(c->mem);
+
+ chunkqueue_prepend_chunk(cq, c);
+
+@@ -259,20 +251,15 @@ buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
+ c = chunkqueue_get_unused_chunk(cq);
+
+ c->type = MEM_CHUNK;
+- c->offset = 0;
+- buffer_reset(c->mem);
+
+ chunkqueue_append_chunk(cq, c);
+
+ return c->mem;
+ }
+
+-int chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
+- if (!cq) return -1;
+-
++void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
++ force_assert(NULL != cq);
+ cq->tempdirs = tempdirs;
+-
+- return 0;
+ }
+
+ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+@@ -282,7 +269,6 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+ c = chunkqueue_get_unused_chunk(cq);
+
+ c->type = FILE_CHUNK;
+- c->offset = 0;
+
+ if (cq->tempdirs && cq->tempdirs->used) {
+ size_t i;
+@@ -292,8 +278,8 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+ for (i = 0; i < cq->tempdirs->used; i++) {
+ data_string *ds = (data_string *)cq->tempdirs->data[i];
+
+- buffer_copy_string_buffer(template, ds->value);
+- BUFFER_APPEND_SLASH(template);
++ buffer_copy_buffer(template, ds->value);
++ buffer_append_slash(template);
+ buffer_append_string_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX"));
+
+ if (-1 != (c->file.fd = mkstemp(template->ptr))) {
+@@ -309,7 +295,7 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+ }
+ }
+
+- buffer_copy_string_buffer(c->file.name, template);
++ buffer_copy_buffer(c->file.name, template);
+ c->file.length = 0;
+
+ chunkqueue_append_chunk(cq, c);
+@@ -319,82 +305,102 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+ return c;
+ }
+
++void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) {
++ while (len > 0) {
++ chunk *c = src->first;
++ off_t clen = 0;
+
+-off_t chunkqueue_length(chunkqueue *cq) {
+- off_t len = 0;
+- chunk *c;
++ if (NULL == c) break;
+
+- for (c = cq->first; c; c = c->next) {
+ switch (c->type) {
+ case MEM_CHUNK:
+- len += c->mem->used ? c->mem->used - 1 : 0;
++ clen = buffer_string_length(c->mem);
+ break;
+ case FILE_CHUNK:
+- len += c->file.length;
++ clen = c->file.length;
+ break;
+- default:
++ }
++ force_assert(clen >= c->offset);
++ clen -= c->offset;
++
++ if (len >= clen) {
++ /* move complete chunk */
++ src->first = c->next;
++ if (c == src->last) src->last = NULL;
++
++ chunkqueue_append_chunk(dest, c);
++ src->bytes_out += clen;
++ dest->bytes_in += clen;
++ len -= clen;
++ continue;
++ }
++
++ /* partial chunk with length "len" */
++
++ switch (c->type) {
++ case MEM_CHUNK:
++ chunkqueue_append_mem(dest, c->mem->ptr + c->offset, len);
++ break;
++ case FILE_CHUNK:
++ /* tempfile flag is in "last" chunk after the split */
++ chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, len);
+ break;
+ }
+- }
+
+- return len;
++ c->offset += len;
++ src->bytes_out += len;
++ dest->bytes_in += len;
++ len = 0;
++ }
+ }
+
+-off_t chunkqueue_written(chunkqueue *cq) {
++off_t chunkqueue_length(chunkqueue *cq) {
+ off_t len = 0;
+ chunk *c;
+
+ for (c = cq->first; c; c = c->next) {
++ off_t c_len = 0;
++
+ switch (c->type) {
+ case MEM_CHUNK:
+- case FILE_CHUNK:
+- len += c->offset;
++ c_len = buffer_string_length(c->mem);
+ break;
+- default:
++ case FILE_CHUNK:
++ c_len = c->file.length;
+ break;
+ }
++ force_assert(c_len >= c->offset);
++ len += c_len - c->offset;
+ }
+
+ return len;
+ }
+
+ int chunkqueue_is_empty(chunkqueue *cq) {
+- return cq->first ? 0 : 1;
++ return NULL == cq->first;
+ }
+
+-int chunkqueue_remove_finished_chunks(chunkqueue *cq) {
++void chunkqueue_remove_finished_chunks(chunkqueue *cq) {
+ chunk *c;
+
+ for (c = cq->first; c; c = cq->first) {
+- int is_finished = 0;
++ off_t c_len = 0;
+
+ switch (c->type) {
+ case MEM_CHUNK:
+- if (c->mem->used == 0 || (c->offset == (off_t)c->mem->used - 1)) is_finished = 1;
++ c_len = buffer_string_length(c->mem);
+ break;
+ case FILE_CHUNK:
+- if (c->offset == c->file.length) is_finished = 1;
+- break;
+- default:
++ c_len = c->file.length;
+ break;
+ }
++ force_assert(c_len >= c->offset);
+
+- if (!is_finished) break;
+-
+- chunk_reset(c);
++ if (c_len > c->offset) break; /* not finished yet */
+
+ cq->first = c->next;
+ if (c == cq->last) cq->last = NULL;
+
+- /* keep at max 4 chunks in the 'unused'-cache */
+- if (cq->unused_chunks > 4) {
+- chunk_free(c);
+- } else {
+- c->next = cq->unused;
+- cq->unused = c;
+- cq->unused_chunks++;
+- }
++ chunkqueue_push_unused_chunk(cq, c);
+ }
+-
+- return 0;
+ }
+diff --git a/src/chunk.h b/src/chunk.h
+index e43d3eb..6559000 100644
+--- a/src/chunk.h
++++ b/src/chunk.h
+@@ -6,7 +6,7 @@
+ #include "sys-mmap.h"
+
+ typedef struct chunk {
+- enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
++ enum { MEM_CHUNK, FILE_CHUNK } type;
+
+ buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
+
+@@ -48,21 +48,21 @@ typedef struct {
+ } chunkqueue;
+
+ chunkqueue *chunkqueue_init(void);
+-int chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs);
+-int chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len);
+-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_prepend_buffer(chunkqueue *c, buffer *mem);
++void chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs);
++void chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len); /* copies "fn" */
++void chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len); /* copies memory */
++void chunkqueue_append_buffer(chunkqueue *c, buffer *mem); /* may reset "mem" */
++void chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem); /* may reset "mem" */
+
+ buffer * chunkqueue_get_append_buffer(chunkqueue *c);
+ buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
+ chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
+
+-int chunkqueue_remove_finished_chunks(chunkqueue *cq);
++void chunkqueue_remove_finished_chunks(chunkqueue *cq);
++
++void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len);
+
+ off_t chunkqueue_length(chunkqueue *c);
+-off_t chunkqueue_written(chunkqueue *c);
+ void chunkqueue_free(chunkqueue *c);
+ void chunkqueue_reset(chunkqueue *c);
+
+diff --git a/src/configfile-glue.c b/src/configfile-glue.c
+index 9f24dcb..2fb8c62 100644
+--- a/src/configfile-glue.c
++++ b/src/configfile-glue.c
+@@ -46,12 +46,12 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
+ if (da->value->data[j]->type == TYPE_STRING) {
+ data_string *ds = data_string_init();
+
+- buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
++ buffer_copy_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
+ if (!da->is_index_key) {
+ /* the id's were generated automaticly, as we copy now we might have to renumber them
+ * this is used to prepend server.modules by mod_indexfile as it has to be loaded
+ * before mod_fastcgi and friends */
+- buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
++ buffer_copy_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
+ }
+
+ array_insert_unique(cv[i].destination, (data_unset *)ds);
+@@ -73,7 +73,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
+ if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+
+- buffer_copy_string_buffer(cv[i].destination, ds->value);
++ buffer_copy_buffer(cv[i].destination, ds->value);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
+
+@@ -202,7 +202,7 @@ int config_insert_values_global(server *srv, array *ca, const config_values_t cv
+ touched = data_string_init();
+
+ buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
+- buffer_copy_string_buffer(touched->key, du->key);
++ buffer_copy_buffer(touched->key, du->key);
+
+ array_insert_unique(srv->config_touched, (data_unset *)touched);
+ }
+@@ -285,7 +285,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
+ case COMP_HTTP_HOST: {
+ char *ck_colon = NULL, *val_colon = NULL;
+
+- if (!buffer_is_empty(con->uri.authority)) {
++ if (!buffer_string_is_empty(con->uri.authority)) {
+
+ /*
+ * append server-port to the HTTP_POST if necessary
+@@ -301,9 +301,9 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
+
+ if (NULL != ck_colon && NULL == val_colon) {
+ /* condition "host:port" but client send "host" */
+- buffer_copy_string_buffer(srv->cond_check_buf, l);
++ buffer_copy_buffer(srv->cond_check_buf, l);
+ buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
+- buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
++ buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
+ l = srv->cond_check_buf;
+ } else if (NULL != val_colon && NULL == ck_colon) {
+ /* condition "host" but client send "host:port" */
+@@ -315,7 +315,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
+ break;
+ }
+ #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+- } else if (!buffer_is_empty(con->tlsext_server_name)) {
++ } else if (!buffer_string_is_empty(con->tlsext_server_name)) {
+ l = con->tlsext_server_name;
+ #endif
+ } else {
+diff --git a/src/configfile.c b/src/configfile.c
+index bf9a34d..2b09d86 100644
+--- a/src/configfile.c
++++ b/src/configfile.c
+@@ -273,7 +273,7 @@ static int config_insert(server *srv) {
+ }
+ }
+
+- if (buffer_is_empty(stat_cache_string)) {
++ if (buffer_string_is_empty(stat_cache_string)) {
+ srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+ } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
+ srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+@@ -323,7 +323,7 @@ int config_setup_connection(server *srv, connection *con) {
+ PATCH(global_bytes_per_second_cnt);
+
+ con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
+- buffer_copy_string_buffer(con->server_name, s->server_name);
++ buffer_copy_buffer(con->server_name, s->server_name);
+
+ PATCH(log_request_header);
+ PATCH(log_response_header);
+@@ -442,7 +442,7 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
+ PATCH(follow_symlink);
+ #endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
+- buffer_copy_string_buffer(con->server_name, s->server_name);
++ buffer_copy_buffer(con->server_name, s->server_name);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
+ PATCH(server_tag);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connection.kbytes-per-second"))) {
+@@ -512,7 +512,7 @@ typedef struct {
+
+ #if 0
+ static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
+- if (buffer_is_empty(basedir) ||
++ if (buffer_string_is_empty(basedir) ||
+ (fn[0] == '/' || fn[0] == '\\') ||
+ (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
+ t->file = buffer_init_string(fn);
+@@ -934,7 +934,7 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
+ lasttoken = buffer_init();
+ token = buffer_init();
+ while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
+- buffer_copy_string_buffer(lasttoken, token);
++ buffer_copy_buffer(lasttoken, token);
+ configparser(pParser, token_id, token, context);
+
+ token = buffer_init();
+@@ -986,7 +986,7 @@ int config_parse_file(server *srv, config_t *context, const char *fn) {
+ int ret;
+ buffer *filename;
+
+- if (buffer_is_empty(context->basedir) ||
++ if (buffer_string_is_empty(context->basedir) ||
+ (fn[0] == '/' || fn[0] == '\\') ||
+ (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
+ filename = buffer_init_string(fn);
+@@ -1057,7 +1057,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
+ source = buffer_init_string(cmd);
+ out = buffer_init();
+
+- if (!buffer_is_empty(context->basedir)) {
++ if (!buffer_string_is_empty(context->basedir)) {
+ chdir(context->basedir->ptr);
+ }
+
+@@ -1173,7 +1173,7 @@ int config_read(server *srv, const char *fn) {
+
+ prepends = (data_array *)configparser_merge_data((data_unset *)prepends, (data_unset *)modules);
+ force_assert(NULL != prepends);
+- buffer_copy_string_buffer(prepends->key, modules->key);
++ buffer_copy_buffer(prepends->key, modules->key);
+ array_replace(srv->config, (data_unset *)prepends);
+ modules->free((data_unset *)modules);
+ modules = prepends;
+@@ -1255,7 +1255,7 @@ int config_set_defaults(server *srv) {
+ { FDEVENT_HANDLER_UNSET, NULL }
+ };
+
+- if (!buffer_is_empty(srv->srvconf.changeroot)) {
++ if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
+ if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.chroot doesn't exist:", srv->srvconf.changeroot);
+@@ -1268,14 +1268,14 @@ int config_set_defaults(server *srv) {
+ }
+ }
+
+- if (buffer_is_empty(s->document_root)) {
++ if (buffer_string_is_empty(s->document_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "a default document-root has to be set");
+
+ return -1;
+ }
+
+- buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
++ buffer_copy_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_lower(srv->tmp_buf);
+
+@@ -1288,7 +1288,7 @@ int config_set_defaults(server *srv) {
+ is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
+
+ /* lower-case existed, check upper-case */
+- buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
++ buffer_copy_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_upper(srv->tmp_buf);
+
+@@ -1356,7 +1356,7 @@ int config_set_defaults(server *srv) {
+ }
+
+ if (s->ssl_enabled) {
+- if (buffer_is_empty(s->ssl_pemfile)) {
++ if (buffer_string_is_empty(s->ssl_pemfile)) {
+ /* PEM file is require */
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+diff --git a/src/configparser.y b/src/configparser.y
+index efa4afd..e4a4f51 100644
+--- a/src/configparser.y
++++ b/src/configparser.y
+@@ -61,11 +61,11 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
+ if (op1->type != op2->type) {
+ if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
+ data_string *ds = (data_string *)op1;
+- buffer_append_long(ds->value, ((data_integer*)op2)->value);
++ buffer_append_int(ds->value, ((data_integer*)op2)->value);
+ return op1;
+ } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
+ data_string *ds = data_string_init();
+- buffer_append_long(ds->value, ((data_integer*)op1)->value);
++ buffer_append_int(ds->value, ((data_integer*)op1)->value);
+ buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
+ op1->free(op1);
+ return (data_unset *)ds;
+@@ -145,7 +145,7 @@ metaline ::= EOL.
+
+ varline ::= key(A) ASSIGN expression(B). {
+ if (ctx->ok) {
+- buffer_copy_string_buffer(B->key, A);
++ buffer_copy_buffer(B->key, A);
+ if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+@@ -183,7 +183,7 @@ varline ::= key(A) APPEND expression(B). {
+ ctx->ok = 0;
+ }
+ else {
+- buffer_copy_string_buffer(du->key, A);
++ buffer_copy_buffer(du->key, A);
+ array_replace(vars, du);
+ }
+ B->free(B);
+@@ -193,12 +193,12 @@ varline ::= key(A) APPEND expression(B). {
+ ctx->ok = 0;
+ }
+ else {
+- buffer_copy_string_buffer(du->key, A);
++ buffer_copy_buffer(du->key, A);
+ array_insert_unique(ctx->current->value, du);
+ }
+ B->free(B);
+ } else {
+- buffer_copy_string_buffer(B->key, A);
++ buffer_copy_buffer(B->key, A);
+ array_insert_unique(ctx->current->value, B);
+ }
+ buffer_free(A);
+@@ -262,7 +262,7 @@ value(A) ::= key(B). {
+
+ value(A) ::= STRING(B). {
+ A = (data_unset *)data_string_init();
+- buffer_copy_string_buffer(((data_string *)(A))->value, B);
++ buffer_copy_buffer(((data_string *)(A))->value, B);
+ buffer_free(B);
+ B = NULL;
+ }
+@@ -320,7 +320,7 @@ aelement(A) ::= expression(B). {
+ B = NULL;
+ }
+ aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
+- buffer_copy_string_buffer(C->key, B);
++ buffer_copy_buffer(C->key, B);
+ buffer_free(B);
+ B = NULL;
+
+@@ -405,7 +405,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
+ }
+
+ b = buffer_init();
+- buffer_copy_string_buffer(b, ctx->current->key);
++ buffer_copy_buffer(b, ctx->current->key);
+ buffer_append_string(b, "/");
+ buffer_append_string_buffer(b, B);
+ buffer_append_string_buffer(b, C);
+@@ -441,9 +441,9 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
+
+ dc = data_config_init();
+
+- buffer_copy_string_buffer(dc->key, b);
+- buffer_copy_string_buffer(dc->op, op);
+- buffer_copy_string_buffer(dc->comp_key, B);
++ buffer_copy_buffer(dc->key, b);
++ buffer_copy_buffer(dc->op, op);
++ buffer_copy_buffer(dc->comp_key, B);
+ buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
+ buffer_append_string_buffer(dc->comp_key, C);
+ buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
+@@ -546,7 +546,7 @@ stringop(A) ::= expression(B). {
+ A = buffer_init_buffer(((data_string*)B)->value);
+ } else if (B->type == TYPE_INTEGER) {
+ A = buffer_init();
+- buffer_copy_long(A, ((data_integer *)B)->value);
++ buffer_copy_int(A, ((data_integer *)B)->value);
+ } else {
+ fprintf(stderr, "operand must be string");
+ ctx->ok = 0;
+diff --git a/src/connections.c b/src/connections.c
+index fe683a2..bc770bf 100644
+--- a/src/connections.c
++++ b/src/connections.c
+@@ -212,7 +212,7 @@ static int connection_handle_read_ssl(server *srv, connection *con) {
+ b = chunkqueue_get_append_buffer(con->read_queue);
+ len = SSL_pending(con->ssl);
+ if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */
+- buffer_prepare_copy(b, len + 1);
++ buffer_prepare_copy(b, len);
+
+ /* overwrite everything with 0 */
+ memset(b->ptr, 0, b->size);
+@@ -362,7 +362,7 @@ static int connection_handle_read(server *srv, connection *con) {
+ } else {
+ if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
+ b = chunkqueue_get_append_buffer(con->read_queue);
+- buffer_prepare_copy(b, toread + 1);
++ buffer_prepare_copy(b, toread);
+ }
+
+ read_offset = (b->used == 0) ? 0 : b->used - 1;
+@@ -473,11 +473,11 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ buffer_reset(con->physical.path);
+
+ /* try to send static errorfile */
+- if (!buffer_is_empty(con->conf.errorfile_prefix)) {
++ if (!buffer_string_is_empty(con->conf.errorfile_prefix)) {
+ stat_cache_entry *sce = NULL;
+
+- buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
+- buffer_append_long(con->physical.path, con->http_status);
++ buffer_copy_buffer(con->physical.path, con->conf.errorfile_prefix);
++ buffer_append_int(con->physical.path, con->http_status);
+ buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
+
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+@@ -504,7 +504,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
+ " <head>\n"
+ " <title>"));
+- buffer_append_long(b, con->http_status);
++ buffer_append_int(b, con->http_status);
+ buffer_append_string_len(b, CONST_STR_LEN(" - "));
+ buffer_append_string(b, get_http_status_name(con->http_status));
+
+@@ -513,7 +513,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ " </head>\n"
+ " <body>\n"
+ " <h1>"));
+- buffer_append_long(b, con->http_status);
++ buffer_append_int(b, con->http_status);
+ buffer_append_string_len(b, CONST_STR_LEN(" - "));
+ buffer_append_string(b, get_http_status_name(con->http_status));
+
+@@ -554,7 +554,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ /* qlen = 0 is important for Redirects (301, ...) as they MAY have
+ * a content. Browsers are waiting for a Content otherwise
+ */
+- buffer_copy_off_t(srv->tmp_buf, qlen);
++ buffer_copy_int(srv->tmp_buf, qlen);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
+ }
+@@ -1135,7 +1135,7 @@ found_header_end:
+ } else {
+ b = chunkqueue_get_append_buffer(dst_cq);
+ /* prepare buffer size for remaining POST data; is < 64kb */
+- buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in + 1);
++ buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in);
+ }
+ buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
+ }
+@@ -1430,17 +1430,17 @@ int connection_state_machine(server *srv, connection *con) {
+ /* 404 error-handler */
+
+ if (con->in_error_handler == 0 &&
+- (!buffer_is_empty(con->conf.error_handler) ||
+- !buffer_is_empty(con->error_handler))) {
++ (!buffer_string_is_empty(con->conf.error_handler) ||
++ !buffer_string_is_empty(con->error_handler))) {
+ /* call error-handler */
+
+ con->error_handler_saved_status = con->http_status;
+ con->http_status = 0;
+
+- if (buffer_is_empty(con->error_handler)) {
+- buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
++ if (buffer_string_is_empty(con->error_handler)) {
++ buffer_copy_buffer(con->request.uri, con->conf.error_handler);
+ } else {
+- buffer_copy_string_buffer(con->request.uri, con->error_handler);
++ buffer_copy_buffer(con->request.uri, con->error_handler);
+ }
+ buffer_reset(con->physical.path);
+
+diff --git a/src/data_array.c b/src/data_array.c
+index 094d8c0..ad96207 100644
+--- a/src/data_array.c
++++ b/src/data_array.c
+@@ -8,7 +8,7 @@ static data_unset *data_array_copy(const data_unset *s) {
+ data_array *src = (data_array *)s;
+ data_array *ds = data_array_init();
+
+- buffer_copy_string_buffer(ds->key, src->key);
++ buffer_copy_buffer(ds->key, src->key);
+ array_free(ds->value);
+ ds->value = array_init_array(src->value);
+ ds->is_index_key = src->is_index_key;
+diff --git a/src/data_config.c b/src/data_config.c
+index 80e38de..b05ba20 100644
+--- a/src/data_config.c
++++ b/src/data_config.c
+@@ -8,8 +8,8 @@ static data_unset *data_config_copy(const data_unset *s) {
+ data_config *src = (data_config *)s;
+ data_config *ds = data_config_init();
+
+- buffer_copy_string_buffer(ds->key, src->key);
+- buffer_copy_string_buffer(ds->comp_key, src->comp_key);
++ buffer_copy_buffer(ds->key, src->key);
++ buffer_copy_buffer(ds->comp_key, src->comp_key);
+ array_free(ds->value);
+ ds->value = array_init_array(src->value);
+ return (data_unset *)ds;
+diff --git a/src/data_count.c b/src/data_count.c
+index 8d36c8b..0337224 100644
+--- a/src/data_count.c
++++ b/src/data_count.c
+@@ -8,7 +8,7 @@ static data_unset *data_count_copy(const data_unset *s) {
+ data_count *src = (data_count *)s;
+ data_count *ds = data_count_init();
+
+- buffer_copy_string_buffer(ds->key, src->key);
++ buffer_copy_buffer(ds->key, src->key);
+ ds->count = src->count;
+ ds->is_index_key = src->is_index_key;
+ return (data_unset *)ds;
+diff --git a/src/data_fastcgi.c b/src/data_fastcgi.c
+index e13a470..a312506 100644
+--- a/src/data_fastcgi.c
++++ b/src/data_fastcgi.c
+@@ -9,8 +9,8 @@ static data_unset *data_fastcgi_copy(const data_unset *s) {
+ data_fastcgi *src = (data_fastcgi *)s;
+ data_fastcgi *ds = data_fastcgi_init();
+
+- buffer_copy_string_buffer(ds->key, src->key);
+- buffer_copy_string_buffer(ds->host, src->host);
++ buffer_copy_buffer(ds->key, src->key);
++ buffer_copy_buffer(ds->host, src->host);
+ ds->is_index_key = src->is_index_key;
+ return (data_unset *)ds;
+ }
+diff --git a/src/data_integer.c b/src/data_integer.c
+index 63cbb10..5cfe11b 100644
+--- a/src/data_integer.c
++++ b/src/data_integer.c
+@@ -8,7 +8,7 @@ static data_unset *data_integer_copy(const data_unset *s) {
+ data_integer *src = (data_integer *)s;
+ data_integer *ds = data_integer_init();
+
+- buffer_copy_string_buffer(ds->key, src->key);
++ buffer_copy_buffer(ds->key, src->key);
+ ds->is_index_key = src->is_index_key;
+ ds->value = src->value;
+ return (data_unset *)ds;
+diff --git a/src/data_string.c b/src/data_string.c
+index 41c9ec1..fc57de2 100644
+--- a/src/data_string.c
++++ b/src/data_string.c
+@@ -9,8 +9,8 @@ static data_unset *data_string_copy(const data_unset *s) {
+ data_string *src = (data_string *)s;
+ data_string *ds = data_string_init();
+
+- buffer_copy_string_buffer(ds->key, src->key);
+- buffer_copy_string_buffer(ds->value, src->value);
++ buffer_copy_buffer(ds->key, src->key);
++ buffer_copy_buffer(ds->value, src->value);
+ ds->is_index_key = src->is_index_key;
+ return (data_unset *)ds;
+ }
+@@ -40,7 +40,7 @@ static int data_string_insert_dup(data_unset *dst, data_unset *src) {
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(", "));
+ buffer_append_string_buffer(ds_dst->value, ds_src->value);
+ } else {
+- buffer_copy_string_buffer(ds_dst->value, ds_src->value);
++ buffer_copy_buffer(ds_dst->value, ds_src->value);
+ }
+
+ src->free(src);
+@@ -58,7 +58,7 @@ static int data_response_insert_dup(data_unset *dst, data_unset *src) {
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(": "));
+ buffer_append_string_buffer(ds_dst->value, ds_src->value);
+ } else {
+- buffer_copy_string_buffer(ds_dst->value, ds_src->value);
++ buffer_copy_buffer(ds_dst->value, ds_src->value);
+ }
+
+ src->free(src);
+diff --git a/src/etag.c b/src/etag.c
+index e7e9e3f..bf63d94 100644
+--- a/src/etag.c
++++ b/src/etag.c
+@@ -10,7 +10,7 @@
+ #include <string.h>
+
+ int etag_is_equal(buffer *etag, const char *matches) {
+- if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1;
++ if (etag && !buffer_string_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1;
+ return 0;
+ }
+
+@@ -20,17 +20,17 @@ int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
+ buffer_reset(etag);
+
+ if (flags & ETAG_USE_INODE) {
+- buffer_append_off_t(etag, st->st_ino);
++ buffer_append_int(etag, st->st_ino);
+ buffer_append_string_len(etag, CONST_STR_LEN("-"));
+ }
+
+ if (flags & ETAG_USE_SIZE) {
+- buffer_append_off_t(etag, st->st_size);
++ buffer_append_int(etag, st->st_size);
+ buffer_append_string_len(etag, CONST_STR_LEN("-"));
+ }
+
+ if (flags & ETAG_USE_MTIME) {
+- buffer_append_long(etag, st->st_mtime);
++ buffer_append_int(etag, st->st_mtime);
+ }
+
+ return 0;
+@@ -44,7 +44,7 @@ int etag_mutate(buffer *mut, buffer *etag) {
+
+ buffer_reset(mut);
+ buffer_copy_string_len(mut, CONST_STR_LEN("\""));
+- buffer_append_off_t(mut, h);
++ buffer_append_int(mut, h);
+ buffer_append_string_len(mut, CONST_STR_LEN("\""));
+
+ return 0;
+diff --git a/src/http-header-glue.c b/src/http-header-glue.c
+index fe2f4fb..abffb7d 100644
+--- a/src/http-header-glue.c
++++ b/src/http-header-glue.c
+@@ -123,7 +123,7 @@ int http_response_redirect_to_directory(server *srv, connection *con) {
+
+ o = buffer_init();
+
+- buffer_copy_string_buffer(o, con->uri.scheme);
++ buffer_copy_buffer(o, con->uri.scheme);
+ buffer_append_string_len(o, CONST_STR_LEN("://"));
+ if (con->uri.authority->used) {
+ buffer_append_string_buffer(o, con->uri.authority);
+@@ -197,13 +197,13 @@ int http_response_redirect_to_directory(server *srv, connection *con) {
+ }
+ if (default_port != srv->srvconf.port) {
+ buffer_append_string_len(o, CONST_STR_LEN(":"));
+- buffer_append_long(o, srv->srvconf.port);
++ buffer_append_int(o, srv->srvconf.port);
+ }
+ }
+ }
+ buffer_append_string_buffer(o, con->uri.path);
+ buffer_append_string_len(o, CONST_STR_LEN("/"));
+- if (!buffer_is_empty(con->uri.query)) {
++ if (!buffer_string_is_empty(con->uri.query)) {
+ buffer_append_string_len(o, CONST_STR_LEN("?"));
+ buffer_append_string_buffer(o, con->uri.query);
+ }
+diff --git a/src/http_auth.c b/src/http_auth.c
+index e1d15e0..91e388c 100644
+--- a/src/http_auth.c
++++ b/src/http_auth.c
+@@ -172,7 +172,7 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *
+ stream f;
+ char * f_line;
+
+- if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
++ if (buffer_string_is_empty(p->conf.auth_htdigest_userfile)) return -1;
+
+ if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
+@@ -253,7 +253,7 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *
+
+ auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
+
+- if (buffer_is_empty(auth_fn)) return -1;
++ if (buffer_string_is_empty(auth_fn)) return -1;
+
+ if (0 != stream_open(&f, auth_fn)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+@@ -748,7 +748,7 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
+ return -1;
+
+ /* build filter */
+- buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
++ buffer_copy_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
+ buffer_append_string_buffer(p->ldap_filter, username);
+ buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
+
+@@ -903,7 +903,7 @@ int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p,
+ }
+
+ /* remember the username */
+- buffer_copy_string_buffer(p->auth_user, username);
++ buffer_copy_buffer(p->auth_user, username);
+
+ buffer_free(username);
+ buffer_free(password);
+@@ -1192,7 +1192,7 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
+ int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer *fn, char out[33]) {
+ HASH h;
+ li_MD5_CTX Md5Ctx;
+- char hh[32];
++ char hh[LI_ITOSTRING_LENGTH];
+
+ UNUSED(p);
+
+@@ -1202,10 +1202,10 @@ int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer
+ 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);
++ li_itostr(hh, srv->cur_ts);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
+- LI_ltostr(hh, rand());
++ li_itostr(hh, rand());
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+
+ li_MD5_Final(h, &Md5Ctx);
+diff --git a/src/http_chunk.c b/src/http_chunk.c
+index 5557edc..e3647e6 100644
+--- a/src/http_chunk.c
++++ b/src/http_chunk.c
+@@ -20,21 +20,23 @@
+ #include <errno.h>
+ #include <string.h>
+
+-static int http_chunk_append_len(server *srv, connection *con, size_t len) {
++static void http_chunk_append_len(server *srv, connection *con, size_t len) {
+ size_t i, olen = len, j;
+ buffer *b;
+
++ force_assert(NULL != srv);
++
+ b = srv->tmp_chunk_len;
+
+ if (len == 0) {
+- buffer_copy_string_len(b, CONST_STR_LEN("0"));
++ buffer_copy_string_len(b, CONST_STR_LEN("0\r\n"));
+ } 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);
++ buffer_prepare_copy(b, i + 2);
+
+ for (j = i-1, len = olen; j+1 > 0; j--) {
+ b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
+@@ -42,39 +44,40 @@ static int http_chunk_append_len(server *srv, connection *con, size_t len) {
+ }
+ b->used = i;
+ b->ptr[b->used++] = '\0';
++
++ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ }
+
+- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ chunkqueue_append_buffer(con->write_queue, b);
+-
+- return 0;
+ }
+
+
+-int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
++void http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
+ chunkqueue *cq;
+
+- if (!con) return -1;
++ force_assert(NULL != con);
++ if (0 == len) return;
+
+ 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);
++ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
++ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+-
+- return 0;
+ }
+
+-int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
++void http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
+ chunkqueue *cq;
+
+- if (!con) return -1;
++ force_assert(NULL != con);
++
++ if (buffer_string_is_empty(mem)) return;
+
+ cq = con->write_queue;
+
+@@ -84,49 +87,37 @@ int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
+
+ 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);
++ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
++ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+-
+- return 0;
+ }
+
+-int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
++void http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
+ chunkqueue *cq;
+
+- if (!con) return -1;
++ force_assert(NULL != con);
++ force_assert(NULL != mem || 0 == len);
+
+- cq = con->write_queue;
++ if (NULL == mem || 0 == len) return;
+
+- 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;
+- }
++ cq = con->write_queue;
+
+ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
+- http_chunk_append_len(srv, con, len - 1);
++ http_chunk_append_len(srv, con, len);
+ }
+
+ chunkqueue_append_mem(cq, mem, len);
+
+ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
+- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
++ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+-
+- return 0;
+ }
+
++void http_chunk_close(server *srv, connection *con) {
++ UNUSED(srv);
++ force_assert(NULL != con);
+
+-off_t http_chunkqueue_length(server *srv, connection *con) {
+- if (!con) {
+- log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
+-
+- return 0;
++ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("0\r\n\r\n"));
+ }
+-
+- return chunkqueue_length(con->write_queue);
+ }
+diff --git a/src/http_chunk.h b/src/http_chunk.h
+index 4ba24a2..127a116 100644
+--- a/src/http_chunk.h
++++ b/src/http_chunk.h
+@@ -4,9 +4,9 @@
+ #include "server.h"
+ #include <sys/types.h>
+
+-int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len);
+-int http_chunk_append_buffer(server *srv, connection *con, buffer *mem);
+-int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len);
+-off_t http_chunkqueue_length(server *srv, connection *con);
++void http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len); /* copies memory */
++void http_chunk_append_buffer(server *srv, connection *con, buffer *mem); /* may reset "mem" */
++void http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len); /* copies "fn" */
++void http_chunk_close(server *srv, connection *con);
+
+ #endif
+diff --git a/src/log.c b/src/log.c
+index 8033d17..75decfe 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -152,7 +152,7 @@ int log_error_open(server *srv) {
+
+ if (srv->srvconf.errorlog_use_syslog) {
+ srv->errorlog_mode = ERRORLOG_SYSLOG;
+- } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
++ } else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) {
+ const char *logfile = srv->srvconf.errorlog_file->ptr;
+
+ if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
+@@ -170,7 +170,7 @@ int log_error_open(server *srv) {
+ srv->errorlog_fd = -1;
+ }
+
+- if (!buffer_is_empty(srv->srvconf.breakagelog_file)) {
++ if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) {
+ int breakage_fd;
+ const char *logfile = srv->srvconf.breakagelog_file->ptr;
+
+@@ -277,12 +277,12 @@ static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ break;
+ case 'd': /* int */
+ d = va_arg(ap, int);
+- buffer_append_long(out, d);
++ buffer_append_int(out, d);
+ buffer_append_string_len(out, CONST_STR_LEN(" "));
+ break;
+ case 'o': /* off_t */
+ o = va_arg(ap, off_t);
+- buffer_append_off_t(out, o);
++ buffer_append_int(out, o);
+ buffer_append_string_len(out, CONST_STR_LEN(" "));
+ break;
+ case 'x': /* int (hex) */
+@@ -301,11 +301,11 @@ static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ break;
+ case 'D': /* int */
+ d = va_arg(ap, int);
+- buffer_append_long(out, d);
++ buffer_append_int(out, d);
+ break;
+ case 'O': /* off_t */
+ o = va_arg(ap, off_t);
+- buffer_append_off_t(out, o);
++ buffer_append_int(out, o);
+ break;
+ case 'X': /* int (hex) */
+ d = va_arg(ap, int);
+@@ -339,7 +339,7 @@ static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsi
+ srv->last_generated_debug_ts = srv->cur_ts;
+ }
+
+- buffer_copy_string_buffer(b, srv->ts_debug_str);
++ buffer_copy_buffer(b, srv->ts_debug_str);
+ buffer_append_string_len(b, CONST_STR_LEN(": ("));
+ break;
+ case ERRORLOG_SYSLOG:
+@@ -350,7 +350,7 @@ static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsi
+
+ buffer_append_string(b, filename);
+ buffer_append_string_len(b, CONST_STR_LEN("."));
+- buffer_append_long(b, line);
++ buffer_append_int(b, line);
+ buffer_append_string_len(b, CONST_STR_LEN(") "));
+
+ return 0;
+diff --git a/src/mod_access.c b/src/mod_access.c
+index c4774b8..7b88e19 100644
+--- a/src/mod_access.c
++++ b/src/mod_access.c
+@@ -132,7 +132,7 @@ URIHANDLER_FUNC(mod_access_uri_handler) {
+ s_len = con->uri.path->used - 1;
+
+ if (con->conf.log_request_handling) {
+- log_error_write(srv, __FILE__, __LINE__, "s",
++ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_access_uri_handler called");
+ }
+
+diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
+index 21a7764..89fd7f5 100644
+--- a/src/mod_accesslog.c
++++ b/src/mod_accesslog.c
+@@ -494,7 +494,7 @@ SETDEFAULTS_FUNC(log_access_open) {
+ return HANDLER_ERROR;
+ }
+
+- if (i == 0 && buffer_is_empty(s->format)) {
++ if (i == 0 && buffer_string_is_empty(s->format)) {
+ /* set a default logfile string */
+
+ buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));
+@@ -523,7 +523,7 @@ SETDEFAULTS_FUNC(log_access_open) {
+ for (j = 0; j < s->parsed_format->used; j++) {
+ if (FIELD_FORMAT == s->parsed_format->ptr[j]->type) {
+ if (FORMAT_TIMESTAMP == s->parsed_format->ptr[j]->field) {
+- if (!buffer_is_empty(s->parsed_format->ptr[j]->string)) {
++ if (!buffer_string_is_empty(s->parsed_format->ptr[j]->string)) {
+ buffer_copy_string(s->ts_accesslog_fmt_str, s->parsed_format->ptr[j]->string->ptr);
+ }
+
+@@ -558,7 +558,7 @@ SETDEFAULTS_FUNC(log_access_open) {
+ }
+
+ s->append_tz_offset = 0;
+- if (buffer_is_empty(s->ts_accesslog_fmt_str)) {
++ if (buffer_string_is_empty(s->ts_accesslog_fmt_str)) {
+ #if defined(HAVE_STRUCT_TM_GMTOFF)
+ BUFFER_COPY_STRING_CONST(s->ts_accesslog_fmt_str, "[%d/%b/%Y:%H:%M:%S ");
+ s->append_tz_offset = 1;
+@@ -730,10 +730,10 @@ REQUESTDONE_FUNC(log_access_write) {
+
+ /* hours */
+ if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
+- buffer_append_long(p->conf.ts_accesslog_str, hrs);
++ buffer_append_int(p->conf.ts_accesslog_str, hrs);
+
+ if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
+- buffer_append_long(p->conf.ts_accesslog_str, min);
++ buffer_append_int(p->conf.ts_accesslog_str, min);
+ buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));
+ }
+ #else /* HAVE_STRUCT_TM_GMTOFF */
+@@ -777,12 +777,12 @@ REQUESTDONE_FUNC(log_access_write) {
+ }
+ break;
+ case FORMAT_STATUS:
+- buffer_append_long(b, con->http_status);
++ buffer_append_int(b, con->http_status);
+ break;
+
+ case FORMAT_BYTES_OUT_NO_HEADER:
+ if (con->bytes_written > 0) {
+- buffer_append_off_t(b,
++ buffer_append_int(b,
+ con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+@@ -818,20 +818,20 @@ REQUESTDONE_FUNC(log_access_write) {
+ break;
+ case FORMAT_BYTES_OUT:
+ if (con->bytes_written > 0) {
+- buffer_append_off_t(b, con->bytes_written);
++ buffer_append_int(b, con->bytes_written);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_BYTES_IN:
+ if (con->bytes_read > 0) {
+- buffer_append_off_t(b, con->bytes_read);
++ buffer_append_int(b, con->bytes_read);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_TIME_USED:
+- buffer_append_long(b, srv->cur_ts - con->request_start);
++ buffer_append_int(b, srv->cur_ts - con->request_start);
+ break;
+ case FORMAT_SERVER_NAME:
+ if (con->server_name->used > 1) {
+@@ -869,7 +869,7 @@ REQUESTDONE_FUNC(log_access_write) {
+ if (colon) {
+ buffer_append_string(b, colon+1);
+ } else {
+- buffer_append_long(b, srv->srvconf.port);
++ buffer_append_int(b, srv->srvconf.port);
+ }
+ }
+ break;
+diff --git a/src/mod_alias.c b/src/mod_alias.c
+index 062c268..bf22b5f 100644
+--- a/src/mod_alias.c
++++ b/src/mod_alias.c
+@@ -173,10 +173,10 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) {
+ strncmp(uri_ptr, ds->key->ptr, alias_len))) {
+ /* matched */
+
+- buffer_copy_string_buffer(con->physical.basedir, ds->value);
+- buffer_copy_string_buffer(srv->tmp_buf, ds->value);
++ buffer_copy_buffer(con->physical.basedir, ds->value);
++ buffer_copy_buffer(srv->tmp_buf, ds->value);
+ buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
+- buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
++ buffer_copy_buffer(con->physical.path, srv->tmp_buf);
+
+ return HANDLER_GO_ON;
+ }
+diff --git a/src/mod_auth.c b/src/mod_auth.c
+index 31e1140..d5a3f1c 100644
+--- a/src/mod_auth.c
++++ b/src/mod_auth.c
+@@ -324,7 +324,7 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
+ buffer_copy_string(ds->key, "REMOTE_USER");
+ array_insert_unique(con->environment, (data_unset *)ds);
+ }
+- buffer_copy_string_buffer(ds->value, p->auth_user);
++ buffer_copy_buffer(ds->value, p->auth_user);
+
+ /* AUTH_TYPE environment */
+
+@@ -535,7 +535,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
+ data_array *a;
+
+ a = data_array_init();
+- buffer_copy_string_buffer(a->key, da_file->key);
++ buffer_copy_buffer(a->key, da_file->key);
+
+ ds = data_string_init();
+
+@@ -608,7 +608,7 @@ handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
+ if (s->auth_ldap_starttls) {
+ /* if no CA file is given, it is ok, as we will use encryption
+ * if the server requires a CAfile it will tell us */
+- if (!buffer_is_empty(s->auth_ldap_cafile)) {
++ if (!buffer_string_is_empty(s->auth_ldap_cafile)) {
+ if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ s->auth_ldap_cafile->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+diff --git a/src/mod_cgi.c b/src/mod_cgi.c
+index 734ecee..76882e8 100644
+--- a/src/mod_cgi.c
++++ b/src/mod_cgi.c
+@@ -235,7 +235,7 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff
+
+ UNUSED(srv);
+
+- buffer_copy_string_buffer(p->parse_response, in);
++ buffer_copy_buffer(p->parse_response, in);
+
+ for (s = p->parse_response->ptr;
+ NULL != (ns = strchr(s, '\n'));
+@@ -350,7 +350,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ buffer_prepare_copy(hctx->response, 4 * 1024);
+ } else {
+ if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
+- buffer_prepare_copy(hctx->response, toread + 1);
++ buffer_prepare_copy(hctx->response, toread);
+ }
+ #endif
+
+@@ -370,7 +370,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->file_finished = 1;
+
+ /* send final chunk */
+- http_chunk_append_mem(srv, con, NULL, 0);
++ http_chunk_close(srv, con);
+ joblist_append(srv, con);
+
+ return FDEVENT_HANDLED_FINISHED;
+@@ -458,7 +458,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
+ }
+
+- http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
++ http_chunk_append_buffer(srv, con, hctx->response_header);
+ joblist_append(srv, con);
+ } else {
+ const char *bstart;
+@@ -493,7 +493,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ }
+
+ if (blen > 0) {
+- http_chunk_append_mem(srv, con, bstart, blen + 1);
++ http_chunk_append_mem(srv, con, bstart, blen);
+ joblist_append(srv, con);
+ }
+ }
+@@ -501,7 +501,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->file_started = 1;
+ }
+ } else {
+- http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
++ http_chunk_append_buffer(srv, con, hctx->response);
+ joblist_append(srv, con);
+ }
+
+@@ -668,27 +668,17 @@ static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
+ /* perhaps this issue is already handled */
+ if (revents & FDEVENT_HUP) {
+ /* check if we still have a unfinished header package which is a body in reality */
+- if (con->file_started == 0 &&
+- hctx->response_header->used) {
++ if (con->file_started == 0 && !buffer_string_is_empty(hctx->response_header)) {
+ con->file_started = 1;
+- http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
+- joblist_append(srv, con);
++ http_chunk_append_buffer(srv, con, hctx->response_header);
+ }
+
+ if (con->file_finished == 0) {
+- http_chunk_append_mem(srv, con, NULL, 0);
+- joblist_append(srv, con);
++ http_chunk_close(srv, con);
+ }
+-
+ con->file_finished = 1;
+
+- if (chunkqueue_is_empty(con->write_queue)) {
+- /* there is nothing left to write */
+- connection_set_state(srv, con, CON_STATE_RESPONSE_END);
+- } else {
+- /* used the write-handler to finish the request on demand */
+-
+- }
++ joblist_append(srv, con);
+
+ # if 0
+ log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
+@@ -777,7 +767,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ char **args;
+ int argc;
+ int i = 0;
+- char buf[32];
++ char buf[LI_ITOSTRING_LENGTH];
+ size_t n;
+ char_array env;
+ char *c;
+@@ -809,7 +799,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
+ }
+
+- if (!buffer_is_empty(con->server_name)) {
++ if (!buffer_string_is_empty(con->server_name)) {
+ size_t len = con->server_name->used - 1;
+
+ if (con->server_name->ptr[0] == '[') {
+@@ -839,7 +829,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
+ #else
+@@ -874,14 +864,14 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ s = get_http_method_name(con->request.http_method);
+ cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
+
+- if (!buffer_is_empty(con->request.pathinfo)) {
++ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
+ }
+ cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
+- if (!buffer_is_empty(con->uri.query)) {
++ if (!buffer_string_is_empty(con->uri.query)) {
+ cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
+ }
+- if (!buffer_is_empty(con->request.orig_uri)) {
++ if (!buffer_string_is_empty(con->request.orig_uri)) {
+ cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
+ }
+
+@@ -909,7 +899,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ }
+ cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
+ #else
+@@ -922,8 +912,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
+ }
+
+- /* request.content_length < SSIZE_MAX, see request.c */
+- LI_ltostr(buf, con->request.content_length);
++ li_itostr(buf, con->request.content_length);
+ 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));
+@@ -1134,8 +1123,6 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ }
+ }
+ break;
+- case UNUSED_CHUNK:
+- break;
+ }
+
+ if (r > 0) {
+diff --git a/src/mod_cml.c b/src/mod_cml.c
+index b5b5ac2..3033d42 100644
+--- a/src/mod_cml.c
++++ b/src/mod_cml.c
+@@ -184,7 +184,7 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *
+
+ /* cleanup basedir */
+ b = p->baseurl;
+- buffer_copy_string_buffer(b, con->uri.path);
++ buffer_copy_buffer(b, con->uri.path);
+ for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
+
+ if (*c == '/') {
+@@ -193,7 +193,7 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *
+ }
+
+ b = p->basedir;
+- buffer_copy_string_buffer(b, con->physical.path);
++ buffer_copy_buffer(b, con->physical.path);
+ for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
+
+ if (*c == '/') {
+@@ -218,7 +218,7 @@ URIHANDLER_FUNC(mod_cml_power_magnet) {
+ buffer_reset(p->baseurl);
+ buffer_reset(p->trigger_handler);
+
+- if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
+
+ /*
+ * power-magnet:
+@@ -264,7 +264,7 @@ URIHANDLER_FUNC(mod_cml_power_magnet) {
+ URIHANDLER_FUNC(mod_cml_is_handled) {
+ plugin_data *p = p_d;
+
+- if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
++ if (buffer_string_is_empty(con->physical.path)) return HANDLER_ERROR;
+
+ mod_cml_patch_connection(srv, con, p);
+
+@@ -272,7 +272,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
+ buffer_reset(p->baseurl);
+ buffer_reset(p->trigger_handler);
+
+- if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(p->conf.ext)) return HANDLER_GO_ON;
+
+ if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
+ return HANDLER_GO_ON;
+diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
+index d05e854..63dd1e7 100644
+--- a/src/mod_cml_lua.c
++++ b/src/mod_cml_lua.c
+@@ -260,7 +260,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
+- if (!buffer_is_empty(con->request.pathinfo)) {
++ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
+ }
+
+@@ -276,7 +276,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ header_tbl = lua_gettop(L);
+ lua_gettable(L, LUA_GLOBALSINDEX);
+
+- buffer_copy_string_buffer(b, con->uri.query);
++ buffer_copy_buffer(b, con->uri.query);
+ cache_export_get_params(L, header_tbl, b);
+ buffer_reset(b);
+
+@@ -346,7 +346,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+
+ /* the file is relative, make it absolute */
+ if (s[0] != '/') {
+- buffer_copy_string_buffer(b, p->basedir);
++ buffer_copy_buffer(b, p->basedir);
+ buffer_append_string(b, lua_tostring(L, -1));
+ } else {
+ buffer_copy_string(b, lua_tostring(L, -1));
+@@ -358,7 +358,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ switch(errno) {
+ case ENOENT:
+ /* a file is missing, call the handler to generate it */
+- if (!buffer_is_empty(p->trigger_handler)) {
++ if (!buffer_string_is_empty(p->trigger_handler)) {
+ ret = 1; /* cache-miss */
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+@@ -433,12 +433,12 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ }
+ }
+
+- if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
++ if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) {
+ /* cache-miss */
+- buffer_copy_string_buffer(con->uri.path, p->baseurl);
++ buffer_copy_buffer(con->uri.path, p->baseurl);
+ buffer_append_string_buffer(con->uri.path, p->trigger_handler);
+
+- buffer_copy_string_buffer(con->physical.path, p->basedir);
++ buffer_copy_buffer(con->physical.path, p->basedir);
+ buffer_append_string_buffer(con->physical.path, p->trigger_handler);
+
+ chunkqueue_reset(con->write_queue);
+diff --git a/src/mod_compress.c b/src/mod_compress.c
+index c4183bb..ad6e9f2 100644
+--- a/src/mod_compress.c
++++ b/src/mod_compress.c
+@@ -222,7 +222,7 @@ SETDEFAULTS_FUNC(mod_compress_setdefaults) {
+
+ array_free(encodings_arr);
+
+- if (!buffer_is_empty(s->compress_cache_dir)) {
++ if (!buffer_string_is_empty(s->compress_cache_dir)) {
+ struct stat st;
+ mkdir_recursive(s->compress_cache_dir->ptr);
+
+@@ -351,7 +351,7 @@ static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_d
+ }
+
+ /* trailer */
+- p->b->used += z.total_out;
++ p->b->used = z.total_out;
+
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+@@ -429,12 +429,12 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
+ if (sce->st.st_size > 128 * 1024 * 1024) return -1;
+
+ buffer_reset(p->ofn);
+- buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
+- BUFFER_APPEND_SLASH(p->ofn);
++ buffer_copy_buffer(p->ofn, p->conf.compress_cache_dir);
++ buffer_append_slash(p->ofn);
+
+ if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
+ buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
+- buffer_copy_string_buffer(p->b, p->ofn);
++ buffer_copy_buffer(p->b, p->ofn);
+ } else {
+ buffer_append_string_buffer(p->ofn, con->uri.path);
+ }
+@@ -469,7 +469,7 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
+ #if 0
+ log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
+ #endif
+- buffer_copy_string_buffer(con->physical.path, p->ofn);
++ buffer_copy_buffer(con->physical.path, p->ofn);
+
+ return 0;
+ }
+@@ -574,7 +574,7 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
+ return -1;
+ }
+
+- buffer_copy_string_buffer(con->physical.path, p->ofn);
++ buffer_copy_buffer(con->physical.path, p->ofn);
+
+ return 0;
+ }
+@@ -652,7 +652,7 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
+
+ chunkqueue_reset(con->write_queue);
+ b = chunkqueue_get_append_buffer(con->write_queue);
+- buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
++ buffer_copy_string_len(b, p->b->ptr, p->b->used);
+
+ buffer_reset(con->physical.path);
+
+@@ -732,7 +732,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
+ return HANDLER_GO_ON;
+ }
+
+- if (buffer_is_empty(con->physical.path)) {
++ if (buffer_string_is_empty(con->physical.path)) {
+ return HANDLER_GO_ON;
+ }
+
+@@ -867,7 +867,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
+
+ if (use_etag) {
+ /* try matching etag of compressed version */
+- buffer_copy_string_buffer(srv->tmp_buf, sce->etag);
++ buffer_copy_buffer(srv->tmp_buf, sce->etag);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("-"));
+ buffer_append_string(srv->tmp_buf, compression_name);
+ etag_mutate(con->physical.etag, srv->tmp_buf);
+diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
+index 6a2b139..4b7106a 100644
+--- a/src/mod_dirlisting.c
++++ b/src/mod_dirlisting.c
+@@ -124,7 +124,7 @@ static int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
+ }
+
+ exb->ptr[exb->used]->string = buffer_init();
+- buffer_copy_string_buffer(exb->ptr[exb->used]->string, string);
++ buffer_copy_buffer(exb->ptr[exb->used]->string, string);
+
+ exb->used++;
+
+@@ -469,7 +469,8 @@ static int http_list_directory_sizefmt(char *buf, off_t size) {
+ u++;
+ }
+
+- out += LI_ltostr(out, size);
++ li_itostr(out, size);
++ out += strlen(out);
+ out[0] = '.';
+ out[1] = remain + '0';
+ out[2] = *u;
+@@ -539,8 +540,8 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
+ stream s;
+ /* if we have a HEADER file, display it in <pre class="header"></pre> */
+
+- buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+- BUFFER_APPEND_SLASH(p->tmp_buf);
++ buffer_copy_buffer(p->tmp_buf, con->physical.path);
++ buffer_append_slash(p->tmp_buf);
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("HEADER.txt"));
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+@@ -592,8 +593,8 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
+ stream s;
+ /* if we have a README file, display it in <pre class="readme"></pre> */
+
+- buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+- BUFFER_APPEND_SLASH(p->tmp_buf);
++ buffer_copy_buffer(p->tmp_buf, con->physical.path);
++ buffer_append_slash(p->tmp_buf);
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt"));
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+@@ -785,7 +786,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+
+ out = chunkqueue_get_append_buffer(con->write_queue);
+ buffer_copy_string_len(out, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\""));
+- if (buffer_is_empty(p->conf.encoding)) {
++ if (buffer_string_is_empty(p->conf.encoding)) {
+ buffer_append_string_len(out, CONST_STR_LEN("iso-8859-1"));
+ } else {
+ buffer_append_string_buffer(out, p->conf.encoding);
+@@ -889,7 +890,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ http_list_directory_footer(srv, con, p, out);
+
+ /* Insert possible charset to Content-Type */
+- if (buffer_is_empty(p->conf.encoding)) {
++ if (buffer_string_is_empty(p->conf.encoding)) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset="));
+diff --git a/src/mod_evhost.c b/src/mod_evhost.c
+index a491baa..5281523 100644
+--- a/src/mod_evhost.c
++++ b/src/mod_evhost.c
+@@ -200,7 +200,7 @@ static int mod_evhost_parse_host(connection *con,array *host) {
+ /* is something between the dots */
+ ds = data_string_init();
+ buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
+- buffer_append_long(ds->key, i++);
++ buffer_append_int(ds->key, i++);
+ buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
+
+ array_insert_unique(host,(data_unset *)ds);
+@@ -213,7 +213,7 @@ static int mod_evhost_parse_host(connection *con,array *host) {
+ if (colon != ptr) {
+ ds = data_string_init();
+ buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
+- buffer_append_long(ds->key, i /* ++ */);
++ buffer_append_int(ds->key, i /* ++ */);
+ buffer_copy_string_len(ds->value,ptr,colon-ptr);
+
+ array_insert_unique(host,(data_unset *)ds);
+@@ -311,7 +311,7 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
+ }
+ }
+
+- BUFFER_APPEND_SLASH(p->tmp_buf);
++ buffer_append_slash(p->tmp_buf);
+
+ array_free(parsed_host);
+
+@@ -324,7 +324,7 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
+ }
+
+ if (!not_good) {
+- buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
++ buffer_copy_buffer(con->physical.doc_root, p->tmp_buf);
+ }
+
+ return HANDLER_GO_ON;
+diff --git a/src/mod_expire.c b/src/mod_expire.c
+index 476261f..41895f9 100644
+--- a/src/mod_expire.c
++++ b/src/mod_expire.c
+@@ -346,7 +346,7 @@ URIHANDLER_FUNC(mod_expire_path_handler) {
+
+ /* HTTP/1.1 */
+ buffer_copy_string_len(p->expire_tstmp, CONST_STR_LEN("max-age="));
+- buffer_append_long(p->expire_tstmp, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
++ buffer_append_int(p->expire_tstmp, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
+
+ response_header_append(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
+
+diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
+index ad1ec18..01e72e5 100644
+--- a/src/mod_fastcgi.c
++++ b/src/mod_fastcgi.c
+@@ -391,7 +391,7 @@ static void fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, f
+ buffer_append_string_buffer(b, host->id);
+ if (proc) {
+ buffer_append_string_len(b, CONST_STR_LEN("."));
+- buffer_append_long(b, proc->id);
++ buffer_append_int(b, proc->id);
+ }
+ }
+
+@@ -637,7 +637,7 @@ static int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_
+ force_assert(fe);
+ fe->key = buffer_init();
+ fe->last_used_ndx = -1;
+- buffer_copy_string_buffer(fe->key, key);
++ buffer_copy_buffer(fe->key, key);
+
+ /* */
+
+@@ -724,7 +724,7 @@ FREE_FUNC(mod_fastcgi_free) {
+ }
+
+ if (proc->is_local &&
+- !buffer_is_empty(proc->unixsocket)) {
++ !buffer_string_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
+ }
+ }
+@@ -734,7 +734,7 @@ FREE_FUNC(mod_fastcgi_free) {
+ kill(proc->pid, host->kill_signal);
+ }
+ if (proc->is_local &&
+- !buffer_is_empty(proc->unixsocket)) {
++ !buffer_string_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
+ }
+ }
+@@ -868,7 +868,7 @@ static int fcgi_spawn_connection(server *srv,
+ "new proc, socket:", proc->port, proc->unixsocket);
+ }
+
+- if (!buffer_is_empty(proc->unixsocket)) {
++ if (!buffer_string_is_empty(proc->unixsocket)) {
+ memset(&fcgi_addr, 0, sizeof(fcgi_addr));
+
+ #ifdef HAVE_SYS_UN_H
+@@ -901,7 +901,7 @@ static int fcgi_spawn_connection(server *srv,
+ } else {
+ fcgi_addr_in.sin_family = AF_INET;
+
+- if (buffer_is_empty(host->host)) {
++ if (buffer_string_is_empty(host->host)) {
+ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ } else {
+ struct hostent *he;
+@@ -937,13 +937,13 @@ static int fcgi_spawn_connection(server *srv,
+ fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
+
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
+- if (!buffer_is_empty(host->host)) {
++ if (!buffer_string_is_empty(host->host)) {
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ } else {
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
+ }
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
+- buffer_append_long(proc->connection_name, proc->port);
++ buffer_append_int(proc->connection_name, proc->port);
+ }
+
+ if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
+@@ -958,7 +958,7 @@ static int fcgi_spawn_connection(server *srv,
+ int val;
+
+ if (errno != ENOENT &&
+- !buffer_is_empty(proc->unixsocket)) {
++ !buffer_string_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
+ }
+
+@@ -1285,7 +1285,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ host = fastcgi_host_init();
+ buffer_reset(fcgi_mode);
+
+- buffer_copy_string_buffer(host->id, da_host->key);
++ buffer_copy_buffer(host->id, da_host->key);
+
+ host->check_local = 1;
+ host->max_procs = 4;
+@@ -1319,8 +1319,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ goto error;
+ }
+
+- if ((!buffer_is_empty(host->host) || host->port) &&
+- !buffer_is_empty(host->unixsocket)) {
++ if ((!buffer_string_is_empty(host->host) || host->port) &&
++ !buffer_string_is_empty(host->unixsocket)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "either host/port or socket have to be set in:",
+ da->key, "= (",
+@@ -1330,7 +1330,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ goto error;
+ }
+
+- if (!buffer_is_empty(host->unixsocket)) {
++ if (!buffer_string_is_empty(host->unixsocket)) {
+ /* unix domain socket */
+ struct sockaddr_un un;
+
+@@ -1346,8 +1346,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ } else {
+ /* tcp/ip */
+
+- if (buffer_is_empty(host->host) &&
+- buffer_is_empty(host->bin_path)) {
++ if (buffer_string_is_empty(host->host) &&
++ buffer_string_is_empty(host->bin_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "host or binpath have to be set in:",
+ da->key, "= (",
+@@ -1366,7 +1366,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ }
+ }
+
+- if (!buffer_is_empty(host->bin_path)) {
++ if (!buffer_string_is_empty(host->bin_path)) {
+ /* a local socket + self spawning */
+ size_t pno;
+
+@@ -1386,12 +1386,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ proc->id = host->num_procs++;
+ host->max_id++;
+
+- if (buffer_is_empty(host->unixsocket)) {
++ if (buffer_string_is_empty(host->unixsocket)) {
+ proc->port = host->port + pno;
+ } else {
+- buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
++ buffer_copy_buffer(proc->unixsocket, host->unixsocket);
+ buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));
+- buffer_append_long(proc->unixsocket, pno);
++ buffer_append_int(proc->unixsocket, pno);
+ }
+
+ if (s->debug) {
+@@ -1425,10 +1425,10 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ host->active_procs++;
+ proc->state = PROC_STATE_RUNNING;
+
+- if (buffer_is_empty(host->unixsocket)) {
++ if (buffer_string_is_empty(host->unixsocket)) {
+ proc->port = host->port;
+ } else {
+- buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
++ buffer_copy_buffer(proc->unixsocket, host->unixsocket);
+ }
+
+ fastcgi_status_init(srv, p->statuskey, host, proc);
+@@ -1438,12 +1438,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ host->max_procs = 1;
+ }
+
+- if (!buffer_is_empty(fcgi_mode)) {
++ if (!buffer_string_is_empty(fcgi_mode)) {
+ if (strcmp(fcgi_mode->ptr, "responder") == 0) {
+ host->mode = FCGI_RESPONDER;
+ } else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
+ host->mode = FCGI_AUTHORIZER;
+- if (buffer_is_empty(host->docroot)) {
++ if (buffer_string_is_empty(host->docroot)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: docroot is required for authorizer mode.");
+ goto error;
+@@ -1672,7 +1672,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
+
+ memset(&fcgi_addr, 0, sizeof(fcgi_addr));
+
+- if (!buffer_is_empty(proc->unixsocket)) {
++ if (!buffer_string_is_empty(proc->unixsocket)) {
+ #ifdef HAVE_SYS_UN_H
+ /* use the unix domain socket */
+ fcgi_addr_un.sun_family = AF_UNIX;
+@@ -1692,7 +1692,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
+ #endif
+ fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+- if (buffer_is_empty(proc->connection_name)) {
++ if (buffer_string_is_empty(proc->connection_name)) {
+ /* on remote spawing we have to set the connection-name now */
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
+ buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
+@@ -1702,7 +1702,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
+ #endif
+ } else {
+ fcgi_addr_in.sin_family = AF_INET;
+- if (!buffer_is_empty(host->host)) {
++ if (!buffer_string_is_empty(host->host)) {
+ if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "converting IP address failed for", host->host,
+@@ -1718,16 +1718,16 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
+
+ fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
+
+- if (buffer_is_empty(proc->connection_name)) {
++ if (buffer_string_is_empty(proc->connection_name)) {
+ /* on remote spawing we have to set the connection-name now */
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
+- if (!buffer_is_empty(host->host)) {
++ if (!buffer_string_is_empty(host->host)) {
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ } else {
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
+ }
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
+- buffer_append_long(proc->connection_name, proc->port);
++ buffer_append_int(proc->connection_name, proc->port);
+ }
+ }
+
+@@ -1840,7 +1840,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ FCGI_Header header;
+ buffer *b;
+
+- char buf[32];
++ char buf[LI_ITOSTRING_LENGTH];
+ const char *s;
+ #ifdef HAVE_IPV6
+ char b2[INET6_ADDRSTRLEN + 1];
+@@ -1865,7 +1865,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+
+ b = chunkqueue_get_append_buffer(hctx->wb);
+
+- buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
++ buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
+
+ /* send FCGI_PARAMS */
+ buffer_prepare_copy(p->fcgi_env, 1024);
+@@ -1904,7 +1904,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con)
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
+ #else
+@@ -1924,7 +1924,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ }
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con)
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
+ #else
+@@ -1940,8 +1940,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
+ /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
+
+- /* request.content_length < SSIZE_MAX, see request.c */
+- LI_ltostr(buf, con->request.content_length);
++ li_itostr(buf, con->request.content_length);
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con)
+ }
+
+@@ -1955,15 +1954,15 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con)
+
+- if (!buffer_is_empty(con->request.pathinfo)) {
++ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)),con)
+
+ /* PATH_TRANSLATED is only defined if PATH_INFO is set */
+
+- if (!buffer_is_empty(host->docroot)) {
+- buffer_copy_string_buffer(p->path, host->docroot);
++ if (!buffer_string_is_empty(host->docroot)) {
++ buffer_copy_buffer(p->path, host->docroot);
+ } else {
+- buffer_copy_string_buffer(p->path, con->physical.basedir);
++ buffer_copy_buffer(p->path, con->physical.basedir);
+ }
+ 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)
+@@ -1980,19 +1979,19 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ * parameter.
+ */
+
+- if (!buffer_is_empty(host->docroot)) {
++ if (!buffer_string_is_empty(host->docroot)) {
+ /*
+ * rewrite SCRIPT_FILENAME
+ *
+ */
+
+- buffer_copy_string_buffer(p->path, host->docroot);
++ buffer_copy_buffer(p->path, host->docroot);
+ buffer_append_string_buffer(p->path, con->uri.path);
+
+ 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(host->docroot)),con)
+ } else {
+- buffer_copy_string_buffer(p->path, con->physical.path);
++ buffer_copy_buffer(p->path, con->physical.path);
+
+ /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
+ *
+@@ -2037,7 +2036,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con)
+ }
+- if (!buffer_is_empty(con->uri.query)) {
++ if (!buffer_string_is_empty(con->uri.query)) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)
+ } else {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con)
+@@ -2056,135 +2055,43 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
+
+ fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
+- buffer_append_memory(b, (const char *)&header, sizeof(header));
+- buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
++ buffer_append_string_len(b, (const char *)&header, sizeof(header));
++ buffer_append_string_len(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
+
+ fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
+- buffer_append_memory(b, (const char *)&header, sizeof(header));
++ buffer_append_string_len(b, (const char *)&header, sizeof(header));
+
+- b->used++; /* add virtual \0 */
+ hctx->wb->bytes_in += b->used - 1;
+
+ if (con->request.content_length) {
+ chunkqueue *req_cq = con->request_content_queue;
+- chunk *req_c;
+ off_t offset;
+
+ /* something to send ? */
+- for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; ) {
++ for (offset = 0; offset != req_cq->bytes_in; ) {
+ off_t weWant = req_cq->bytes_in - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cq->bytes_in - offset;
+- off_t written = 0;
+- off_t weHave = 0;
+
+ /* we announce toWrite octets
+ * now take all the request_content chunks that we need to fill this request
+ * */
+
+- b = chunkqueue_get_append_buffer(hctx->wb);
+ fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
+- buffer_copy_memory(b, (const char *)&header, sizeof(header));
++ chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header));
+ hctx->wb->bytes_in += sizeof(header);
+
+ if (p->conf.debug > 10) {
+ log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cq->bytes_in);
+ }
+
+- for (written = 0; written != weWant; ) {
+- if (p->conf.debug > 10) {
+- log_error_write(srv, __FILE__, __LINE__, "soso", "chunk:", written, "/", weWant);
+- }
+-
+- switch (req_c->type) {
+- case FILE_CHUNK:
+- weHave = req_c->file.length - req_c->offset;
+-
+- if (weHave > weWant - written) weHave = weWant - written;
+-
+- if (p->conf.debug > 10) {
+- log_error_write(srv, __FILE__, __LINE__, "soSosOsb",
+- "sending", weHave, "bytes from (",
+- req_c->offset, "/", req_c->file.length, ")",
+- req_c->file.name);
+- }
+-
+- force_assert(weHave != 0);
+-
+- chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
+-
+- req_c->offset += weHave;
+- req_cq->bytes_out += weHave;
+- written += weHave;
+-
+- hctx->wb->bytes_in += weHave;
+-
+- /* steal the tempfile
+- *
+- * This is tricky:
+- * - we reference the tempfile from the request-content-queue several times
+- * if the req_c is larger than FCGI_MAX_LENGTH
+- * - we can't simply cleanup the request-content-queue as soon as possible
+- * as it would remove the tempfiles
+- * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
+- * referencing chunk of the fastcgi-write-queue
+- *
+- * */
+-
+- if (req_c->offset == req_c->file.length) {
+- chunk *c;
+-
+- if (p->conf.debug > 10) {
+- log_error_write(srv, __FILE__, __LINE__, "s", "next chunk");
+- }
+- c = hctx->wb->last;
+-
+- force_assert(c->type == FILE_CHUNK);
+- force_assert(req_c->file.is_temp == 1);
+-
+- c->file.is_temp = 1;
+- req_c->file.is_temp = 0;
+-
+- chunkqueue_remove_finished_chunks(req_cq);
+-
+- req_c = req_cq->first;
+- }
+-
+- break;
+- case MEM_CHUNK:
+- /* append to the buffer */
+- weHave = req_c->mem->used - 1 - req_c->offset;
+-
+- if (weHave > weWant - written) weHave = weWant - written;
+-
+- buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
++ chunkqueue_steal(hctx->wb, req_cq, weWant);
+
+- req_c->offset += weHave;
+- req_cq->bytes_out += weHave;
+- written += weHave;
+-
+- hctx->wb->bytes_in += weHave;
+-
+- if (req_c->offset == (off_t) req_c->mem->used - 1) {
+- chunkqueue_remove_finished_chunks(req_cq);
+-
+- req_c = req_cq->first;
+- }
+-
+- break;
+- default:
+- break;
+- }
+- }
+-
+- b->used++; /* add virtual \0 */
+ offset += weWant;
+ }
+ }
+
+- b = chunkqueue_get_append_buffer(hctx->wb);
+ /* terminate STDIN */
+ fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
+- buffer_copy_memory(b, (const char *)&header, sizeof(header));
+- b->used++; /* add virtual \0 */
++ chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header));
+
+ hctx->wb->bytes_in += sizeof(header);
+
+@@ -2201,7 +2108,7 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf
+
+ UNUSED(srv);
+
+- buffer_copy_string_buffer(p->parse_response, in);
++ buffer_copy_buffer(p->parse_response, in);
+
+ /* search for \n */
+ for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
+@@ -2381,7 +2288,7 @@ range_success: ;
+ }
+
+ buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
+- buffer_copy_off_t(dcls->value, sendfile2_content_length);
++ buffer_copy_int(dcls->value, sendfile2_content_length);
+ dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls);
+ if (dcls) dcls->free((data_unset*)dcls);
+
+@@ -2599,17 +2506,17 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ */
+
+ if (hctx->response_header->used == 0) {
+- buffer_copy_string_buffer(hctx->response_header, packet.b);
++ buffer_copy_buffer(hctx->response_header, packet.b);
+ } else {
+ buffer_append_string_buffer(hctx->response_header, packet.b);
+ }
+
+ if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
+- blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
++ blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4 - 1;
+ hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
+ c += 4; /* point the the start of the response */
+ } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
+- blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
++ blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2 - 1;
+ hctx->response_header->used = c - hctx->response_header->ptr + 2;
+ c += 2; /* point the the start of the response */
+ } else {
+@@ -2650,7 +2557,7 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ joblist_append(srv, con);
+
+ buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
+- buffer_copy_off_t(dcls->value, sce->st.st_size);
++ buffer_copy_int(dcls->value, sce->st.st_size);
+ dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls);
+ if (dcls) dcls->free((data_unset*)dcls);
+
+@@ -2668,7 +2575,7 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ }
+
+
+- if (hctx->send_content_body && blen > 1) {
++ if (hctx->send_content_body && blen > 0) {
+ /* enable chunked-transfer-encoding */
+ if (con->request.http_version == HTTP_VERSION_1_1 &&
+ !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
+@@ -2685,7 +2592,7 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
+ }
+
+- http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
++ http_chunk_append_buffer(srv, con, packet.b);
+ joblist_append(srv, con);
+ }
+ break;
+@@ -2703,7 +2610,7 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ !(con->http_status == 0 ||
+ con->http_status == 200)) {
+ /* send chunk-end if necessary */
+- http_chunk_append_mem(srv, con, NULL, 0);
++ http_chunk_close(srv, con);
+ joblist_append(srv, con);
+ }
+
+@@ -2820,7 +2727,7 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
+ /* local procs get restarted by us,
+ * remote ones hopefully by the admin */
+
+- if (!buffer_is_empty(host->bin_path)) {
++ if (!buffer_string_is_empty(host->bin_path)) {
+ /* we still have connections bound to this proc,
+ * let them terminate first */
+ if (proc->load != 0) break;
+@@ -3264,10 +3171,10 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) {
+ * now to handle authorized request.
+ */
+
+- buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
+- buffer_copy_string_buffer(con->physical.basedir, host->docroot);
++ buffer_copy_buffer(con->physical.doc_root, host->docroot);
++ buffer_copy_buffer(con->physical.basedir, host->docroot);
+
+- buffer_copy_string_buffer(con->physical.path, host->docroot);
++ buffer_copy_buffer(con->physical.path, host->docroot);
+ buffer_append_string_buffer(con->physical.path, con->uri.path);
+ fcgi_connection_close(srv, hctx);
+
+@@ -3486,7 +3393,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
+
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
+
+- if (buffer_is_empty(fn)) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(fn)) return HANDLER_GO_ON;
+
+ s_len = fn->used - 1;
+
+diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
+index 8041507..501f8e8 100644
+--- a/src/mod_flv_streaming.c
++++ b/src/mod_flv_streaming.c
+@@ -191,7 +191,7 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_flv_streaming_patch_connection(srv, con, p);
+
+@@ -214,7 +214,7 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+ * otherwise send the full file */
+
+ array_reset(p->get_params);
+- buffer_copy_string_buffer(p->query_str, con->uri.query);
++ buffer_copy_buffer(p->query_str, con->uri.query);
+ split_get_params(p->get_params, p->query_str);
+
+ if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
+diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
+index b46ead6..fe750c1 100644
+--- a/src/mod_indexfile.c
++++ b/src/mod_indexfile.c
+@@ -158,9 +158,9 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
+ if (ds->value && ds->value->ptr[0] == '/') {
+ /* if the index-file starts with a prefix as use this file as
+ * index-generator */
+- buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
++ buffer_copy_buffer(p->tmp_buf, con->physical.doc_root);
+ } else {
+- buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
++ buffer_copy_buffer(p->tmp_buf, con->physical.path);
+ }
+ buffer_append_string_buffer(p->tmp_buf, ds->value);
+
+@@ -192,7 +192,7 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
+
+ /* rewrite uri.path to the real path (/ -> /index.php) */
+ buffer_append_string_buffer(con->uri.path, ds->value);
+- buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
++ buffer_copy_buffer(con->physical.path, p->tmp_buf);
+
+ /* fce is already set up a few lines above */
+
+diff --git a/src/mod_magnet.c b/src/mod_magnet.c
+index cfdc976..80cb799 100644
+--- a/src/mod_magnet.c
++++ b/src/mod_magnet.c
+@@ -319,7 +319,7 @@ static int magnet_stat(lua_State *L) {
+ lua_setfield(L, -2, "st_ino");
+
+
+- if (!buffer_is_empty(sce->etag)) {
++ if (!buffer_string_is_empty(sce->etag)) {
+ /* we have to mutate the etag */
+ buffer *b = buffer_init();
+ etag_mutate(b, sce->etag);
+@@ -331,7 +331,7 @@ static int magnet_stat(lua_State *L) {
+ }
+ lua_setfield(L, -2, "etag");
+
+- if (!buffer_is_empty(sce->content_type)) {
++ if (!buffer_string_is_empty(sce->content_type)) {
+ lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1);
+ } else {
+ lua_pushnil(L);
+@@ -759,7 +759,7 @@ static int magnet_attach_content(server *srv, connection *con, plugin_data *p, l
+ size_t s_len = 0;
+ const char *s = lua_tolstring(L, -1, &s_len);
+
+- chunkqueue_append_mem(con->write_queue, s, s_len + 1);
++ chunkqueue_append_mem(con->write_queue, s, s_len);
+ } else if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "filename");
+ lua_getfield(L, -2, "length");
+@@ -1066,7 +1066,7 @@ static handler_t magnet_attract_array(server *srv, connection *con, plugin_data
+ data_string *ds = (data_string *)files->data[i];
+ handler_t ret;
+
+- if (buffer_is_empty(ds->value)) continue;
++ if (buffer_string_is_empty(ds->value)) continue;
+
+ ret = magnet_attract(srv, con, p, ds->value);
+
+diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c
+index 90c633e..0e9f72f 100644
+--- a/src/mod_magnet_cache.c
++++ b/src/mod_magnet_cache.c
+@@ -104,7 +104,7 @@ lua_State *script_cache_get_script(server *srv, connection *con, script_cache *c
+
+ cache->ptr[cache->used++] = sc;
+
+- buffer_copy_string_buffer(sc->name, name);
++ buffer_copy_buffer(sc->name, name);
+
+ sc->L = luaL_newstate();
+ luaL_openlibs(sc->L);
+@@ -119,7 +119,7 @@ lua_State *script_cache_get_script(server *srv, connection *con, script_cache *c
+ }
+
+ if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+- buffer_copy_string_buffer(sc->etag, sce->etag);
++ buffer_copy_buffer(sc->etag, sce->etag);
+ }
+
+ /**
+diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
+index a02ed2c..8442f76 100644
+--- a/src/mod_mysql_vhost.c
++++ b/src/mod_mysql_vhost.c
+@@ -227,7 +227,7 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
+ buffer_copy_string(s->mysql_pre, sel->ptr);
+ buffer_copy_string(s->mysql_post, qmark+1);
+ } else {
+- buffer_copy_string_buffer(s->mysql_pre, sel);
++ buffer_copy_buffer(s->mysql_pre, sel);
+ }
+
+ /* required:
+@@ -242,8 +242,8 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
+ */
+
+ /* all have to be set */
+- if (!(buffer_is_empty(s->myuser) ||
+- buffer_is_empty(s->mydb))) {
++ if (!(buffer_string_is_empty(s->myuser) ||
++ buffer_string_is_empty(s->mydb))) {
+ my_bool reconnect = 1;
+
+ if (NULL == (s->mysql = mysql_init(NULL))) {
+@@ -349,7 +349,7 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+ buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
+
+ /* build and run SQL query */
+- buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
++ buffer_copy_buffer(p->tmp_buf, p->conf.mysql_pre);
+ if (p->conf.mysql_post->used) {
+ /* escape the uri.authority */
+ unsigned long to_len;
+@@ -382,7 +382,7 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+
+ /* sanity check that really is a directory */
+ buffer_copy_string(p->tmp_buf, row[0]);
+- BUFFER_APPEND_SLASH(p->tmp_buf);
++ buffer_append_slash(p->tmp_buf);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
+@@ -394,8 +394,8 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+ }
+
+ /* cache the data */
+- buffer_copy_string_buffer(c->server_name, con->uri.authority);
+- buffer_copy_string_buffer(c->document_root, p->tmp_buf);
++ buffer_copy_buffer(c->server_name, con->uri.authority);
++ buffer_copy_buffer(c->document_root, p->tmp_buf);
+
+ /* fcgi_offset and fcgi_arg are optional */
+ if (cols > 1 && row[1]) {
+@@ -416,8 +416,8 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+
+ /* fix virtual server and docroot */
+ GO_ON:
+- buffer_copy_string_buffer(con->server_name, c->server_name);
+- buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
++ buffer_copy_buffer(con->server_name, c->server_name);
++ buffer_copy_buffer(con->physical.doc_root, c->document_root);
+
+ #ifdef DEBUG
+ log_error_write(srv, __FILE__, __LINE__, "sbbdb",
+diff --git a/src/mod_proxy.c b/src/mod_proxy.c
+index 957a5a2..3bfc78f 100644
+--- a/src/mod_proxy.c
++++ b/src/mod_proxy.c
+@@ -217,7 +217,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (buffer_is_empty(p->balance_buf)) {
++ if (buffer_string_is_empty(p->balance_buf)) {
+ s->balance = PROXY_BALANCE_FAIR;
+ } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
+ s->balance = PROXY_BALANCE_FAIR;
+@@ -292,7 +292,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
+
+ df->port = 80;
+
+- buffer_copy_string_buffer(df->key, da_host->key);
++ buffer_copy_buffer(df->key, da_host->key);
+
+ pcv[0].destination = df->host;
+ pcv[1].destination = &(df->port);
+@@ -302,7 +302,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (buffer_is_empty(df->host)) {
++ if (buffer_string_is_empty(df->host)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbbbs",
+ "missing key (string):",
+ da->key,
+@@ -319,7 +319,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
+ if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
+ dfa = data_array_init();
+
+- buffer_copy_string_buffer(dfa->key, da_ext->key);
++ buffer_copy_buffer(dfa->key, da_ext->key);
+
+ array_insert_unique(dfa->value, (data_unset *)df);
+ array_insert_unique(s->extensions, (data_unset *)dfa);
+@@ -461,8 +461,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
+ proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
+ /* http_host is NOT is just a pointer to a buffer
+ * which is NULL if it is not set */
+- if (con->request.http_host &&
+- !buffer_is_empty(con->request.http_host)) {
++ if (!buffer_string_is_empty(con->request.http_host)) {
+ proxy_set_header(con, "X-Host", con->request.http_host->ptr);
+ }
+ proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr);
+@@ -491,55 +490,8 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
+
+ if (con->request.content_length) {
+ chunkqueue *req_cq = con->request_content_queue;
+- chunk *req_c;
+- off_t offset;
+-
+- /* something to send ? */
+- for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) {
+- off_t weWant = req_cq->bytes_in - offset;
+- off_t weHave = 0;
+-
+- /* we announce toWrite octects
+- * now take all the request_content chunk that we need to fill this request
+- * */
+-
+- switch (req_c->type) {
+- case FILE_CHUNK:
+- weHave = req_c->file.length - req_c->offset;
+-
+- if (weHave > weWant) weHave = weWant;
+-
+- chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
+-
+- req_c->offset += weHave;
+- req_cq->bytes_out += weHave;
+-
+- hctx->wb->bytes_in += weHave;
+-
+- break;
+- case MEM_CHUNK:
+- /* append to the buffer */
+- weHave = req_c->mem->used - 1 - req_c->offset;
+-
+- if (weHave > weWant) weHave = weWant;
+-
+- b = chunkqueue_get_append_buffer(hctx->wb);
+- buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
+- b->used++; /* add virtual \0 */
+-
+- req_c->offset += weHave;
+- req_cq->bytes_out += weHave;
+-
+- hctx->wb->bytes_in += weHave;
+-
+- break;
+- default:
+- break;
+- }
+-
+- offset += weHave;
+- }
+
++ chunkqueue_steal(hctx->wb, req_cq, req_cq->bytes_in);
+ }
+
+ return 0;
+@@ -561,7 +513,7 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu
+
+ /* \r\n -> \0\0 */
+
+- buffer_copy_string_buffer(p->parse_response, in);
++ buffer_copy_buffer(p->parse_response, in);
+
+ for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
+ char *key, *value;
+@@ -705,12 +657,12 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+ char *c;
+
+ /* search for the \r\n\r\n in the string */
+- if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
++ if (NULL != (c = buffer_search_string_len(hctx->response, CONST_STR_LEN("\r\n\r\n")))) {
+ size_t hlen = c - hctx->response->ptr + 4;
+ size_t blen = hctx->response->used - hlen - 1;
+ /* found */
+
+- buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
++ buffer_append_string_len(hctx->response_header, hctx->response->ptr, hlen);
+ #if 0
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
+ #endif
+@@ -724,14 +676,12 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+ }
+
+ con->file_started = 1;
+- if (blen) {
+- http_chunk_append_mem(srv, con, c + 4, blen + 1);
+- }
++ if (blen > 0) http_chunk_append_mem(srv, con, c + 4, blen);
+ hctx->response->used = 0;
+ joblist_append(srv, con);
+ }
+ } else {
+- http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
++ http_chunk_append_buffer(srv, con, hctx->response);
+ joblist_append(srv, con);
+ hctx->response->used = 0;
+ }
+@@ -740,7 +690,7 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+ /* reading from upstream done */
+ con->file_finished = 1;
+
+- http_chunk_append_mem(srv, con, NULL, 0);
++ http_chunk_close(srv, con);
+ joblist_append(srv, con);
+
+ fin = 1;
+@@ -976,6 +926,7 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) {
+ case 1:
+ /* we are done */
+ proxy_connection_close(srv, hctx);
++ log_error_write(srv, __FILE__, __LINE__, "s", "proxy request finished");
+
+ joblist_append(srv, con);
+ return HANDLER_FINISHED;
+@@ -1092,7 +1043,7 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) {
+ }
+
+ if (!con->file_finished) {
+- http_chunk_append_mem(srv, con, NULL, 0);
++ http_chunk_close(srv, con);
+ }
+
+ con->file_finished = 1;
+diff --git a/src/mod_redirect.c b/src/mod_redirect.c
+index bfc00d7..93cecb7 100644
+--- a/src/mod_redirect.c
++++ b/src/mod_redirect.c
+@@ -183,7 +183,7 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
+
+ mod_redirect_patch_connection(srv, con, p);
+
+- buffer_copy_string_buffer(p->match_buf, con->request.uri);
++ buffer_copy_buffer(p->match_buf, con->request.uri);
+
+ for (i = 0; i < p->conf.redirect->used; i++) {
+ pcre *match;
+diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
+index 381f0ed..48c0987 100644
+--- a/src/mod_rewrite.c
++++ b/src/mod_rewrite.c
+@@ -101,7 +101,7 @@ static int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buf
+ }
+
+ kvb->ptr[kvb->used]->value = buffer_init();
+- buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
++ buffer_copy_buffer(kvb->ptr[kvb->used]->value, value);
+ kvb->ptr[kvb->used]->once = once;
+
+ kvb->used++;
+@@ -359,7 +359,7 @@ static int process_rewrite_rules(server *srv, connection *con, plugin_data *p, r
+ if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
+ }
+
+- buffer_copy_string_buffer(p->match_buf, con->request.uri);
++ buffer_copy_buffer(p->match_buf, con->request.uri);
+
+ for (i = 0; i < kvb->used; i++) {
+ pcre *match;
+diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
+index df2a781..4986ea3 100644
+--- a/src/mod_rrdtool.c
++++ b/src/mod_rrdtool.c
+@@ -366,7 +366,7 @@ SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
++ if (i > 0 && !buffer_string_is_empty(s->path_rrdtool_bin)) {
+ /* path_rrdtool_bin is a global option */
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+@@ -382,7 +382,7 @@ SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
+
+ /* check for dir */
+
+- if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
++ if (buffer_string_is_empty(p->conf.path_rrdtool_bin)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "rrdtool.binary has to be set");
+ return HANDLER_ERROR;
+@@ -409,7 +409,7 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ plugin_config *s = p->config_storage[i];
+ int r;
+
+- if (buffer_is_empty(s->path_rrd)) continue;
++ if (buffer_string_is_empty(s->path_rrd)) continue;
+
+ /* write the data down every minute */
+
+@@ -418,11 +418,11 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ buffer_copy_string_len(p->cmd, CONST_STR_LEN("update "));
+ buffer_append_string_buffer(p->cmd, s->path_rrd);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(" N:"));
+- buffer_append_off_t(p->cmd, s->bytes_read);
++ buffer_append_int(p->cmd, s->bytes_read);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
+- buffer_append_off_t(p->cmd, s->bytes_written);
++ buffer_append_int(p->cmd, s->bytes_written);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
+- buffer_append_long(p->cmd, s->requests);
++ buffer_append_int(p->cmd, s->requests);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN("\n"));
+
+ if (-1 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
+diff --git a/src/mod_scgi.c b/src/mod_scgi.c
+index 1c16c2d..66dce5e 100644
+--- a/src/mod_scgi.c
++++ b/src/mod_scgi.c
+@@ -306,7 +306,6 @@ typedef struct {
+
+ int reconnects; /* number of reconnect attempts */
+
+- read_buffer *rb;
+ chunkqueue *wb;
+
+ buffer *response_header;
+@@ -380,11 +379,6 @@ static void handler_ctx_free(handler_ctx *hctx) {
+
+ chunkqueue_free(hctx->wb);
+
+- if (hctx->rb) {
+- if (hctx->rb->ptr) free(hctx->rb->ptr);
+- free(hctx->rb);
+- }
+-
+ free(hctx);
+ }
+
+@@ -497,7 +491,7 @@ static int scgi_extension_insert(scgi_exts *ext, buffer *key, scgi_extension_hos
+ fe = calloc(1, sizeof(*fe));
+ force_assert(fe);
+ fe->key = buffer_init();
+- buffer_copy_string_buffer(fe->key, key);
++ buffer_copy_buffer(fe->key, key);
+
+ /* */
+
+@@ -579,7 +573,7 @@ FREE_FUNC(mod_scgi_free) {
+ if (proc->pid != 0) kill(proc->pid, SIGTERM);
+
+ if (proc->is_local &&
+- !buffer_is_empty(proc->socket)) {
++ !buffer_string_is_empty(proc->socket)) {
+ unlink(proc->socket->ptr);
+ }
+ }
+@@ -588,7 +582,7 @@ FREE_FUNC(mod_scgi_free) {
+ if (proc->pid != 0) kill(proc->pid, SIGTERM);
+
+ if (proc->is_local &&
+- !buffer_is_empty(proc->socket)) {
++ !buffer_string_is_empty(proc->socket)) {
+ unlink(proc->socket->ptr);
+ }
+ }
+@@ -665,7 +659,7 @@ static int scgi_spawn_connection(server *srv,
+ "new proc, socket:", proc->port, proc->socket);
+ }
+
+- if (!buffer_is_empty(proc->socket)) {
++ if (!buffer_string_is_empty(proc->socket)) {
+ memset(&scgi_addr, 0, sizeof(scgi_addr));
+
+ #ifdef HAVE_SYS_UN_H
+@@ -694,7 +688,7 @@ static int scgi_spawn_connection(server *srv,
+ } else {
+ scgi_addr_in.sin_family = AF_INET;
+
+- if (buffer_is_empty(host->host)) {
++ if (buffer_string_is_empty(host->host)) {
+ scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
+ } else {
+ struct hostent *he;
+@@ -741,7 +735,7 @@ static int scgi_spawn_connection(server *srv,
+ pid_t child;
+ int val;
+
+- if (!buffer_is_empty(proc->socket)) {
++ if (!buffer_string_is_empty(proc->socket)) {
+ unlink(proc->socket->ptr);
+ }
+
+@@ -1066,15 +1060,15 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ goto error;
+ }
+
+- if ((!buffer_is_empty(df->host) || df->port) &&
+- !buffer_is_empty(df->unixsocket)) {
++ if ((!buffer_string_is_empty(df->host) || df->port) &&
++ !buffer_string_is_empty(df->unixsocket)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "either host+port or socket");
+
+ goto error;
+ }
+
+- if (!buffer_is_empty(df->unixsocket)) {
++ if (!buffer_string_is_empty(df->unixsocket)) {
+ /* unix domain socket */
+ struct sockaddr_un un;
+
+@@ -1086,8 +1080,8 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ } else {
+ /* tcp/ip */
+
+- if (buffer_is_empty(df->host) &&
+- buffer_is_empty(df->bin_path)) {
++ if (buffer_string_is_empty(df->host) &&
++ buffer_string_is_empty(df->bin_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbbbs",
+ "missing key (string):",
+ da->key,
+@@ -1107,7 +1101,7 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ }
+ }
+
+- if (!buffer_is_empty(df->bin_path)) {
++ if (!buffer_string_is_empty(df->bin_path)) {
+ /* a local socket + self spawning */
+ size_t pno;
+
+@@ -1134,12 +1128,12 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ proc->id = df->num_procs++;
+ df->max_id++;
+
+- if (buffer_is_empty(df->unixsocket)) {
++ if (buffer_string_is_empty(df->unixsocket)) {
+ proc->port = df->port + pno;
+ } else {
+- buffer_copy_string_buffer(proc->socket, df->unixsocket);
++ buffer_copy_buffer(proc->socket, df->unixsocket);
+ buffer_append_string_len(proc->socket, CONST_STR_LEN("-"));
+- buffer_append_long(proc->socket, pno);
++ buffer_append_int(proc->socket, pno);
+ }
+
+ if (s->debug) {
+@@ -1171,10 +1165,10 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ df->active_procs++;
+ fp->state = PROC_STATE_RUNNING;
+
+- if (buffer_is_empty(df->unixsocket)) {
++ if (buffer_string_is_empty(df->unixsocket)) {
+ fp->port = df->port;
+ } else {
+- buffer_copy_string_buffer(fp->socket, df->unixsocket);
++ buffer_copy_buffer(fp->socket, df->unixsocket);
+ }
+
+ df->first = fp;
+@@ -1342,7 +1336,7 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
+
+ memset(&scgi_addr, 0, sizeof(scgi_addr));
+
+- if (!buffer_is_empty(proc->socket)) {
++ if (!buffer_string_is_empty(proc->socket)) {
+ #ifdef HAVE_SYS_UN_H
+ /* use the unix domain socket */
+ scgi_addr_un.sun_family = AF_UNIX;
+@@ -1471,7 +1465,7 @@ static int scgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+
+
+ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+- char buf[32];
++ char buf[LI_ITOSTRING_LENGTH];
+ const char *s;
+ #ifdef HAVE_IPV6
+ char b2[INET6_ADDRSTRLEN + 1];
+@@ -1491,8 +1485,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
+
+- /* request.content_length < SSIZE_MAX, see request.c */
+- LI_ltostr(buf, con->request.content_length);
++ li_itostr(buf, con->request.content_length);
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
+
+@@ -1530,7 +1523,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
+ #else
+@@ -1550,7 +1543,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ }
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
+ #else
+@@ -1571,15 +1564,15 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
+
+- if (!buffer_is_empty(con->request.pathinfo)) {
++ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
+
+ /* PATH_TRANSLATED is only defined if PATH_INFO is set */
+
+- if (!buffer_is_empty(host->docroot)) {
+- buffer_copy_string_buffer(p->path, host->docroot);
++ if (!buffer_string_is_empty(host->docroot)) {
++ buffer_copy_buffer(p->path, host->docroot);
+ } else {
+- buffer_copy_string_buffer(p->path, con->physical.basedir);
++ buffer_copy_buffer(p->path, con->physical.basedir);
+ }
+ 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));
+@@ -1595,19 +1588,19 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ * parameter.
+ */
+
+- if (!buffer_is_empty(host->docroot)) {
++ if (!buffer_string_is_empty(host->docroot)) {
+ /*
+ * rewrite SCRIPT_FILENAME
+ *
+ */
+
+- buffer_copy_string_buffer(p->path, host->docroot);
++ buffer_copy_buffer(p->path, host->docroot);
+ buffer_append_string_buffer(p->path, con->uri.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(host->docroot));
+ } else {
+- buffer_copy_string_buffer(p->path, con->physical.path);
++ buffer_copy_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));
+@@ -1616,7 +1609,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
+ }
+- if (!buffer_is_empty(con->uri.query)) {
++ if (!buffer_string_is_empty(con->uri.query)) {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
+ } else {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
+@@ -1638,7 +1631,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ b = chunkqueue_get_append_buffer(hctx->wb);
+
+- buffer_append_long(b, p->scgi_env->used);
++ buffer_append_int(b, p->scgi_env->used);
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
+ buffer_append_string_len(b, CONST_STR_LEN(","));
+@@ -1647,54 +1640,8 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ if (con->request.content_length) {
+ chunkqueue *req_cq = con->request_content_queue;
+- chunk *req_c;
+- off_t offset;
+-
+- /* something to send ? */
+- for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) {
+- off_t weWant = req_cq->bytes_in - offset;
+- off_t weHave = 0;
+-
+- /* we announce toWrite octects
+- * now take all the request_content chunk that we need to fill this request
+- * */
+-
+- switch (req_c->type) {
+- case FILE_CHUNK:
+- weHave = req_c->file.length - req_c->offset;
+-
+- if (weHave > weWant) weHave = weWant;
+-
+- chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
+-
+- req_c->offset += weHave;
+- req_cq->bytes_out += weHave;
+-
+- hctx->wb->bytes_in += weHave;
+-
+- break;
+- case MEM_CHUNK:
+- /* append to the buffer */
+- weHave = req_c->mem->used - 1 - req_c->offset;
+
+- if (weHave > weWant) weHave = weWant;
+-
+- b = chunkqueue_get_append_buffer(hctx->wb);
+- buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
+- b->used++; /* add virtual \0 */
+-
+- req_c->offset += weHave;
+- req_cq->bytes_out += weHave;
+-
+- hctx->wb->bytes_in += weHave;
+-
+- break;
+- default:
+- break;
+- }
+-
+- offset += weHave;
+- }
++ chunkqueue_steal(hctx->wb, req_cq, req_cq->bytes_in);
+ }
+
+ return 0;
+@@ -1707,7 +1654,7 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf
+
+ UNUSED(srv);
+
+- buffer_copy_string_buffer(p->parse_response, in);
++ buffer_copy_buffer(p->parse_response, in);
+
+ for (s = p->parse_response->ptr;
+ NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
+@@ -1827,7 +1774,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->file_finished = 1;
+
+ /* send final chunk */
+- http_chunk_append_mem(srv, con, NULL, 0);
++ http_chunk_close(srv, con);
+ joblist_append(srv, con);
+
+ return 1;
+@@ -1905,7 +1852,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
+ }
+
+- http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
++ http_chunk_append_buffer(srv, con, hctx->response_header);
+ joblist_append(srv, con);
+ } else {
+ size_t blen = hctx->response_header->used - hlen - 1;
+@@ -1924,7 +1871,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ }
+
+ if ((hctx->response->used != hlen) && blen > 0) {
+- http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen + 1);
++ http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen);
+ joblist_append(srv, con);
+ }
+ }
+@@ -1932,7 +1879,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->file_started = 1;
+ }
+ } else {
+- http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
++ http_chunk_append_buffer(srv, con, hctx->response);
+ joblist_append(srv, con);
+ }
+
+@@ -2727,7 +2674,7 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
+
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
+
+- if (buffer_is_empty(fn)) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(fn)) return HANDLER_GO_ON;
+
+ s_len = fn->used - 1;
+
+@@ -3007,12 +2954,12 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) {
+
+ host->num_procs++;
+
+- if (buffer_is_empty(host->unixsocket)) {
++ if (buffer_string_is_empty(host->unixsocket)) {
+ fp->port = host->port + fp->id;
+ } else {
+- buffer_copy_string_buffer(fp->socket, host->unixsocket);
++ buffer_copy_buffer(fp->socket, host->unixsocket);
+ buffer_append_string_len(fp->socket, CONST_STR_LEN("-"));
+- buffer_append_long(fp->socket, fp->id);
++ buffer_append_int(fp->socket, fp->id);
+ }
+
+ if (scgi_spawn_connection(srv, p, host, fp)) {
+diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
+index c32a3ac..d94482e 100644
+--- a/src/mod_secure_download.c
++++ b/src/mod_secure_download.c
+@@ -204,13 +204,13 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+
+ if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
+
+- if (buffer_is_empty(p->conf.secret)) {
++ if (buffer_string_is_empty(p->conf.secret)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "secdownload.secret has to be set");
+ return HANDLER_ERROR;
+ }
+
+- if (buffer_is_empty(p->conf.doc_root)) {
++ if (buffer_string_is_empty(p->conf.doc_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "secdownload.document-root has to be set");
+ return HANDLER_ERROR;
+@@ -233,7 +233,7 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+ if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
+
+ for (i = 0; i < 8; i++) {
+- ts = (ts << 4) + hex2int(*(ts_str + i));
++ ts = (ts << 4) + hex2int(ts_str[i]);
+ }
+
+ /* timed-out */
+@@ -252,7 +252,7 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+ * <secret><rel-path><timestamp-hex>
+ */
+
+- buffer_copy_string_buffer(p->md5, p->conf.secret);
++ buffer_copy_buffer(p->md5, p->conf.secret);
+ buffer_append_string(p->md5, rel_uri);
+ buffer_append_string_len(p->md5, ts_str, 8);
+ force_assert(p->md5->used > 0);
+@@ -276,10 +276,10 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+ /* starting with the last / we should have relative-path to the docroot
+ */
+
+- buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
+- buffer_copy_string_buffer(con->physical.basedir, p->conf.doc_root);
++ buffer_copy_buffer(con->physical.doc_root, p->conf.doc_root);
++ buffer_copy_buffer(con->physical.basedir, p->conf.doc_root);
+ buffer_copy_string(con->physical.rel_path, rel_uri);
+- buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
++ buffer_copy_buffer(con->physical.path, con->physical.doc_root);
+ buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
+
+ return HANDLER_GO_ON;
+diff --git a/src/mod_setenv.c b/src/mod_setenv.c
+index ad91609..60e9b55 100644
+--- a/src/mod_setenv.c
++++ b/src/mod_setenv.c
+@@ -185,8 +185,8 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) {
+ ds_dst = data_string_init();
+ }
+
+- buffer_copy_string_buffer(ds_dst->key, ds->key);
+- buffer_copy_string_buffer(ds_dst->value, ds->value);
++ buffer_copy_buffer(ds_dst->key, ds->key);
++ buffer_copy_buffer(ds_dst->value, ds->value);
+
+ array_insert_unique(con->request.headers, (data_unset *)ds_dst);
+ }
+@@ -199,8 +199,8 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) {
+ ds_dst = data_string_init();
+ }
+
+- buffer_copy_string_buffer(ds_dst->key, ds->key);
+- buffer_copy_string_buffer(ds_dst->value, ds->value);
++ buffer_copy_buffer(ds_dst->key, ds->key);
++ buffer_copy_buffer(ds_dst->value, ds->value);
+
+ array_insert_unique(con->environment, (data_unset *)ds_dst);
+ }
+diff --git a/src/mod_simple_vhost.c b/src/mod_simple_vhost.c
+index 1240fda..7245fd5 100644
+--- a/src/mod_simple_vhost.c
++++ b/src/mod_simple_vhost.c
+@@ -127,7 +127,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
+ force_assert(p->conf.server_root->used > 1);
+
+ buffer_prepare_copy(out, 128);
+- buffer_copy_string_buffer(out, p->conf.server_root);
++ buffer_copy_buffer(out, p->conf.server_root);
+
+ if (host->used) {
+ /* a hostname has to start with a alpha-numerical character
+@@ -135,7 +135,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
+ */
+ char *dp;
+
+- BUFFER_APPEND_SLASH(out);
++ buffer_append_slash(out);
+
+ if (NULL == (dp = strchr(host->ptr, ':'))) {
+ buffer_append_string_buffer(out, host);
+@@ -143,13 +143,13 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
+ buffer_append_string_len(out, host->ptr, dp - host->ptr);
+ }
+ }
+- BUFFER_APPEND_SLASH(out);
++ buffer_append_slash(out);
+
+ if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
+ buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
+ } else {
+ buffer_append_string_buffer(out, p->conf.document_root);
+- BUFFER_APPEND_SLASH(out);
++ buffer_append_slash(out);
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
+@@ -233,8 +233,8 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_
+ con->uri.authority->used &&
+ buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
+ /* cache hit */
+- buffer_copy_string_buffer(con->server_name, p->conf.docroot_cache_servername);
+- buffer_copy_string_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
++ buffer_copy_buffer(con->server_name, p->conf.docroot_cache_servername);
++ buffer_copy_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
+ } else {
+ /* build document-root */
+ if ((con->uri.authority->used == 0) ||
+@@ -244,21 +244,21 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_
+ p->doc_root,
+ p->conf.default_host)) {
+ /* default host worked */
+- buffer_copy_string_buffer(con->server_name, p->conf.default_host);
+- buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
++ buffer_copy_buffer(con->server_name, p->conf.default_host);
++ buffer_copy_buffer(con->physical.doc_root, p->doc_root);
+ /* do not cache default host */
+ }
+ return HANDLER_GO_ON;
+ }
+
+ /* found host */
+- buffer_copy_string_buffer(con->server_name, con->uri.authority);
+- buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
++ buffer_copy_buffer(con->server_name, con->uri.authority);
++ buffer_copy_buffer(con->physical.doc_root, p->doc_root);
+
+ /* copy to cache */
+- buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
+- buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
+- buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
++ buffer_copy_buffer(p->conf.docroot_cache_key, con->uri.authority);
++ buffer_copy_buffer(p->conf.docroot_cache_value, p->doc_root);
++ buffer_copy_buffer(p->conf.docroot_cache_servername, con->server_name);
+ }
+
+ return HANDLER_GO_ON;
+diff --git a/src/mod_ssi.c b/src/mod_ssi.c
+index 0c1cdba..38eeac5 100644
+--- a/src/mod_ssi.c
++++ b/src/mod_ssi.c
+@@ -236,7 +236,7 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
+ }
+
+ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
+- char buf[32];
++ char buf[LI_ITOSTRING_LENGTH];
+
+ server_socket *srv_sock = con->srv_socket;
+
+@@ -263,7 +263,7 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
+ );
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
+
+- LI_ltostr(buf,
++ li_utostr(buf,
+ #ifdef HAVE_IPV6
+ ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
+ #else
+@@ -279,8 +279,7 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
+ if (con->request.content_length > 0) {
+ /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
+
+- /* request.content_length < SSIZE_MAX, see request.c */
+- LI_ltostr(buf, con->request.content_length);
++ li_itostr(buf, con->request.content_length);
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
+ }
+
+@@ -434,12 +433,12 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ b = chunkqueue_get_append_buffer(con->write_queue);
+ #ifdef HAVE_PWD_H
+ if (NULL == (pw = getpwuid(sce->st.st_uid))) {
+- buffer_copy_long(b, sce->st.st_uid);
++ buffer_copy_int(b, sce->st.st_uid);
+ } else {
+ buffer_copy_string(b, pw->pw_name);
+ }
+ #else
+- buffer_copy_long(b, sce->st.st_uid);
++ buffer_copy_int(b, sce->st.st_uid);
+ #endif
+ break;
+ }
+@@ -481,7 +480,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+
+ b = chunkqueue_get_append_buffer(con->write_queue);
+ if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
+- buffer_copy_string_buffer(b, con->physical.path);
++ buffer_copy_buffer(b, con->physical.path);
+ } else {
+ buffer_copy_string(b, sl + 1);
+ }
+@@ -489,7 +488,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ }
+ case SSI_ECHO_DOCUMENT_URI: {
+ b = chunkqueue_get_append_buffer(con->write_queue);
+- buffer_copy_string_buffer(b, con->uri.path);
++ buffer_copy_buffer(b, con->uri.path);
+ break;
+ }
+ default: {
+@@ -499,7 +498,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
+- buffer_copy_string_buffer(b, ds->value);
++ buffer_copy_buffer(b, ds->value);
+ } else {
+ buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
+ }
+@@ -575,7 +574,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+
+ /* we have an uri */
+
+- buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
++ buffer_copy_buffer(p->stat_fn, con->physical.doc_root);
+ buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
+ }
+
+@@ -593,10 +592,10 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+
+ for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
+
+- buffer_copy_off_t(b, s);
++ buffer_copy_int(b, s);
+ buffer_append_string(b, abr[j]);
+ } else {
+- buffer_copy_off_t(b, st.st_size);
++ buffer_copy_int(b, st.st_size);
+ }
+ break;
+ case SSI_FLASTMOD:
+@@ -783,19 +782,19 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ int toread;
+ /* read everything from client and paste it into the output */
+ was_interrupted = 0;
+-
++
+ while(1) {
+ if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected end-of-file (perhaps the ssi-exec process died)");
+ return -1;
+ }
+-
++
+ if (toread > 0) {
+ b = chunkqueue_get_append_buffer(con->write_queue);
+-
+- buffer_prepare_copy(b, toread + 1);
+-
++
++ buffer_prepare_copy(b, toread);
++
+ if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
+ /* read failed */
+ break;
+diff --git a/src/mod_ssi_expr.c b/src/mod_ssi_expr.c
+index f839987..140d086 100644
+--- a/src/mod_ssi_expr.c
++++ b/src/mod_ssi_expr.c
+@@ -215,9 +215,9 @@ static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p,
+ tid = TK_VALUE;
+
+ if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
+- buffer_copy_string_buffer(token, ds->value);
++ buffer_copy_buffer(token, ds->value);
+ } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
+- buffer_copy_string_buffer(token, ds->value);
++ buffer_copy_buffer(token, ds->value);
+ } else {
+ buffer_copy_string_len(token, CONST_STR_LEN(""));
+ }
+diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
+index af0718e..931bc57 100644
+--- a/src/mod_staticfile.c
++++ b/src/mod_staticfile.c
+@@ -294,11 +294,11 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+
+ /* write Content-Range */
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));
+- buffer_append_off_t(b, start);
++ buffer_append_int(b, start);
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+- buffer_append_off_t(b, end);
++ buffer_append_int(b, end);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+- buffer_append_off_t(b, sce->st.st_size);
++ buffer_append_int(b, sce->st.st_size);
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: "));
+ buffer_append_string_buffer(b, content_type);
+@@ -341,11 +341,11 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+ /* add Content-Range-header */
+
+ buffer_copy_string_len(p->range_buf, CONST_STR_LEN("bytes "));
+- buffer_append_off_t(p->range_buf, start);
++ buffer_append_int(p->range_buf, start);
+ buffer_append_string_len(p->range_buf, CONST_STR_LEN("-"));
+- buffer_append_off_t(p->range_buf, end);
++ buffer_append_int(p->range_buf, end);
+ buffer_append_string_len(p->range_buf, CONST_STR_LEN("/"));
+- buffer_append_off_t(p->range_buf, sce->st.st_size);
++ buffer_append_int(p->range_buf, sce->st.st_size);
+
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
+ }
+@@ -449,7 +449,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
+ /* set response content-type, if not set already */
+
+ if (NULL == array_get_element(con->response.headers, "Content-Type")) {
+- if (buffer_is_empty(sce->content_type)) {
++ if (buffer_string_is_empty(sce->content_type)) {
+ /* we are setting application/octet-stream, but also announce that
+ * this header field might change in the seconds few requests
+ *
+@@ -469,7 +469,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
+ }
+
+ if (allow_caching) {
+- if (p->conf.etags_used && con->etag_flags != 0 && !buffer_is_empty(sce->etag)) {
++ if (p->conf.etags_used && con->etag_flags != 0 && !buffer_string_is_empty(sce->etag)) {
+ if (NULL == array_get_element(con->response.headers, "ETag")) {
+ /* generate e-tag */
+ etag_mutate(con->physical.etag, sce->etag);
+diff --git a/src/mod_status.c b/src/mod_status.c
+index f0d753b..e8da0a8 100644
+--- a/src/mod_status.c
++++ b/src/mod_status.c
+@@ -323,21 +323,21 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+ seconds = ts;
+
+ if (days) {
+- buffer_append_long(b, days);
++ buffer_append_int(b, days);
+ buffer_append_string_len(b, CONST_STR_LEN(" days "));
+ }
+
+ if (hours) {
+- buffer_append_long(b, hours);
++ buffer_append_int(b, hours);
+ buffer_append_string_len(b, CONST_STR_LEN(" hours "));
+ }
+
+ if (mins) {
+- buffer_append_long(b, mins);
++ buffer_append_int(b, mins);
+ buffer_append_string_len(b, CONST_STR_LEN(" min "));
+ }
+
+- buffer_append_long(b, seconds);
++ buffer_append_int(b, seconds);
+ buffer_append_string_len(b, CONST_STR_LEN(" s"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+@@ -357,7 +357,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ mod_status_get_multiplier(&avg, &multiplier, 1000);
+
+- buffer_append_long(b, avg);
++ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("req</td></tr>\n"));
+@@ -382,7 +382,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ mod_status_get_multiplier(&avg, &multiplier, 1000);
+
+- buffer_append_long(b, avg);
++ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
+@@ -411,7 +411,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ mod_status_get_multiplier(&avg, &multiplier, 1000);
+
+- buffer_append_long(b, avg);
++ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+
+@@ -444,7 +444,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+ "s = response-start, S = response-end\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<b>"));
+- buffer_append_long(b, srv->conns->used);
++ buffer_append_int(b, srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN(" connections</b>\n"));
+
+ for (j = 0; j < srv->conns->used; j++) {
+@@ -488,18 +488,18 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+ if (c->request.content_length) {
+- buffer_append_long(b, c->request_content_queue->bytes_in);
++ buffer_append_int(b, c->request_content_queue->bytes_in);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+- buffer_append_long(b, c->request.content_length);
++ buffer_append_int(b, c->request.content_length);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("0/0"));
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+- buffer_append_off_t(b, chunkqueue_written(c->write_queue));
++ buffer_append_int(b, c->write_queue->bytes_out);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+- buffer_append_off_t(b, chunkqueue_length(c->write_queue));
++ buffer_append_int(b, c->write_queue->bytes_out + chunkqueue_length(c->write_queue));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+@@ -511,11 +511,11 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+- buffer_append_long(b, srv->cur_ts - c->request_start);
++ buffer_append_int(b, srv->cur_ts - c->request_start);
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+- if (buffer_is_empty(c->server_name)) {
++ if (buffer_string_is_empty(c->server_name)) {
+ buffer_append_string_buffer(b, c->uri.authority);
+ }
+ else {
+@@ -524,16 +524,16 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+- if (!buffer_is_empty(c->uri.path)) {
++ if (!buffer_string_is_empty(c->uri.path)) {
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
+ }
+
+- if (!buffer_is_empty(c->uri.query)) {
++ if (!buffer_string_is_empty(c->uri.query)) {
+ buffer_append_string_len(b, CONST_STR_LEN("?"));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.query), ENCODING_HTML);
+ }
+
+- if (!buffer_is_empty(c->request.orig_uri)) {
++ if (!buffer_string_is_empty(c->request.orig_uri)) {
+ buffer_append_string_len(b, CONST_STR_LEN(" ("));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->request.orig_uri), ENCODING_HTML);
+ buffer_append_string_len(b, CONST_STR_LEN(")"));
+@@ -589,16 +589,16 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
+ /* output uptime */
+ buffer_append_string_len(b, CONST_STR_LEN("Uptime: "));
+ ts = srv->cur_ts - srv->startup_ts;
+- buffer_append_long(b, ts);
++ buffer_append_int(b, ts);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output busy servers */
+ buffer_append_string_len(b, CONST_STR_LEN("BusyServers: "));
+- buffer_append_long(b, srv->conns->used);
++ buffer_append_int(b, srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
+- buffer_append_long(b, srv->conns->size - srv->conns->used);
++ buffer_append_int(b, srv->conns->size - srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output scoreboard */
+@@ -641,7 +641,7 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co
+
+ buffer_append_string_buffer(b, st->data[ndx]->key);
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
+- buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
++ buffer_append_int(b, ((data_integer *)(st->data[ndx]))->value);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+
+@@ -740,7 +740,7 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
+ plugin *pl = ps[i];
+
+ if (i == 0) {
+- buffer_copy_string_buffer(m, pl->name);
++ buffer_copy_buffer(m, pl->name);
+ } else {
+ buffer_append_string_len(m, CONST_STR_LEN("<br />"));
+ buffer_append_string_buffer(m, pl->name);
+@@ -809,13 +809,13 @@ static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
+
+ mod_status_patch_connection(srv, con, p);
+
+- if (!buffer_is_empty(p->conf.status_url) &&
++ if (!buffer_string_is_empty(p->conf.status_url) &&
+ buffer_is_equal(p->conf.status_url, con->uri.path)) {
+ return mod_status_handle_server_status(srv, con, p_d);
+- } else if (!buffer_is_empty(p->conf.config_url) &&
++ } else if (!buffer_string_is_empty(p->conf.config_url) &&
+ buffer_is_equal(p->conf.config_url, con->uri.path)) {
+ return mod_status_handle_server_config(srv, con, p_d);
+- } else if (!buffer_is_empty(p->conf.statistics_url) &&
++ } else if (!buffer_string_is_empty(p->conf.statistics_url) &&
+ buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
+ return mod_status_handle_server_statistics(srv, con, p_d);
+ }
+diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c
+index 6d9010d..cff125c 100644
+--- a/src/mod_trigger_b4_dl.c
++++ b/src/mod_trigger_b4_dl.c
+@@ -175,7 +175,7 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
+ return HANDLER_ERROR;
+ }
+ #if defined(HAVE_GDBM_H)
+- if (!buffer_is_empty(s->db_filename)) {
++ if (!buffer_string_is_empty(s->db_filename)) {
+ if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "gdbm-open failed");
+@@ -185,7 +185,7 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
+ }
+ #endif
+ #if defined(HAVE_PCRE_H)
+- if (!buffer_is_empty(s->download_url)) {
++ if (!buffer_string_is_empty(s->download_url)) {
+ if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
+ 0, &errptr, &erroff, NULL))) {
+
+@@ -196,7 +196,7 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
+ }
+ }
+
+- if (!buffer_is_empty(s->trigger_url)) {
++ if (!buffer_string_is_empty(s->trigger_url)) {
+ if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
+ 0, &errptr, &erroff, NULL))) {
+
+@@ -384,7 +384,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+ # if defined(HAVE_MEMCACHE_H)
+ if (p->conf.mc) {
+ size_t i;
+- buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
++ buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
+ buffer_append_string(p->tmp_buf, remote_ip);
+
+ for (i = 0; i < p->tmp_buf->used - 1; i++) {
+@@ -471,7 +471,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+ void *r;
+ size_t i;
+
+- buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
++ buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
+ buffer_append_string(p->tmp_buf, remote_ip);
+
+ for (i = 0; i < p->tmp_buf->used - 1; i++) {
+diff --git a/src/mod_userdir.c b/src/mod_userdir.c
+index 572b5e7..392f4b2 100644
+--- a/src/mod_userdir.c
++++ b/src/mod_userdir.c
+@@ -209,7 +209,7 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+
+ buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
+
+- if (buffer_is_empty(p->conf.basepath)
++ if (buffer_string_is_empty(p->conf.basepath)
+ #ifdef HAVE_PWD_H
+ && NULL == (pwd = getpwnam(p->username->ptr))
+ #endif
+@@ -245,7 +245,7 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+
+ /* we build the physical path */
+
+- if (buffer_is_empty(p->conf.basepath)) {
++ if (buffer_string_is_empty(p->conf.basepath)) {
+ #ifdef HAVE_PWD_H
+ buffer_copy_string(p->temp_path, pwd->pw_dir);
+ #endif
+@@ -272,18 +272,18 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+ buffer_to_lower(p->username);
+ }
+
+- buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
+- BUFFER_APPEND_SLASH(p->temp_path);
++ buffer_copy_buffer(p->temp_path, p->conf.basepath);
++ buffer_append_slash(p->temp_path);
+ if (p->conf.letterhomes) {
+ buffer_append_string_len(p->temp_path, p->username->ptr, 1);
+- BUFFER_APPEND_SLASH(p->temp_path);
++ buffer_append_slash(p->temp_path);
+ }
+ buffer_append_string_buffer(p->temp_path, p->username);
+ }
+- BUFFER_APPEND_SLASH(p->temp_path);
++ buffer_append_slash(p->temp_path);
+ buffer_append_string_buffer(p->temp_path, p->conf.path);
+
+- if (buffer_is_empty(p->conf.basepath)) {
++ if (buffer_string_is_empty(p->conf.basepath)) {
+ struct stat st;
+ int ret;
+
+@@ -293,7 +293,7 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+ }
+ }
+
+- buffer_copy_string_buffer(con->physical.basedir, p->temp_path);
++ buffer_copy_buffer(con->physical.basedir, p->temp_path);
+
+ /* the physical rel_path is basically the same as uri.path;
+ * but it is converted to lowercase in case of force_lowercase_filenames and some special handling
+@@ -302,7 +302,7 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+ * (docroot should only set the docroot/server name, phyiscal should only change the phyiscal.path;
+ * the exception mod_secure_download doesn't work with userdir anyway)
+ */
+- BUFFER_APPEND_SLASH(p->temp_path);
++ buffer_append_slash(p->temp_path);
+ /* if no second '/' is found, we assume that it was stripped from the uri.path for the special handling
+ * on windows.
+ * we do not care about the trailing slash here on windows, as we already ensured it is a directory
+@@ -313,7 +313,7 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+ if (NULL != (rel_url = strchr(con->physical.rel_path->ptr + 2, '/'))) {
+ buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
+ }
+- buffer_copy_string_buffer(con->physical.path, p->temp_path);
++ buffer_copy_buffer(con->physical.path, p->temp_path);
+
+ buffer_reset(p->temp_path);
+
+diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c
+index 4f4f264..29e9fdf 100644
+--- a/src/mod_usertrack.c
++++ b/src/mod_usertrack.c
+@@ -98,7 +98,7 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (buffer_is_empty(s->cookie_name)) {
++ if (buffer_string_is_empty(s->cookie_name)) {
+ buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
+ } else {
+ size_t j;
+@@ -114,7 +114,7 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
+ }
+ }
+
+- if (!buffer_is_empty(s->cookie_domain)) {
++ if (!buffer_string_is_empty(s->cookie_domain)) {
+ size_t j;
+ for (j = 0; j < s->cookie_domain->used - 1; j++) {
+ char c = s->cookie_domain->ptr[j];
+@@ -173,7 +173,7 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ data_string *ds;
+ unsigned char h[16];
+ li_MD5_CTX Md5Ctx;
+- char hh[32];
++ char hh[LI_ITOSTRING_LENGTH];
+
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+
+@@ -211,7 +211,7 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ ds = data_response_init();
+ }
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("Set-Cookie"));
+- buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
++ buffer_copy_buffer(ds->value, p->conf.cookie_name);
+ buffer_append_string_len(ds->value, CONST_STR_LEN("="));
+
+
+@@ -223,10 +223,10 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ 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);
++ li_itostr(hh, srv->cur_ts);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
+- LI_ltostr(hh, rand());
++ li_itostr(hh, rand());
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+
+ li_MD5_Final(h, &Md5Ctx);
+@@ -235,14 +235,14 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; Path=/"));
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; Version=1"));
+
+- if (!buffer_is_empty(p->conf.cookie_domain)) {
++ if (!buffer_string_is_empty(p->conf.cookie_domain)) {
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; Domain="));
+ buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
+ }
+
+ if (p->conf.cookie_max_age) {
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; max-age="));
+- buffer_append_long(ds->value, p->conf.cookie_max_age);
++ buffer_append_int(ds->value, p->conf.cookie_max_age);
+ }
+
+ array_insert_unique(con->response.headers, (data_unset *)ds);
+diff --git a/src/mod_webdav.c b/src/mod_webdav.c
+index 04b2161..a3807c0 100644
+--- a/src/mod_webdav.c
++++ b/src/mod_webdav.c
+@@ -198,7 +198,7 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (!buffer_is_empty(s->sqlite_db_name)) {
++ if (!buffer_string_is_empty(s->sqlite_db_name)) {
+ #ifdef USE_PROPPATCH
+ const char *next_stmt;
+ char *err;
+@@ -519,7 +519,7 @@ static int webdav_gen_response_status_tag(server *srv, connection *con, physical
+ } else {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
+ }
+- buffer_append_long(b, status);
++ buffer_append_int(b, status);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ buffer_append_string(b, get_http_status_name(status));
+
+@@ -595,12 +595,12 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
+ /* ignore the parent dir */
+ }
+
+- buffer_copy_string_buffer(d.path, dst->path);
+- BUFFER_APPEND_SLASH(d.path);
++ buffer_copy_buffer(d.path, dst->path);
++ buffer_append_slash(d.path);
+ buffer_append_string(d.path, de->d_name);
+
+- buffer_copy_string_buffer(d.rel_path, dst->rel_path);
+- BUFFER_APPEND_SLASH(d.rel_path);
++ buffer_copy_buffer(d.rel_path, dst->rel_path);
++ buffer_append_slash(d.rel_path);
+ buffer_append_string(d.rel_path, de->d_name);
+
+ /* stat and unlink afterwards */
+@@ -756,20 +756,20 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
+ continue;
+ }
+
+- buffer_copy_string_buffer(s.path, src->path);
+- BUFFER_APPEND_SLASH(s.path);
++ buffer_copy_buffer(s.path, src->path);
++ buffer_append_slash(s.path);
+ buffer_append_string(s.path, de->d_name);
+
+- buffer_copy_string_buffer(d.path, dst->path);
+- BUFFER_APPEND_SLASH(d.path);
++ buffer_copy_buffer(d.path, dst->path);
++ buffer_append_slash(d.path);
+ buffer_append_string(d.path, de->d_name);
+
+- buffer_copy_string_buffer(s.rel_path, src->rel_path);
+- BUFFER_APPEND_SLASH(s.rel_path);
++ buffer_copy_buffer(s.rel_path, src->rel_path);
++ buffer_append_slash(s.rel_path);
+ buffer_append_string(s.rel_path, de->d_name);
+
+- buffer_copy_string_buffer(d.rel_path, dst->rel_path);
+- BUFFER_APPEND_SLASH(d.rel_path);
++ buffer_copy_buffer(d.rel_path, dst->rel_path);
++ buffer_append_slash(d.rel_path);
+ buffer_append_string(d.rel_path, de->d_name);
+
+ if (-1 == stat(s.path->ptr, &st)) {
+@@ -877,7 +877,7 @@ static int webdav_get_live_property(server *srv, connection *con, plugin_data *p
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getcontentlength")) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlength>"));
+- buffer_append_off_t(b, sce->st.st_size);
++ buffer_append_int(b, sce->st.st_size);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlength>"));
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getcontentlanguage")) {
+@@ -1062,8 +1062,6 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
+ cq->bytes_out += weHave;
+
+ break;
+- case UNUSED_CHUNK:
+- break;
+ }
+ chunkqueue_remove_finished_chunks(cq);
+ }
+@@ -1367,7 +1365,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ buffer_append_string_encoded(b, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
+
+- if (!buffer_is_empty(prop_200)) {
++ if (!buffer_string_is_empty(prop_200)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+@@ -1379,7 +1377,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
+ }
+- if (!buffer_is_empty(prop_404)) {
++ if (!buffer_string_is_empty(prop_404)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+@@ -1410,11 +1408,11 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ /* ignore the parent dir */
+ }
+
+- buffer_copy_string_buffer(d.path, dst->path);
+- BUFFER_APPEND_SLASH(d.path);
++ buffer_copy_buffer(d.path, dst->path);
++ buffer_append_slash(d.path);
+
+- buffer_copy_string_buffer(d.rel_path, dst->rel_path);
+- BUFFER_APPEND_SLASH(d.rel_path);
++ buffer_copy_buffer(d.rel_path, dst->rel_path);
++ buffer_append_slash(d.rel_path);
+
+ if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
+ /* don't append the . */
+@@ -1436,7 +1434,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ buffer_append_string_encoded(b, CONST_BUF_LEN(d.rel_path), ENCODING_REL_URI);
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
+
+- if (!buffer_is_empty(prop_200)) {
++ if (!buffer_string_is_empty(prop_200)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+@@ -1448,7 +1446,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
+ }
+- if (!buffer_is_empty(prop_404)) {
++ if (!buffer_string_is_empty(prop_404)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+@@ -1763,8 +1761,6 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ }
+ }
+ break;
+- case UNUSED_CHUNK:
+- break;
+ }
+
+ if (r > 0) {
+@@ -1862,21 +1858,21 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ return HANDLER_FINISHED;
+ }
+
+- buffer_copy_string_buffer(p->tmp_buf, p->uri.path_raw);
++ buffer_copy_buffer(p->tmp_buf, p->uri.path_raw);
+ buffer_urldecode_path(p->tmp_buf);
+ buffer_path_simplify(p->uri.path, p->tmp_buf);
+
+ /* we now have a URI which is clean. transform it into a physical path */
+- buffer_copy_string_buffer(p->physical.doc_root, con->physical.doc_root);
+- buffer_copy_string_buffer(p->physical.rel_path, p->uri.path);
++ buffer_copy_buffer(p->physical.doc_root, con->physical.doc_root);
++ buffer_copy_buffer(p->physical.rel_path, p->uri.path);
+
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(p->physical.rel_path);
+ }
+
+- buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
+- BUFFER_APPEND_SLASH(p->physical.path);
+- buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
++ buffer_copy_buffer(p->physical.path, p->physical.doc_root);
++ buffer_append_slash(p->physical.path);
++ buffer_copy_buffer(p->physical.basedir, p->physical.path);
+
+ /* don't add a second / */
+ if (p->physical.rel_path->ptr[0] == '/') {
+diff --git a/src/network.c b/src/network.c
+index 776a86c..f1c9489 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -187,10 +187,10 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
+ srv_socket->fde_ndx = -1;
+
+ srv_socket->srv_token = buffer_init();
+- buffer_copy_string_buffer(srv_socket->srv_token, host_token);
++ buffer_copy_buffer(srv_socket->srv_token, host_token);
+
+ b = buffer_init();
+- buffer_copy_string_buffer(b, host_token);
++ buffer_copy_buffer(b, host_token);
+
+ /* ipv4:port
+ * [ipv6]:port
+@@ -701,7 +701,7 @@ int network_init(server *srv) {
+ long ssloptions =
+ SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;
+
+- if (buffer_is_empty(s->ssl_pemfile) && buffer_is_empty(s->ssl_ca_file)) continue;
++ if (buffer_string_is_empty(s->ssl_pemfile) && buffer_string_is_empty(s->ssl_ca_file)) continue;
+
+ if (srv->ssl_is_init == 0) {
+ SSL_load_error_strings();
+@@ -716,7 +716,7 @@ int network_init(server *srv) {
+ }
+ }
+
+- if (!buffer_is_empty(s->ssl_pemfile)) {
++ if (!buffer_string_is_empty(s->ssl_pemfile)) {
+ #ifdef OPENSSL_NO_TLSEXT
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ if (COMP_HTTP_HOST == dc->comp) {
+@@ -729,7 +729,7 @@ int network_init(server *srv) {
+ }
+
+
+- if (!buffer_is_empty(s->ssl_ca_file)) {
++ if (!buffer_string_is_empty(s->ssl_ca_file)) {
+ s->ssl_ca_file_cert_names = SSL_load_client_CA_file(s->ssl_ca_file->ptr);
+ if (NULL == s->ssl_ca_file_cert_names) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+@@ -737,7 +737,7 @@ int network_init(server *srv) {
+ }
+ }
+
+- if (buffer_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue;
++ if (buffer_string_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue;
+
+ if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+@@ -784,7 +784,7 @@ int network_init(server *srv) {
+ }
+ }
+
+- if (!buffer_is_empty(s->ssl_cipher_list)) {
++ if (!buffer_string_is_empty(s->ssl_cipher_list)) {
+ /* Disable support for low encryption ciphers */
+ if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+@@ -799,7 +799,7 @@ int network_init(server *srv) {
+
+ #ifndef OPENSSL_NO_DH
+ /* Support for Diffie-Hellman key exchange */
+- if (!buffer_is_empty(s->ssl_dh_file)) {
++ if (!buffer_string_is_empty(s->ssl_dh_file)) {
+ /* DH parameters from file */
+ bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r");
+ if (bio == NULL) {
+@@ -832,7 +832,7 @@ int network_init(server *srv) {
+ SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE);
+ DH_free(dh);
+ #else
+- if (!buffer_is_empty(s->ssl_dh_file)) {
++ if (!buffer_string_is_empty(s->ssl_dh_file)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: openssl compiled without DH support, can't load parameters from", s->ssl_dh_file->ptr);
+ }
+ #endif
+@@ -840,7 +840,7 @@ int network_init(server *srv) {
+ #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+ #ifndef OPENSSL_NO_ECDH
+ /* Support for Elliptic-Curve Diffie-Hellman key exchange */
+- if (!buffer_is_empty(s->ssl_ec_curve)) {
++ if (!buffer_string_is_empty(s->ssl_ec_curve)) {
+ /* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */
+ nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr);
+ if (nid == 0) {
+@@ -866,7 +866,7 @@ int network_init(server *srv) {
+ for (j = 0; j < srv->config_context->used; j++) {
+ specific_config *s1 = srv->config_storage[j];
+
+- if (!buffer_is_empty(s1->ssl_ca_file)) {
++ if (!buffer_string_is_empty(s1->ssl_ca_file)) {
+ if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s1->ssl_ca_file);
+@@ -926,9 +926,9 @@ int network_init(server *srv) {
+
+ b = buffer_init();
+
+- buffer_copy_string_buffer(b, srv->srvconf.bindhost);
++ buffer_copy_buffer(b, srv->srvconf.bindhost);
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+- buffer_append_long(b, srv->srvconf.port);
++ buffer_append_int(b, srv->srvconf.port);
+
+ if (0 != network_server_init(srv, b, srv->config_storage[0])) {
+ buffer_free(b);
+@@ -944,7 +944,7 @@ int network_init(server *srv) {
+ backend = network_backends[0].nb;
+
+ /* match name against known types */
+- if (!buffer_is_empty(srv->srvconf.network_backend)) {
++ if (!buffer_string_is_empty(srv->srvconf.network_backend)) {
+ for (i = 0; network_backends[i].name; i++) {
+ /**/
+ if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) {
+diff --git a/src/plugin.c b/src/plugin.c
+index 55f8b03..d587308 100644
+--- a/src/plugin.c
++++ b/src/plugin.c
+@@ -133,7 +133,7 @@ int plugins_load(server *srv) {
+ }
+ }
+
+- buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
++ buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
+
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
+ buffer_append_string(srv->tmp_buf, modules);
+diff --git a/src/request.c b/src/request.c
+index 2eb0b0e..65d0a0e 100644
+--- a/src/request.c
++++ b/src/request.c
+@@ -322,7 +322,7 @@ int http_request_parse(server *srv, connection *con) {
+ buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
+ } else {
+ /* fill the local request buffer */
+- buffer_copy_string_buffer(con->parse_request, con->request.request);
++ buffer_copy_buffer(con->parse_request, con->request.request);
+ }
+
+ keep_alive_set = 0;
+@@ -508,7 +508,7 @@ int http_request_parse(server *srv, connection *con) {
+ }
+ }
+
+- buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
++ buffer_copy_buffer(con->request.orig_uri, con->request.uri);
+
+ con->http_status = 0;
+
+@@ -1061,7 +1061,7 @@ int http_request_parse(server *srv, connection *con) {
+
+ /* RFC 2616, 14.23 */
+ if (con->request.http_host == NULL ||
+- buffer_is_empty(con->request.http_host)) {
++ buffer_string_is_empty(con->request.http_host)) {
+ con->http_status = 400;
+ con->response.keep_alive = 0;
+ con->keep_alive = 0;
+diff --git a/src/response.c b/src/response.c
+index eb5c2f2..bde381f 100644
+--- a/src/response.c
++++ b/src/response.c
+@@ -40,7 +40,7 @@ int http_response_write_header(server *srv, connection *con) {
+ } else {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
+ }
+- buffer_append_long(b, con->http_status);
++ buffer_append_int(b, con->http_status);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ buffer_append_string(b, get_http_status_name(con->http_status));
+
+@@ -181,7 +181,7 @@ static void https_add_ssl_entries(connection *con) {
+ buffer_copy_string(ds->key, "REMOTE_USER");
+ array_insert_unique(con->environment, (data_unset *)ds);
+ }
+- buffer_copy_string_buffer(ds->value, envds->value);
++ buffer_copy_buffer(ds->value, envds->value);
+ }
+ array_insert_unique(con->environment, (data_unset *)envds);
+ }
+@@ -199,7 +199,7 @@ static void https_add_ssl_entries(connection *con) {
+ }
+
+ buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
+- buffer_prepare_copy(envds->value, n+1);
++ buffer_prepare_copy(envds->value, n);
+ BIO_read(bio, envds->value->ptr, n);
+ BIO_free(bio);
+ envds->value->ptr[n] = '\0';
+@@ -278,7 +278,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ } else {
+ buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
+ }
+- buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
++ buffer_copy_buffer(con->uri.authority, con->request.http_host);
+ buffer_to_lower(con->uri.authority);
+
+ config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */
+@@ -302,7 +302,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr);
+ } else {
+ buffer_reset (con->uri.query);
+- buffer_copy_string_buffer(con->uri.path_raw, con->request.uri);
++ buffer_copy_buffer(con->uri.path_raw, con->request.uri);
+ }
+
+ /* decode url to path
+@@ -314,9 +314,9 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ if (con->request.http_method == HTTP_METHOD_OPTIONS &&
+ con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
+ /* OPTIONS * ... */
+- buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
++ buffer_copy_buffer(con->uri.path, con->uri.path_raw);
+ } else {
+- buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
++ buffer_copy_buffer(srv->tmp_buf, con->uri.path_raw);
+ buffer_urldecode_path(srv->tmp_buf);
+ buffer_path_simplify(con->uri.path, srv->tmp_buf);
+ }
+@@ -430,8 +430,8 @@ handler_t http_response_prepare(server *srv, connection *con) {
+
+ /* set a default */
+
+- buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
+- buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
++ buffer_copy_buffer(con->physical.doc_root, con->conf.document_root);
++ buffer_copy_buffer(con->physical.rel_path, con->uri.path);
+
+ #if defined(__WIN32) || defined(__CYGWIN__)
+ /* strip dots from the end and spaces
+@@ -500,8 +500,8 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ }
+
+ /* the docroot plugins might set the servername, if they don't we take http-host */
+- if (buffer_is_empty(con->server_name)) {
+- buffer_copy_string_buffer(con->server_name, con->uri.authority);
++ if (buffer_string_is_empty(con->server_name)) {
++ buffer_copy_buffer(con->server_name, con->uri.authority);
+ }
+
+ /**
+@@ -510,9 +510,9 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ *
+ */
+
+- buffer_copy_string_buffer(con->physical.basedir, con->physical.doc_root);
+- buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
+- BUFFER_APPEND_SLASH(con->physical.path);
++ buffer_copy_buffer(con->physical.basedir, con->physical.doc_root);
++ buffer_copy_buffer(con->physical.path, con->physical.doc_root);
++ buffer_append_slash(con->physical.path);
+ if (con->physical.rel_path->used &&
+ con->physical.rel_path->ptr[0] == '/') {
+ buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
+@@ -645,13 +645,13 @@ handler_t http_response_prepare(server *srv, connection *con) {
+
+ /* not found, perhaps PATHINFO */
+
+- buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
++ buffer_copy_buffer(srv->tmp_buf, con->physical.path);
+
+ do {
+ if (slash) {
+ buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
+ } else {
+- buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
++ buffer_copy_buffer(con->physical.path, srv->tmp_buf);
+ }
+
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+diff --git a/src/server.c b/src/server.c
+index d47fd62..71d3538 100644
+--- a/src/server.c
++++ b/src/server.c
+@@ -999,7 +999,7 @@ int main (int argc, char **argv) {
+
+ /* write pid file */
+ if (pid_fd != -1) {
+- buffer_copy_long(srv->tmp_buf, getpid());
++ buffer_copy_int(srv->tmp_buf, getpid());
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
+ force_assert(srv->tmp_buf->used > 0);
+ write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
+diff --git a/src/stat_cache.c b/src/stat_cache.c
+index 9007325..b5aa9ce 100644
+--- a/src/stat_cache.c
++++ b/src/stat_cache.c
+@@ -221,7 +221,7 @@ static int stat_cache_attr_get(buffer *buf, char *name) {
+
+ attrlen = 1024;
+ buffer_prepare_copy(buf, attrlen);
+- attrlen--;
++ attrlen = buf->size - 1;
+ if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) {
+ buf->used = attrlen + 1;
+ buf->ptr[attrlen] = '\0';
+@@ -234,7 +234,7 @@ static int stat_cache_attr_get(buffer *buf, char *name) {
+
+ buffer_prepare_copy(buf, attrlen);
+
+- if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, "Content-Type", buf->ptr, attrlen-1))) {
++ if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, "Content-Type", buf->ptr, buf->size - 1))) {
+ buf->used = attrlen + 1;
+ buf->ptr[attrlen] = '\0';
+ return 0;
+@@ -294,7 +294,7 @@ handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent) {
+
+ for (j = 0; j < 2; j++) {
+ buffer_copy_string(sc->hash_key, fe.filename);
+- buffer_append_long(sc->hash_key, j);
++ buffer_append_int(sc->hash_key, j);
+
+ ndx = hashme(sc->hash_key);
+
+@@ -331,7 +331,7 @@ handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent) {
+ static int buffer_copy_dirname(buffer *dst, buffer *file) {
+ size_t i;
+
+- if (buffer_is_empty(file)) return -1;
++ if (buffer_string_is_empty(file)) return -1;
+
+ for (i = file->used - 1; i+1 > 0; i--) {
+ if (file->ptr[i] == '/') {
+@@ -394,8 +394,8 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+
+ sc = srv->stat_cache;
+
+- buffer_copy_string_buffer(sc->hash_key, name);
+- buffer_append_long(sc->hash_key, con->conf.follow_symlink);
++ buffer_copy_buffer(sc->hash_key, name);
++ buffer_append_int(sc->hash_key, con->conf.follow_symlink);
+
+ file_ndx = hashme(sc->hash_key);
+ sc->files = splaytree_splay(sc->files, file_ndx);
+@@ -460,8 +460,8 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ return HANDLER_ERROR;
+ }
+
+- buffer_copy_string_buffer(sc->hash_key, sc->dir_name);
+- buffer_append_long(sc->hash_key, con->conf.follow_symlink);
++ buffer_copy_buffer(sc->hash_key, sc->dir_name);
++ buffer_append_int(sc->hash_key, con->conf.follow_symlink);
+
+ dir_ndx = hashme(sc->hash_key);
+
+@@ -518,7 +518,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ #endif
+
+ sce = stat_cache_entry_init();
+- buffer_copy_string_buffer(sce->name, name);
++ buffer_copy_buffer(sce->name, name);
+
+ sc->files = splaytree_insert(sc->files, file_ndx, sce);
+ #ifdef DEBUG_STAT_CACHE
+@@ -577,7 +577,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ char *s_cur;
+
+ dname = buffer_init();
+- buffer_copy_string_buffer(dname, name);
++ buffer_copy_buffer(dname, name);
+
+ while ((s_cur = strrchr(dname->ptr,'/'))) {
+ *s_cur = '\0';
+@@ -615,7 +615,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ }
+ #endif
+ /* xattr did not set a content-type. ask the config */
+- if (buffer_is_empty(sce->content_type)) {
++ if (buffer_string_is_empty(sce->content_type)) {
+ for (k = 0; k < con->conf.mimetypes->used; k++) {
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+ buffer *type = ds->key;
+@@ -626,7 +626,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ if (type->used > name->used) continue;
+
+ if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) {
+- buffer_copy_string_buffer(sce->content_type, ds->value);
++ buffer_copy_buffer(sce->content_type, ds->value);
+ break;
+ }
+ }
+@@ -642,7 +642,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ if (!dir_node) {
+ fam_dir = fam_dir_entry_init();
+
+- buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
++ buffer_copy_buffer(fam_dir->name, sc->dir_name);
+
+ fam_dir->version = 1;
+
+--
+2.4.5
+
diff --git a/main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch b/main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch
new file mode 100644
index 0000000000..6f265d155b
--- /dev/null
+++ b/main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch
@@ -0,0 +1,1537 @@
+From 1be163b44a53eebb0a7b0ed562d12e3f252794e1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:36 +0000
+Subject: [PATCH 16/29] Remove chunkqueue_get_{append,prepend}* API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ Although those were "easy" to use, they violated the abstraction:
+ content of the chunkqueue should only be modified via the API.
+ Replace with chunkqueue_get_memory() and chunkqueue_use_memory() for
+ functions that read data from network (reusing large buffers),
+ chunkqueue_steal_with_tempfiles() to store request bodies on disk
+ temporarily.
+ Modules that were generating content and need a buffer maintain the
+ buffer manually (have to be careful to free the buffer on errors, as
+ it isn't part of the chunkqueue yet).
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2976 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/buffer.c | 23 +++-
+ src/buffer.h | 12 ++
+ src/chunk.c | 295 +++++++++++++++++++++++++++++++++++++++--------
+ src/chunk.h | 39 ++++---
+ src/connections.c | 195 +++++--------------------------
+ src/mod_compress.c | 4 +-
+ src/mod_dirlisting.c | 4 +-
+ src/mod_fastcgi.c | 76 +++++-------
+ src/mod_flv_streaming.c | 6 +-
+ src/mod_proxy.c | 5 +-
+ src/mod_scgi.c | 4 +-
+ src/mod_ssi.c | 63 +++++-----
+ src/mod_staticfile.c | 13 +--
+ src/mod_status.c | 42 ++++---
+ src/mod_uploadprogress.c | 11 +-
+ src/mod_webdav.c | 18 ++-
+ src/response.c | 6 +-
+ 17 files changed, 465 insertions(+), 351 deletions(-)
+
+diff --git a/src/buffer.c b/src/buffer.c
+index caaa5bb..019abb7 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -139,6 +139,27 @@ char* buffer_prepare_append(buffer *b, size_t size) {
+ return b->ptr + b->used - 1;
+ }
+
++char* buffer_string_prepare_copy(buffer *b, size_t size) {
++ force_assert(NULL != b);
++
++ buffer_prepare_copy(b, size);
++ b->used = 1;
++
++ return b->ptr;
++}
++
++char* buffer_string_prepare_append(buffer *b, size_t size) {
++ force_assert(NULL != b);
++
++ if (0 == b->used) {
++ return buffer_string_prepare_copy(b, size);
++ } else {
++ force_assert('\0' == b->ptr[b->used - 1]);
++ return buffer_prepare_append(b, size);
++ }
++}
++
++
+ void buffer_commit(buffer *b, size_t size)
+ {
+ force_assert(NULL != b);
+@@ -231,7 +252,7 @@ void buffer_append_long_hex(buffer *b, unsigned long value) {
+ } while (0 != copy);
+ }
+
+- buf = buffer_prepare_append(b, shift);
++ buf = buffer_string_prepare_append(b, shift);
+ buffer_commit(b, shift); /* will fill below */
+
+ shift <<= 2; /* count bits now */
+diff --git a/src/buffer.h b/src/buffer.h
+index ff57d68..5d540a4 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -62,6 +62,11 @@ char* buffer_prepare_copy(buffer *b, size_t size);
+ */
+ char* buffer_prepare_append(buffer *b, size_t size);
+
++/* similar to buffer_prepare_copy(b, size), but sets b->used = 1 */
++char* buffer_string_prepare_copy(buffer *b, size_t size);
++/* similar to buffer_prepare_append(b, size), but sets b->used = 1 if used was b->0 before */
++char* buffer_string_prepare_append(buffer *b, size_t size);
++
+ /* use after prepare_(copy,append) when you have written data to the buffer
+ * to increase the buffer length by size. also sets the terminating zero.
+ * requires enough space is present for the terminating zero (prepare with the
+@@ -136,6 +141,7 @@ int light_isalpha(int c);
+ int light_isalnum(int c);
+
+ static inline size_t buffer_string_length(const buffer *b); /* buffer string length without terminating 0 */
++static inline size_t buffer_string_space(const buffer *b); /* maximum length of string that can be stored without reallocating */
+ static inline void buffer_append_slash(buffer *b); /* append '/' no non-empty strings not ending in '/' */
+
+ #define BUFFER_APPEND_STRING_CONST(x, y) \
+@@ -161,6 +167,12 @@ static inline size_t buffer_string_length(const buffer *b) {
+ return NULL != b && 0 != b->used ? b->used - 1 : 0;
+ }
+
++static inline size_t buffer_string_space(const buffer *b) {
++ if (NULL == b || b->size == 0) return 0;
++ if (0 == b->used) return b->size - 1;
++ return b->size - b->used;
++}
++
+ static inline void buffer_append_slash(buffer *b) {
+ size_t len = buffer_string_length(b);
+ if (len > 0 && '/' != b->ptr[len-1]) BUFFER_APPEND_STRING_CONST(b, "/");
+diff --git a/src/chunk.c b/src/chunk.c
+index c991b82..83adc15 100644
+--- a/src/chunk.c
++++ b/src/chunk.c
+@@ -5,6 +5,8 @@
+ */
+
+ #include "chunk.h"
++#include "base.h"
++#include "log.h"
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+@@ -233,28 +235,84 @@ void chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
+ chunkqueue_append_chunk(cq, c);
+ }
+
+-buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
++void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_size, size_t alloc_size) {
++ static const size_t REALLOC_MAX_SIZE = 256;
+ chunk *c;
++ buffer *b;
++ char *dummy_mem;
++ size_t dummy_len;
+
+- c = chunkqueue_get_unused_chunk(cq);
++ force_assert(NULL != cq);
++ if (NULL == mem) mem = &dummy_mem;
++ if (NULL == len) len = &dummy_len;
+
+- c->type = MEM_CHUNK;
++ /* default values: */
++ if (0 == min_size) min_size = 1024;
++ if (0 == alloc_size) alloc_size = 4096;
++ if (alloc_size < min_size) alloc_size = min_size;
+
+- chunkqueue_prepend_chunk(cq, c);
++ if (NULL != cq->last && MEM_CHUNK == cq->last->type) {
++ size_t have;
+
+- return c->mem;
+-}
++ b = cq->last->mem;
++ have = buffer_string_space(b);
+
+-buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
+- chunk *c;
++ /* unused buffer: allocate space */
++ if (buffer_string_is_empty(b)) {
++ buffer_string_prepare_copy(b, alloc_size);
++ have = buffer_string_space(b);
++ }
++ /* if buffer is really small just make it bigger */
++ else if (have < min_size && b->size <= REALLOC_MAX_SIZE) {
++ size_t new_size = b->used + min_size, append;
++ if (new_size < alloc_size) new_size = alloc_size;
++
++ append = new_size - b->used;
++ if (append >= min_size) {
++ buffer_string_prepare_append(b, append);
++ have = buffer_string_space(b);
++ }
++ }
+
+- c = chunkqueue_get_unused_chunk(cq);
++ /* return pointer into existing buffer if large enough */
++ if (have >= min_size) {
++ *mem = b->ptr + buffer_string_length(b);
++ *len = have;
++ return;
++ }
++ }
+
++ /* allocate new chunk */
++ c = chunkqueue_get_unused_chunk(cq);
+ c->type = MEM_CHUNK;
+-
+ chunkqueue_append_chunk(cq, c);
+
+- return c->mem;
++ b = c->mem;
++ buffer_string_prepare_append(b, alloc_size);
++
++ *mem = b->ptr + buffer_string_length(b);
++ *len = buffer_string_space(b);
++}
++
++void chunkqueue_use_memory(chunkqueue *cq, size_t len) {
++ buffer *b;
++
++ force_assert(NULL != cq);
++ force_assert(NULL != cq->last && MEM_CHUNK == cq->last->type);
++ b = cq->last->mem;
++
++ force_assert(b->used > 0);
++ force_assert(len <= buffer_string_space(b));
++
++ if (len > 0) {
++ b->used += len;
++ b->ptr[b->used - 1] = '\0';
++ } else if (buffer_string_is_empty(b)) {
++ /* unused buffer: can't remove chunk easily from
++ * end of list, so just reset the buffer
++ */
++ buffer_reset(b);
++ }
+ }
+
+ void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
+@@ -262,13 +320,67 @@ void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
+ cq->tempdirs = tempdirs;
+ }
+
+-chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+- chunk *c;
+- buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
++void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) {
++ while (len > 0) {
++ chunk *c = src->first;
++ off_t clen = 0, use;
+
+- c = chunkqueue_get_unused_chunk(cq);
++ if (NULL == c) break;
+
+- c->type = FILE_CHUNK;
++ switch (c->type) {
++ case MEM_CHUNK:
++ clen = buffer_string_length(c->mem);
++ break;
++ case FILE_CHUNK:
++ clen = c->file.length;
++ break;
++ }
++ force_assert(clen >= c->offset);
++ clen -= c->offset;
++ use = len >= clen ? clen : len;
++
++ src->bytes_out += use;
++ dest->bytes_in += use;
++ len -= use;
++
++ if (0 == clen) {
++ /* drop empty chunk */
++ src->first = c->next;
++ if (c == src->last) src->last = NULL;
++ chunkqueue_push_unused_chunk(src, c);
++ continue;
++ }
++
++ if (use == clen) {
++ /* move complete chunk */
++ src->first = c->next;
++ if (c == src->last) src->last = NULL;
++
++ chunkqueue_append_chunk(dest, c);
++ continue;
++ }
++
++ /* partial chunk with length "use" */
++
++ switch (c->type) {
++ case MEM_CHUNK:
++ chunkqueue_append_mem(dest, c->mem->ptr + c->offset, use);
++ break;
++ case FILE_CHUNK:
++ /* tempfile flag is in "last" chunk after the split */
++ chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, use);
++ break;
++ }
++
++ c->offset += use;
++ force_assert(0 == len);
++ }
++}
++
++static chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
++ chunk *c;
++ buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
++ int fd;
+
+ if (cq->tempdirs && cq->tempdirs->used) {
+ size_t i;
+@@ -282,19 +394,21 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+ buffer_append_slash(template);
+ buffer_append_string_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX"));
+
+- if (-1 != (c->file.fd = mkstemp(template->ptr))) {
+- /* only trigger the unlink if we created the temp-file successfully */
+- c->file.is_temp = 1;
+- break;
+- }
++ if (-1 != (fd = mkstemp(template->ptr))) break;
+ }
+ } else {
+- if (-1 != (c->file.fd = mkstemp(template->ptr))) {
+- /* only trigger the unlink if we created the temp-file successfully */
+- c->file.is_temp = 1;
+- }
++ fd = mkstemp(template->ptr);
+ }
+
++ if (-1 == fd) {
++ buffer_free(template);
++ return NULL;
++ }
++
++ c = chunkqueue_get_unused_chunk(cq);
++ c->type = FILE_CHUNK;
++ c->file.fd = fd;
++ c->file.is_temp = 1;
+ buffer_copy_buffer(c->file.name, template);
+ c->file.length = 0;
+
+@@ -305,10 +419,76 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
+ return c;
+ }
+
+-void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) {
++static int chunkqueue_append_to_tempfile(server *srv, chunkqueue *dest, const char *mem, size_t len) {
++ chunk *dst_c = NULL;
++ ssize_t written;
++ /* copy everything to max 1Mb sized tempfiles */
++
++ /*
++ * if the last chunk is
++ * - smaller than 1Mb (size < 1Mb)
++ * - not read yet (offset == 0)
++ * -> append to it
++ * otherwise
++ * -> create a new chunk
++ *
++ * */
++
++ if (NULL != dest->last
++ && FILE_CHUNK != dest->last->type
++ && dest->last->file.is_temp
++ && -1 != dest->last->file.fd
++ && 0 == dest->last->offset) {
++ /* ok, take the last chunk for our job */
++ dst_c = dest->last;
++
++ if (dest->last->file.length >= 1 * 1024 * 1024) {
++ /* the chunk is too large now, close it */
++ if (-1 != dst_c->file.fd) {
++ close(dst_c->file.fd);
++ dst_c->file.fd = -1;
++ }
++ dst_c = chunkqueue_get_append_tempfile(dest);
++ }
++ } else {
++ dst_c = chunkqueue_get_append_tempfile(dest);
++ }
++
++ if (NULL == dst_c) {
++ /* we don't have file to write to,
++ * EACCES might be one reason.
++ *
++ * Instead of sending 500 we send 413 and say the request is too large
++ */
++
++ log_error_write(srv, __FILE__, __LINE__, "sbs",
++ "denying upload as opening temp-file for upload failed:",
++ dst_c->file.name, strerror(errno));
++
++ return -1;
++ }
++
++ if (0 > (written = write(dst_c->file.fd, mem, len)) || (size_t) written != len) {
++ /* write failed for some reason ... disk full ? */
++ log_error_write(srv, __FILE__, __LINE__, "sbs",
++ "denying upload as writing to file failed:",
++ dst_c->file.name, strerror(errno));
++
++ close(dst_c->file.fd);
++ dst_c->file.fd = -1;
++
++ return -1;
++ }
++
++ dst_c->file.length += len;
++
++ return 0;
++}
++
++int chunkqueue_steal_with_tempfiles(server *srv, chunkqueue *dest, chunkqueue *src, off_t len) {
+ while (len > 0) {
+ chunk *c = src->first;
+- off_t clen = 0;
++ off_t clen = 0, use;
+
+ if (NULL == c) break;
+
+@@ -322,36 +502,57 @@ void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) {
+ }
+ force_assert(clen >= c->offset);
+ clen -= c->offset;
++ use = len >= clen ? clen : len;
+
+- if (len >= clen) {
+- /* move complete chunk */
++ src->bytes_out += use;
++ dest->bytes_in += use;
++ len -= use;
++
++ if (0 == clen) {
++ /* drop empty chunk */
+ src->first = c->next;
+ if (c == src->last) src->last = NULL;
+-
+- chunkqueue_append_chunk(dest, c);
+- src->bytes_out += clen;
+- dest->bytes_in += clen;
+- len -= clen;
++ chunkqueue_push_unused_chunk(src, c);
+ continue;
+ }
+
+- /* partial chunk with length "len" */
++ if (FILE_CHUNK == c->type) {
++ if (use == clen) {
++ /* move complete chunk */
++ src->first = c->next;
++ if (c == src->last) src->last = NULL;
+
+- switch (c->type) {
+- case MEM_CHUNK:
+- chunkqueue_append_mem(dest, c->mem->ptr + c->offset, len);
+- break;
+- case FILE_CHUNK:
+- /* tempfile flag is in "last" chunk after the split */
+- chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, len);
+- break;
++ chunkqueue_append_chunk(dest, c);
++ } else {
++ /* partial chunk with length "use" */
++ /* tempfile flag is in "last" chunk after the split */
++ chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, use);
++
++ c->offset += use;
++ force_assert(0 == len);
++ }
++ continue;
+ }
+
+- c->offset += len;
+- src->bytes_out += len;
+- dest->bytes_in += len;
+- len = 0;
++ /* store "use" bytes from memory chunk in tempfile */
++ if (0 != chunkqueue_append_to_tempfile(srv, dest, c->mem->ptr + c->offset, use)) {
++ /* undo counters */
++ src->bytes_out -= use;
++ dest->bytes_in -= use;
++ return -1;
++ }
++
++
++ c->offset += use;
++ if (use == clen) {
++ /* finished chunk */
++ src->first = c->next;
++ if (c == src->last) src->last = NULL;
++ chunkqueue_push_unused_chunk(src, c);
++ }
+ }
++
++ return 0;
+ }
+
+ off_t chunkqueue_length(chunkqueue *cq) {
+diff --git a/src/chunk.h b/src/chunk.h
+index 6559000..33b7e27 100644
+--- a/src/chunk.h
++++ b/src/chunk.h
+@@ -48,24 +48,37 @@ typedef struct {
+ } chunkqueue;
+
+ chunkqueue *chunkqueue_init(void);
+-void chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs);
+-void chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len); /* copies "fn" */
+-void chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len); /* copies memory */
+-void chunkqueue_append_buffer(chunkqueue *c, buffer *mem); /* may reset "mem" */
+-void chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem); /* may reset "mem" */
+-
+-buffer * chunkqueue_get_append_buffer(chunkqueue *c);
+-buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
+-chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
++void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs);
++void chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len); /* copies "fn" */
++void chunkqueue_append_mem(chunkqueue *cq, const char *mem, size_t len); /* copies memory */
++void chunkqueue_append_buffer(chunkqueue *cq, buffer *mem); /* may reset "mem" */
++void chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem); /* may reset "mem" */
++
++/* functions to handle buffers to read into: */
++/* return a pointer to a buffer in *mem with size *len;
++ * it should be at least min_size big, and use alloc_size if
++ * new memory is allocated.
++ * modifying the chunkqueue invalidates the memory area.
++ * should always be followed by chunkqueue_get_memory(),
++ * even if nothing was read.
++ * pass 0 for min_size/alloc_size for default values
++ */
++void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_size, size_t alloc_size);
++/* append first len bytes of the memory queried with
++ * chunkqueue_get_memory to the chunkqueue
++ */
++void chunkqueue_use_memory(chunkqueue *cq, size_t len);
+
+ void chunkqueue_remove_finished_chunks(chunkqueue *cq);
+
+ void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len);
++struct server;
++int chunkqueue_steal_with_tempfiles(struct server *srv, chunkqueue *dest, chunkqueue *src, off_t len);
+
+-off_t chunkqueue_length(chunkqueue *c);
+-void chunkqueue_free(chunkqueue *c);
+-void chunkqueue_reset(chunkqueue *c);
++off_t chunkqueue_length(chunkqueue *cq);
++void chunkqueue_free(chunkqueue *cq);
++void chunkqueue_reset(chunkqueue *cq);
+
+-int chunkqueue_is_empty(chunkqueue *c);
++int chunkqueue_is_empty(chunkqueue *cq);
+
+ #endif
+diff --git a/src/connections.c b/src/connections.c
+index bc770bf..3fab768 100644
+--- a/src/connections.c
++++ b/src/connections.c
+@@ -197,31 +197,22 @@ static void dump_packet(const unsigned char *data, size_t len) {
+
+ static int connection_handle_read_ssl(server *srv, connection *con) {
+ #ifdef USE_OPENSSL
+- int r, ssl_err, len, count = 0, read_offset, toread;
+- buffer *b = NULL;
++ int r, ssl_err, len, count = 0;
++ char *mem = NULL;
++ size_t mem_len = 0;
+
+ if (!con->srv_socket->is_ssl) return -1;
+
+ ERR_clear_error();
+ do {
+- if (NULL != con->read_queue->last) {
+- b = con->read_queue->last->mem;
+- }
+-
+- if (NULL == b || b->size - b->used < 1024) {
+- b = chunkqueue_get_append_buffer(con->read_queue);
+- len = SSL_pending(con->ssl);
+- if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */
+- buffer_prepare_copy(b, len);
+-
+- /* overwrite everything with 0 */
+- memset(b->ptr, 0, b->size);
+- }
+-
+- read_offset = (b->used > 0) ? b->used - 1 : 0;
+- toread = b->size - 1 - read_offset;
++ chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl));
++#if 0
++ /* overwrite everything with 0 */
++ memset(mem, 0, mem_len);
++#endif
+
+- len = SSL_read(con->ssl, b->ptr + read_offset, toread);
++ len = SSL_read(con->ssl, mem, mem_len);
++ chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
+
+ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
+@@ -230,15 +221,10 @@ static int connection_handle_read_ssl(server *srv, connection *con) {
+ }
+
+ if (len > 0) {
+- if (b->used > 0) b->used--;
+- b->used += len;
+- b->ptr[b->used++] = '\0';
+-
+ con->bytes_read += len;
+-
+ count += len;
+ }
+- } while (len == toread && count < MAX_READ_LIMIT);
++ } while (len == (ssize_t) mem_len && count < MAX_READ_LIMIT);
+
+
+ if (len < 0) {
+@@ -331,44 +317,36 @@ static int connection_handle_read_ssl(server *srv, connection *con) {
+ /* 0: everything ok, -1: error, -2: con closed */
+ static int connection_handle_read(server *srv, connection *con) {
+ int len;
+- buffer *b;
+- int toread, read_offset;
++ char *mem = NULL;
++ size_t mem_len = 0;
++ int toread;
+
+ if (con->srv_socket->is_ssl) {
+ return connection_handle_read_ssl(srv, con);
+ }
+
+- b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL;
+-
+ /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
+ * us more than 4kb is available
+ * if FIONREAD doesn't signal a big chunk we fill the previous buffer
+ * if it has >= 1kb free
+ */
+ #if defined(__WIN32)
+- if (NULL == b || b->size - b->used < 1024) {
+- b = chunkqueue_get_append_buffer(con->read_queue);
+- buffer_prepare_copy(b, 4 * 1024);
+- }
++ chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096);
+
+- read_offset = (b->used == 0) ? 0 : b->used - 1;
+- len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0);
++ len = recv(con->fd, mem, mem_len, 0);
+ #else
+ if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
+- if (NULL == b || b->size - b->used < 1024) {
+- b = chunkqueue_get_append_buffer(con->read_queue);
+- buffer_prepare_copy(b, 4 * 1024);
+- }
+- } else {
+ if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
+- b = chunkqueue_get_append_buffer(con->read_queue);
+- buffer_prepare_copy(b, toread);
++ } else {
++ toread = 4096;
+ }
++ chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread);
+
+- read_offset = (b->used == 0) ? 0 : b->used - 1;
+- len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset);
++ len = read(con->fd, mem, mem_len);
+ #endif
+
++ chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
++
+ if (len < 0) {
+ con->is_readable = 0;
+
+@@ -394,16 +372,12 @@ static int connection_handle_read(server *srv, connection *con) {
+ /* pipelining */
+
+ return -2;
+- } else if ((size_t)len < b->size - 1) {
++ } else if (len != (ssize_t) mem_len) {
+ /* we got less then expected, wait for the next fd-event */
+
+ con->is_readable = 0;
+ }
+
+- if (b->used > 0) b->used--;
+- b->used += len;
+- b->ptr[b->used++] = '\0';
+-
+ con->bytes_read += len;
+ #if 0
+ dump_packet(b->ptr, len);
+@@ -494,7 +468,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ buffer_reset(con->physical.path);
+
+ con->file_finished = 1;
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ b = buffer_init();
+
+ /* build default error-page */
+ buffer_copy_string_len(b, CONST_STR_LEN(
+@@ -522,6 +496,10 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ "</html>\n"
+ ));
+
++ http_chunk_append_buffer(srv, con, b);
++ buffer_free(b);
++ http_chunk_close(srv, con);
++
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ }
+ break;
+@@ -1029,119 +1007,10 @@ found_header_end:
+ }
+ break;
+ case CON_STATE_READ_POST:
+- for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
+- off_t weWant, weHave, toRead;
+-
+- weWant = con->request.content_length - dst_cq->bytes_in;
+-
+- force_assert(c->mem->used);
+-
+- weHave = c->mem->used - c->offset - 1;
+-
+- toRead = weHave > weWant ? weWant : weHave;
+-
+- /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
+- if (con->request.content_length > 64 * 1024) {
+- chunk *dst_c = NULL;
+- /* copy everything to max 1Mb sized tempfiles */
+-
+- /*
+- * if the last chunk is
+- * - smaller than 1Mb (size < 1Mb)
+- * - not read yet (offset == 0)
+- * -> append to it
+- * otherwise
+- * -> create a new chunk
+- *
+- * */
+-
+- if (dst_cq->last &&
+- dst_cq->last->type == FILE_CHUNK &&
+- dst_cq->last->file.is_temp &&
+- dst_cq->last->offset == 0) {
+- /* ok, take the last chunk for our job */
+-
+- if (dst_cq->last->file.length < 1 * 1024 * 1024) {
+- dst_c = dst_cq->last;
+-
+- if (dst_c->file.fd == -1) {
+- /* this should not happen as we cache the fd, but you never know */
+- dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
+- fd_close_on_exec(dst_c->file.fd);
+- }
+- } else {
+- /* the chunk is too large now, close it */
+- dst_c = dst_cq->last;
+-
+- if (dst_c->file.fd != -1) {
+- close(dst_c->file.fd);
+- dst_c->file.fd = -1;
+- }
+- dst_c = chunkqueue_get_append_tempfile(dst_cq);
+- }
+- } else {
+- dst_c = chunkqueue_get_append_tempfile(dst_cq);
+- }
+-
+- /* we have a chunk, let's write to it */
+-
+- if (dst_c->file.fd == -1) {
+- /* we don't have file to write to,
+- * EACCES might be one reason.
+- *
+- * Instead of sending 500 we send 413 and say the request is too large
+- * */
+-
+- log_error_write(srv, __FILE__, __LINE__, "sbs",
+- "denying upload as opening to temp-file for upload failed:",
+- dst_c->file.name, strerror(errno));
+-
+- con->http_status = 413; /* Request-Entity too large */
+- con->keep_alive = 0;
+- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+-
+- break;
+- }
+-
+- if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
+- /* write failed for some reason ... disk full ? */
+- log_error_write(srv, __FILE__, __LINE__, "sbs",
+- "denying upload as writing to file failed:",
+- dst_c->file.name, strerror(errno));
+-
+- con->http_status = 413; /* Request-Entity too large */
+- con->keep_alive = 0;
+- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+-
+- close(dst_c->file.fd);
+- dst_c->file.fd = -1;
+-
+- break;
+- }
+-
+- dst_c->file.length += toRead;
+-
+- if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
+- /* we read everything, close the chunk */
+- close(dst_c->file.fd);
+- dst_c->file.fd = -1;
+- }
+- } else {
+- buffer *b;
+-
+- if (dst_cq->last &&
+- dst_cq->last->type == MEM_CHUNK) {
+- b = dst_cq->last->mem;
+- } else {
+- b = chunkqueue_get_append_buffer(dst_cq);
+- /* prepare buffer size for remaining POST data; is < 64kb */
+- buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in);
+- }
+- buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
+- }
+-
+- c->offset += toRead;
+- dst_cq->bytes_in += toRead;
++ if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, con->request.content_length - dst_cq->bytes_in )) {
++ con->http_status = 413; /* Request-Entity too large */
++ con->keep_alive = 0;
++ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+ }
+
+ /* Content is ready */
+diff --git a/src/mod_compress.c b/src/mod_compress.c
+index ad6e9f2..b428cd0 100644
+--- a/src/mod_compress.c
++++ b/src/mod_compress.c
+@@ -583,7 +583,6 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
+ int ifd;
+ int ret = -1;
+ void *start;
+- buffer *b;
+
+ /* overflow */
+ if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
+@@ -651,8 +650,7 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
+ if (ret != 0) return -1;
+
+ chunkqueue_reset(con->write_queue);
+- b = chunkqueue_get_append_buffer(con->write_queue);
+- buffer_copy_string_len(b, p->b->ptr, p->b->used);
++ chunkqueue_append_mem(con->write_queue, p->b->ptr, p->b->used);
+
+ buffer_reset(con->physical.path);
+
+diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
+index 4b7106a..e2e0bfa 100644
+--- a/src/mod_dirlisting.c
++++ b/src/mod_dirlisting.c
+@@ -784,7 +784,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+
+ if (files.used) http_dirls_sort(files.ent, files.used);
+
+- out = chunkqueue_get_append_buffer(con->write_queue);
++ out = buffer_init();
+ buffer_copy_string_len(out, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\""));
+ if (buffer_string_is_empty(p->conf.encoding)) {
+ buffer_append_string_len(out, CONST_STR_LEN("iso-8859-1"));
+@@ -899,6 +899,8 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ }
+
+ con->file_finished = 1;
++ chunkqueue_append_buffer(con->write_queue, out);
++ buffer_free(out);
+
+ return 0;
+ }
+diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
+index 01e72e5..e7b62f6 100644
+--- a/src/mod_fastcgi.c
++++ b/src/mod_fastcgi.c
+@@ -52,13 +52,6 @@
+
+ #include "version.h"
+
+-#define FCGI_ENV_ADD_CHECK(ret, con) \
+- if (ret == -1) { \
+- con->http_status = 400; \
+- con->file_finished = 1; \
+- return -1; \
+- };
+-
+ /*
+ *
+ * TODO:
+@@ -1769,6 +1762,12 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
+ return CONNECTION_OK;
+ }
+
++#define FCGI_ENV_ADD_CHECK(ret, con) \
++ if (ret == -1) { \
++ con->http_status = 400; \
++ con->file_finished = 1; \
++ return -1; \
++ };
+ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
+ size_t i;
+
+@@ -1834,11 +1833,9 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+ return 0;
+ }
+
+-
+ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ FCGI_BeginRequestRecord beginRecord;
+ FCGI_Header header;
+- buffer *b;
+
+ char buf[LI_ITOSTRING_LENGTH];
+ const char *s;
+@@ -1863,10 +1860,6 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ beginRecord.body.flags = 0;
+ memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
+
+- b = chunkqueue_get_append_buffer(hctx->wb);
+-
+- buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
+-
+ /* send FCGI_PARAMS */
+ buffer_prepare_copy(p->fcgi_env, 1024);
+
+@@ -2054,14 +2047,22 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
+
+- fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
+- buffer_append_string_len(b, (const char *)&header, sizeof(header));
+- buffer_append_string_len(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
++ {
++ buffer *b = buffer_init();
+
+- fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
+- buffer_append_string_len(b, (const char *)&header, sizeof(header));
++ buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
+
+- hctx->wb->bytes_in += b->used - 1;
++ fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
++ buffer_append_string_len(b, (const char *)&header, sizeof(header));
++ buffer_append_string_len(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
++
++ fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
++ buffer_append_string_len(b, (const char *)&header, sizeof(header));
++
++ hctx->wb->bytes_in += b->used - 1;
++ chunkqueue_append_buffer(hctx->wb, b);
++ buffer_free(b);
++ }
+
+ if (con->request.content_length) {
+ chunkqueue *req_cq = con->request_content_queue;
+@@ -2433,38 +2434,21 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ return -1;
+ }
+
+- /* init read-buffer */
+-
+ if (toread > 0) {
+- buffer *b;
+- chunk *cq_first = hctx->rb->first;
+- chunk *cq_last = hctx->rb->last;
+-
+- b = chunkqueue_get_append_buffer(hctx->rb);
+- buffer_prepare_copy(b, toread + 1);
+-
+- /* append to read-buffer */
+- if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
+- if (errno == EAGAIN) {
+- /* roll back the last chunk allocation,
+- and continue on next iteration */
+- buffer_free(hctx->rb->last->mem);
+- free(hctx->rb->last);
+- hctx->rb->first = cq_first;
+- hctx->rb->last = cq_last;
+- return 0;
+- }
++ char *mem;
++ size_t mem_len;
++
++ chunkqueue_get_memory(hctx->rb, &mem, &mem_len, 0, toread);
++ r = read(hctx->fd, mem, mem_len);
++ chunkqueue_use_memory(hctx->rb, r > 0 ? r : 0);
++
++ if (-1 == r) {
++ if (errno == EAGAIN) return 0;
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "unexpected end-of-file (perhaps the fastcgi process died):",
+ fcgi_fd, strerror(errno));
+ return -1;
+ }
+-
+- /* this should be catched by the b > 0 above */
+- force_assert(r);
+-
+- b->used = r + 1; /* one extra for the fake \0 */
+- b->ptr[b->used - 1] = '\0';
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssdsb",
+ "unexpected end-of-file (perhaps the fastcgi process died):",
+@@ -2973,8 +2957,8 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
+ "fcgi-request is already in use:", hctx->request_id);
+ }
+
+- /* fall through */
+ if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR;
++
+ fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
+ /* fall through */
+ case FCGI_STATE_WRITE:
+diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
+index 501f8e8..1c1a356 100644
+--- a/src/mod_flv_streaming.c
++++ b/src/mod_flv_streaming.c
+@@ -207,7 +207,6 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+ 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;
+- buffer *b;
+ int start;
+ char *err = NULL;
+ /* if there is a start=[0-9]+ in the header use it as start,
+@@ -242,10 +241,9 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+ }
+
+ /* we are safe now, let's build a flv header */
+- b = chunkqueue_get_append_buffer(con->write_queue);
+- buffer_copy_string_len(b, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
+-
++ http_chunk_append_mem(srv, con, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
+ http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
++ http_chunk_close(srv, con);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
+
+diff --git a/src/mod_proxy.c b/src/mod_proxy.c
+index 3bfc78f..2b5a740 100644
+--- a/src/mod_proxy.c
++++ b/src/mod_proxy.c
+@@ -449,7 +449,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
+
+ /* build header */
+
+- b = chunkqueue_get_append_buffer(hctx->wb);
++ b = buffer_init();
+
+ /* request line */
+ buffer_copy_string(b, get_http_method_name(con->request.http_method));
+@@ -486,6 +486,9 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+
+ hctx->wb->bytes_in += b->used - 1;
++ chunkqueue_append_buffer(hctx->wb, b);
++ buffer_free(b);
++
+ /* body */
+
+ if (con->request.content_length) {
+diff --git a/src/mod_scgi.c b/src/mod_scgi.c
+index 66dce5e..2fa265d 100644
+--- a/src/mod_scgi.c
++++ b/src/mod_scgi.c
+@@ -1629,7 +1629,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ scgi_env_add_request_headers(srv, con, p);
+
+- b = chunkqueue_get_append_buffer(hctx->wb);
++ b = buffer_init();
+
+ buffer_append_int(b, p->scgi_env->used);
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+@@ -1637,6 +1637,8 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ buffer_append_string_len(b, CONST_STR_LEN(","));
+
+ hctx->wb->bytes_in += b->used - 1;
++ chunkqueue_append_buffer(hctx->wb, b);
++ buffer_free(b);
+
+ if (con->request.content_length) {
+ chunkqueue *req_cq = con->request_content_queue;
+diff --git a/src/mod_ssi.c b/src/mod_ssi.c
+index 38eeac5..ecdfb99 100644
+--- a/src/mod_ssi.c
++++ b/src/mod_ssi.c
+@@ -430,7 +430,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ case SSI_ECHO_USER_NAME: {
+ struct passwd *pw;
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ b = buffer_init();
+ #ifdef HAVE_PWD_H
+ if (NULL == (pw = getpwuid(sce->st.st_uid))) {
+ buffer_copy_int(b, sce->st.st_uid);
+@@ -440,67 +440,62 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ #else
+ buffer_copy_int(b, sce->st.st_uid);
+ #endif
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
+ break;
+ }
+ case SSI_ECHO_LAST_MODIFIED: {
+ time_t t = sce->st.st_mtime;
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
+- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+- buffer_copy_string(b, buf);
++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ }
+ case SSI_ECHO_DATE_LOCAL: {
+ time_t t = time(NULL);
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
+- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+- buffer_copy_string(b, buf);
++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ }
+ case SSI_ECHO_DATE_GMT: {
+ time_t t = time(NULL);
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
+- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+- buffer_copy_string(b, buf);
++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ }
+ case SSI_ECHO_DOCUMENT_NAME: {
+ char *sl;
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+ if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
+- buffer_copy_buffer(b, con->physical.path);
++ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->physical.path));
+ } else {
+- buffer_copy_string(b, sl + 1);
++ chunkqueue_append_mem(con->write_queue, sl + 1, strlen(sl + 1));
+ }
+ break;
+ }
+ case SSI_ECHO_DOCUMENT_URI: {
+- b = chunkqueue_get_append_buffer(con->write_queue);
+- buffer_copy_buffer(b, con->uri.path);
++ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.path));
+ break;
+ }
+ default: {
+ data_string *ds;
+ /* check if it is a cgi-var */
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+-
+ if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
+- buffer_copy_buffer(b, ds->value);
++ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(ds->value));
+ } else {
+- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ }
+
+ break;
+@@ -583,7 +578,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+
+ switch (ssicmd) {
+ case SSI_FSIZE:
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ b = buffer_init();
+ if (p->sizefmt) {
+ int j = 0;
+ const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
+@@ -597,13 +592,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ } else {
+ buffer_copy_int(b, st.st_size);
+ }
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
+ break;
+ case SSI_FLASTMOD:
+- b = chunkqueue_get_append_buffer(con->write_queue);
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
+- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+- buffer_copy_string(b, buf);
++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ case SSI_INCLUDE:
+@@ -611,7 +607,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+
+ /* Keep the newest mtime of included files */
+ if (st.st_mtime > include_file_last_mtime)
+- include_file_last_mtime = st.st_mtime;
++ include_file_last_mtime = st.st_mtime;
+
+ break;
+ }
+@@ -683,7 +679,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ case SSI_PRINTENV:
+ if (p->if_is_false) break;
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ b = buffer_init();
+ for (i = 0; i < p->ssi_vars->used; i++) {
+ data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
+
+@@ -700,6 +696,8 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
+
+ break;
+ case SSI_EXEC: {
+@@ -791,17 +789,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
+ }
+
+ if (toread > 0) {
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ char *mem;
++ size_t mem_len;
+
+- buffer_prepare_copy(b, toread);
++ chunkqueue_get_memory(con->write_queue, &mem, &mem_len, 0, toread);
++ r = read(from_exec_fds[0], mem, mem_len);
++ chunkqueue_use_memory(con->write_queue, r > 0 ? r : 0);
+
+- if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
+- /* read failed */
+- break;
+- } else {
+- b->used = r;
+- b->ptr[b->used++] = '\0';
+- }
++ if (r < 0) break; /* read failed */
+ } else {
+ break;
+ }
+diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
+index 931bc57..e36c697 100644
+--- a/src/mod_staticfile.c
++++ b/src/mod_staticfile.c
+@@ -285,9 +285,7 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+ if (!error) {
+ if (multipart) {
+ /* write boundary-header */
+- buffer *b;
+-
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ buffer *b = buffer_init();
+
+ buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));
+ buffer_append_string(b, boundary);
+@@ -307,7 +305,8 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+ con->response.content_length += b->used - 1;
+-
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
+ }
+
+ chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
+@@ -320,15 +319,15 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+
+ if (multipart) {
+ /* add boundary end */
+- buffer *b;
+-
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ buffer *b = buffer_init();
+
+ buffer_copy_string_len(b, "\r\n--", 4);
+ buffer_append_string(b, boundary);
+ buffer_append_string_len(b, "--\r\n", 4);
+
+ con->response.content_length += b->used - 1;
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
+
+ /* set header-fields */
+
+diff --git a/src/mod_status.c b/src/mod_status.c
+index e8da0a8..99b332a 100644
+--- a/src/mod_status.c
++++ b/src/mod_status.c
+@@ -199,7 +199,7 @@ static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
+
+ static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+- buffer *b;
++ buffer *b = buffer_init();
+ size_t j;
+ double avg;
+ char multiplier = '\0';
+@@ -208,8 +208,6 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ int days, hours, mins, seconds;
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+-
+ buffer_copy_string_len(b, CONST_STR_LEN(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+@@ -555,6 +553,9 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+ "</html>\n"
+ ));
+
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+
+ return 0;
+@@ -563,15 +564,13 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+- buffer *b;
++ buffer *b = buffer_init();
+ double avg;
+ time_t ts;
+ char buf[32];
+ unsigned int k;
+ unsigned int l;
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+-
+ /* output total number of requests */
+ buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: "));
+ avg = p->abs_requests;
+@@ -598,13 +597,13 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
+- buffer_append_int(b, srv->conns->size - srv->conns->used);
+- buffer_append_string_len(b, CONST_STR_LEN("\n"));
++ buffer_append_int(b, srv->conns->size - srv->conns->used);
++ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+- /* output scoreboard */
+- buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: "));
+- for (k = 0; k < srv->conns->used; k++) {
+- connection *c = srv->conns->ptr[k];
++ /* output scoreboard */
++ buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: "));
++ for (k = 0; k < srv->conns->used; k++) {
++ connection *c = srv->conns->ptr[k];
+ const char *state = connection_get_short_state(c->state);
+ buffer_append_string_len(b, state, 1);
+ }
+@@ -613,15 +612,17 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+- /* set text/plain output */
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
+
++ /* set text/plain output */
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
+
+ return 0;
+ }
+
+ static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
+- buffer *b;
++ buffer *b = buffer_init();
+ size_t i;
+ array *st = srv->status;
+ UNUSED(p_d);
+@@ -634,8 +635,6 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co
+ return HANDLER_FINISHED;
+ }
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+-
+ for (i = 0; i < st->used; i++) {
+ size_t ndx = st->sorted[i];
+
+@@ -645,6 +644,9 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
+
+ con->http_status = 200;
+@@ -671,7 +673,8 @@ static handler_t mod_status_handle_server_status(server *srv, connection *con, v
+
+ static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+- buffer *b, *m = p->module_list;
++ buffer *b = buffer_init();
++ buffer *m = p->module_list;
+ size_t i;
+
+ struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
+@@ -703,8 +706,6 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
+ { FDEVENT_HANDLER_UNSET, NULL }
+ };
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+-
+ buffer_copy_string_len(b, CONST_STR_LEN(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+@@ -756,6 +757,9 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
+ "</html>\n"
+ ));
+
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+
+ con->http_status = 200;
+diff --git a/src/mod_webdav.c b/src/mod_webdav.c
+index a3807c0..433b904 100644
+--- a/src/mod_webdav.c
++++ b/src/mod_webdav.c
+@@ -1094,7 +1094,7 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
+ static int webdav_lockdiscovery(server *srv, connection *con,
+ buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
+
+- buffer *b;
++ buffer *b = buffer_init();
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
+
+@@ -1102,8 +1102,6 @@ static int webdav_lockdiscovery(server *srv, connection *con,
+ CONST_STR_LEN("Content-Type"),
+ CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
+-
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
+@@ -1143,6 +1141,9 @@ static int webdav_lockdiscovery(server *srv, connection *con,
+ buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ return 0;
+ }
+ #endif
+@@ -1341,7 +1342,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ b = buffer_init();
+
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+@@ -1487,6 +1488,10 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ if (p->conf.log_xml) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
+ }
++
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+@@ -1555,7 +1560,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ /* we got an error somewhere in between, build a 207 */
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+- b = chunkqueue_get_append_buffer(con->write_queue);
++ b = buffer_init();
+
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+@@ -1569,6 +1574,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
+ }
+
++ chunkqueue_append_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ con->http_status = 207;
+ con->file_finished = 1;
+ } else {
+diff --git a/src/response.c b/src/response.c
+index bde381f..31bcd69 100644
+--- a/src/response.c
++++ b/src/response.c
+@@ -33,7 +33,7 @@ int http_response_write_header(server *srv, connection *con) {
+ int have_date = 0;
+ int have_server = 0;
+
+- b = chunkqueue_get_prepend_buffer(con->write_queue);
++ b = buffer_init();
+
+ if (con->request.http_version == HTTP_VERSION_1_1) {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
+@@ -121,13 +121,15 @@ int http_response_write_header(server *srv, connection *con) {
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+-
+ con->bytes_header = b->used - 1;
+
+ if (con->conf.log_response_header) {
+ log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
+ }
+
++ chunkqueue_prepend_buffer(con->write_queue, b);
++ buffer_free(b);
++
+ return 0;
+ }
+
+--
+2.4.5
+
diff --git a/main/lighttpd/0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch b/main/lighttpd/0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch
new file mode 100644
index 0000000000..97e6d3015b
--- /dev/null
+++ b/main/lighttpd/0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch
@@ -0,0 +1,1182 @@
+From 4365bdbebe4542efc28ce6a79e1341870abc24d3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:39 +0000
+Subject: [PATCH 17/29] Remove buffer_prepare_copy() and
+ buffer_prepare_append()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+* removed almost all usages of buffer as "memory" (without terminating
+ zero)
+* refactored cgi variable name encoding
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2977 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/buffer.c | 99 ++++++++++++++++++++++----------------
+ src/buffer.h | 24 +++++-----
+ src/configfile.c | 4 +-
+ src/http-header-glue.c | 2 +-
+ src/http_auth.c | 2 +-
+ src/http_chunk.c | 4 +-
+ src/log.c | 2 +-
+ src/mod_accesslog.c | 8 ++--
+ src/mod_cgi.c | 49 ++-----------------
+ src/mod_compress.c | 27 ++++++-----
+ src/mod_expire.c | 2 +-
+ src/mod_fastcgi.c | 128 ++++++++++++++++---------------------------------
+ src/mod_mysql_vhost.c | 2 +-
+ src/mod_proxy.c | 12 ++---
+ src/mod_rrdtool.c | 11 +++--
+ src/mod_scgi.c | 47 +++++-------------
+ src/mod_simple_vhost.c | 2 +-
+ src/mod_ssi.c | 40 +---------------
+ src/network_write.c | 2 +-
+ src/proc_open.c | 6 +--
+ src/response.c | 4 +-
+ src/stat_cache.c | 7 ++-
+ 22 files changed, 175 insertions(+), 309 deletions(-)
+
+diff --git a/src/buffer.c b/src/buffer.c
+index 019abb7..979d954 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -83,7 +83,7 @@ static size_t buffer_align_size(size_t size) {
+ return size + align;
+ }
+
+-char* buffer_prepare_copy(buffer *b, size_t size) {
++static char* buffer_prepare_copy(buffer *b, size_t size) {
+ force_assert(NULL != b);
+
+ /* also allocate space for terminating 0 */
+@@ -109,36 +109,6 @@ char* buffer_prepare_copy(buffer *b, size_t size) {
+ return b->ptr;
+ }
+
+-char* buffer_prepare_append(buffer *b, size_t size) {
+- size_t req_size;
+- force_assert(NULL != b);
+-
+- if (buffer_string_is_empty(b)) {
+- size_t old_used = b->used; /* either 0 or 1 */
+- /* just prepare copy (free+malloc instead of realloc) */
+- buffer_prepare_copy(b, size);
+- b->used = old_used; /* buffer_prepare_append mustn't modify b->used */
+- return b->ptr;
+- }
+-
+- /* not empty, b->used already includes a terminating 0 */
+- req_size = b->used + size;
+-
+- /* check for overflow: unsigned overflow is defined to wrap around */
+- force_assert(req_size >= b->used);
+-
+- if (req_size > b->size) {
+- char *ptr;
+- b->size = buffer_align_size(req_size);
+-
+- ptr = realloc(b->ptr, b->size);
+- force_assert(NULL != ptr);
+- b->ptr = ptr;
+- }
+-
+- return b->ptr + b->used - 1;
+-}
+-
+ char* buffer_string_prepare_copy(buffer *b, size_t size) {
+ force_assert(NULL != b);
+
+@@ -151,11 +121,28 @@ char* buffer_string_prepare_copy(buffer *b, size_t size) {
+ char* buffer_string_prepare_append(buffer *b, size_t size) {
+ force_assert(NULL != b);
+
+- if (0 == b->used) {
++ if (buffer_string_is_empty(b)) {
+ return buffer_string_prepare_copy(b, size);
+ } else {
++ /* not empty, b->used already includes a terminating 0 */
++ size_t req_size = b->used + size;
++
++ /* check for overflow: unsigned overflow is defined to wrap around */
++ force_assert(req_size >= b->used);
++
++ /* only append to 0-terminated string */
+ force_assert('\0' == b->ptr[b->used - 1]);
+- return buffer_prepare_append(b, size);
++
++ if (req_size > b->size) {
++ char *ptr;
++ b->size = buffer_align_size(req_size);
++
++ ptr = realloc(b->ptr, b->size);
++ force_assert(NULL != ptr);
++ b->ptr = ptr;
++ }
++
++ return b->ptr + b->used - 1;
+ }
+ }
+
+@@ -186,7 +173,7 @@ void buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
+ force_assert(NULL != b);
+ force_assert(NULL != s || s_len == 0);
+
+- buffer_prepare_copy(b, s_len);
++ buffer_string_prepare_copy(b, s_len);
+
+ if (0 != s_len) memcpy(b->ptr, s, s_len);
+
+@@ -222,12 +209,11 @@ void buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
+ force_assert(NULL != b);
+ force_assert(NULL != s || s_len == 0);
+
+- target_buf = buffer_prepare_append(b, s_len);
++ target_buf = buffer_string_prepare_append(b, s_len);
+
+- /* only append to 0-terminated string */
+- force_assert('\0' == *target_buf);
++ if (0 == s_len) return; /* nothing to append */
+
+- if (s_len > 0) memcpy(target_buf, s, s_len);
++ memcpy(target_buf, s, s_len);
+
+ buffer_commit(b, s_len);
+ }
+@@ -667,7 +653,7 @@ void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer
+ }
+ }
+
+- d = (unsigned char*) buffer_prepare_append(b, d_len);
++ d = (unsigned char*) buffer_string_prepare_append(b, d_len);
+ buffer_commit(b, d_len); /* fill below */
+ force_assert('\0' == *d);
+
+@@ -704,6 +690,35 @@ void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer
+ }
+ }
+
++void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header) {
++ size_t i, j;
++
++ force_assert(NULL != b);
++ force_assert(NULL != s || 0 == s_len);
++
++ buffer_reset(b);
++
++ if (is_http_header && NULL != s && 0 != strcasecmp(s, "CONTENT-TYPE")) {
++ buffer_string_prepare_append(b, s_len + 5);
++ buffer_copy_string_len(b, CONST_STR_LEN("HTTP_"));
++ } else {
++ buffer_string_prepare_append(b, s_len);
++ }
++
++ j = buffer_string_length(b);
++ for (i = 0; i < s_len; ++i) {
++ unsigned char cr = s[i];
++ if (light_isalpha(cr)) {
++ /* upper-case */
++ cr &= ~32;
++ } else if (!light_isdigit(cr)) {
++ cr = '_';
++ }
++ b->ptr[j++] = cr;
++ }
++ b->used = j;
++ b->ptr[b->used++] = '\0';
++}
+
+ /* decodes url-special-chars inplace.
+ * replaces non-printable characters with '_'
+@@ -790,7 +805,7 @@ void buffer_path_simplify(buffer *dest, buffer *src)
+ force_assert(NULL != dest && NULL != src);
+
+ if (buffer_string_is_empty(src)) {
+- buffer_copy_string_len(dest, NULL, 0);
++ buffer_string_prepare_copy(dest, 0);
+ return;
+ }
+
+@@ -798,9 +813,9 @@ void buffer_path_simplify(buffer *dest, buffer *src)
+
+ /* might need one character more for the '/' prefix */
+ if (src == dest) {
+- buffer_prepare_append(dest, 1);
++ buffer_string_prepare_append(dest, 1);
+ } else {
+- buffer_prepare_copy(dest, buffer_string_length(src) + 1);
++ buffer_string_prepare_copy(dest, buffer_string_length(src) + 1);
+ }
+
+ #if defined(__WIN32) || defined(__CYGWIN__)
+diff --git a/src/buffer.h b/src/buffer.h
+index 5d540a4..7ea27f1 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -49,22 +49,19 @@ void buffer_reset(buffer *b); /* b can be NULL */
+ /* reset b. if NULL != b && NULL != src, move src content to b. reset src. */
+ void buffer_move(buffer *b, buffer *src);
+
+-/* prepare for size bytes in the buffer (b->size > size), destroys content
+- * (sets used = 0 and ptr[0] = 0). allocates storage for terminating 0.
++/* make sure buffer is large enough to store a string of given size
++ * and a terminating zero.
++ * sets b to an empty string, and may drop old content.
+ * @return b->ptr
+ */
+-char* buffer_prepare_copy(buffer *b, size_t size);
++char* buffer_string_prepare_copy(buffer *b, size_t size);
+
+-/* prepare for appending size bytes to the buffer
+- * allocates storage for terminating 0; if used > 0 assumes ptr[used-1] == 0,
+- * i.e. doesn't allocate another byte for terminating 0.
+- * @return (b->used > 0 ? b->ptr + b->used - 1 : b->ptr) - first new character
++/* allocate buffer large enough to be able to append a string of given size
++ * if b was empty (used == 0) it will contain an empty string (used == 1)
++ * afterwards
++ * "used" data is preserved; if not empty buffer must contain a
++ * zero terminated string.
+ */
+-char* buffer_prepare_append(buffer *b, size_t size);
+-
+-/* similar to buffer_prepare_copy(b, size), but sets b->used = 1 */
+-char* buffer_string_prepare_copy(buffer *b, size_t size);
+-/* similar to buffer_prepare_append(b, size), but sets b->used = 1 if used was b->0 before */
+ char* buffer_string_prepare_append(buffer *b, size_t size);
+
+ /* use after prepare_(copy,append) when you have written data to the buffer
+@@ -123,6 +120,9 @@ typedef enum {
+
+ void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
+
++/* to upper case, replace non alpha-numerics with '_'; if is_http_header prefix with "HTTP_" unless s is "content-type" */
++void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header);
++
+ void buffer_urldecode_path(buffer *url);
+ void buffer_urldecode_query(buffer *url);
+ void buffer_path_simplify(buffer *dest, buffer *src);
+diff --git a/src/configfile.c b/src/configfile.c
+index 2b09d86..1c36c3e 100644
+--- a/src/configfile.c
++++ b/src/configfile.c
+@@ -1066,7 +1066,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
+ "opening", source, "failed:", strerror(errno));
+ ret = -1;
+ } else {
+- tokenizer_init(&t, source, out->ptr, out->used);
++ tokenizer_init(&t, source, CONST_BUF_LEN(out));
+ ret = config_parse(srv, context, &t);
+ }
+
+@@ -1128,7 +1128,7 @@ int config_read(server *srv, const char *fn) {
+ array_insert_unique(srv->config, (data_unset *)dpid);
+
+ dcwd = data_string_init();
+- buffer_prepare_copy(dcwd->value, 1024);
++ buffer_string_prepare_copy(dcwd->value, 1023);
+ if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
+ dcwd->value->used = strlen(dcwd->value->ptr) + 1;
+ buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
+diff --git a/src/http-header-glue.c b/src/http-header-glue.c
+index abffb7d..f910f3f 100644
+--- a/src/http-header-glue.c
++++ b/src/http-header-glue.c
+@@ -235,7 +235,7 @@ buffer * strftime_cache_get(server *srv, time_t last_mod) {
+ }
+
+ srv->mtime_cache[i].mtime = last_mod;
+- buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
++ buffer_string_prepare_copy(srv->mtime_cache[i].str, 1023);
+ tm = gmtime(&(srv->mtime_cache[i].mtime));
+ srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
+ srv->mtime_cache[i].str->size - 1,
+diff --git a/src/http_auth.c b/src/http_auth.c
+index 91e388c..c693645 100644
+--- a/src/http_auth.c
++++ b/src/http_auth.c
+@@ -97,7 +97,7 @@ static unsigned char * base64_decode(buffer *out, const char *in) {
+
+ size_t in_len = strlen(in);
+
+- buffer_prepare_copy(out, in_len);
++ buffer_string_prepare_copy(out, in_len);
+
+ result = (unsigned char *)out->ptr;
+
+diff --git a/src/http_chunk.c b/src/http_chunk.c
+index e3647e6..dd6a043 100644
+--- a/src/http_chunk.c
++++ b/src/http_chunk.c
+@@ -35,8 +35,8 @@ static void http_chunk_append_len(server *srv, connection *con, size_t len) {
+ len >>= 4;
+ }
+
+- /* i is the number of hex digits we have */
+- buffer_prepare_copy(b, i + 2);
++ /* i is the number of hex digits we have, + \r\n */
++ buffer_string_prepare_copy(b, i + 2);
+
+ for (j = i-1, len = olen; j+1 > 0; j--) {
+ b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
+diff --git a/src/log.c b/src/log.c
+index 75decfe..097e59e 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -332,7 +332,7 @@ static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsi
+ if (-1 == srv->errorlog_fd) return -1;
+ /* cache the generated timestamp */
+ if (srv->cur_ts != srv->last_generated_debug_ts) {
+- buffer_prepare_copy(srv->ts_debug_str, 255);
++ buffer_string_prepare_copy(srv->ts_debug_str, 255);
+ strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
+ srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
+
+diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
+index 89fd7f5..20d52b9 100644
+--- a/src/mod_accesslog.c
++++ b/src/mod_accesslog.c
+@@ -165,10 +165,10 @@ static void accesslog_append_escaped(buffer *dest, buffer *str) {
+
+ /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
+ /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
+- if (str->used == 0) return;
+- buffer_prepare_append(dest, str->used - 1);
++ if (buffer_string_is_empty(str)) return;
++ buffer_string_prepare_append(dest, buffer_string_length(str));
+
+- for (ptr = start = str->ptr, end = str->ptr + str->used - 1; ptr < end; ptr++) {
++ for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) {
+ char const c = *ptr;
+ if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
+ /* nothing to change, add later as one block */
+@@ -711,7 +711,7 @@ REQUESTDONE_FUNC(log_access_write) {
+ long scd, hrs, min;
+ #endif
+
+- buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
++ buffer_string_prepare_copy(p->conf.ts_accesslog_str, 255);
+ #if defined(HAVE_STRUCT_TM_GMTOFF)
+ # ifdef HAVE_LOCALTIME_R
+ localtime_r(&(srv->cur_ts), &tm);
+diff --git a/src/mod_cgi.c b/src/mod_cgi.c
+index 76882e8..f132b8a 100644
+--- a/src/mod_cgi.c
++++ b/src/mod_cgi.c
+@@ -344,13 +344,13 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ int toread;
+
+ #if defined(__WIN32)
+- buffer_prepare_copy(hctx->response, 4 * 1024);
++ buffer_string_prepare_copy(hctx->response, 4 * 1024);
+ #else
+ if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
+- buffer_prepare_copy(hctx->response, 4 * 1024);
++ buffer_string_prepare_copy(hctx->response, 4 * 1024);
+ } else {
+ if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
+- buffer_prepare_copy(hctx->response, toread);
++ buffer_string_prepare_copy(hctx->response, toread);
+ }
+ #endif
+
+@@ -939,29 +939,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ ds = (data_string *)con->request.headers->data[n];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+-
+- buffer_reset(p->tmp_buf);
+-
+- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
+- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_"));
+- p->tmp_buf->used--; /* strip \0 after HTTP_ */
+- }
+-
+- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
+-
+- for (j = 0; j < ds->key->used - 1; j++) {
+- char cr = '_';
+- if (light_isalpha(ds->key->ptr[j])) {
+- /* upper-case */
+- cr = ds->key->ptr[j] & ~32;
+- } else if (light_isdigit(ds->key->ptr[j])) {
+- /* copy */
+- cr = ds->key->ptr[j];
+- }
+- p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
+- }
+- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
+ }
+@@ -973,24 +951,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ ds = (data_string *)con->environment->data[n];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+-
+- buffer_reset(p->tmp_buf);
+-
+- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
+-
+- for (j = 0; j < ds->key->used - 1; j++) {
+- char cr = '_';
+- if (light_isalpha(ds->key->ptr[j])) {
+- /* upper-case */
+- cr = ds->key->ptr[j] & ~32;
+- } else if (light_isdigit(ds->key->ptr[j])) {
+- /* copy */
+- cr = ds->key->ptr[j];
+- }
+- p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
+- }
+- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
+ }
+diff --git a/src/mod_compress.c b/src/mod_compress.c
+index b428cd0..120b379 100644
+--- a/src/mod_compress.c
++++ b/src/mod_compress.c
+@@ -266,7 +266,7 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+ z.total_in = 0;
+
+
+- buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
++ buffer_string_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
+
+ /* write gzip header */
+
+@@ -284,7 +284,7 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+
+ p->b->used = 10;
+ z.next_out = (unsigned char *)p->b->ptr + p->b->used;
+- z.avail_out = p->b->size - p->b->used - 8;
++ z.avail_out = p->b->size - p->b->used - 9;
+ z.total_out = 0;
+
+ if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
+@@ -308,6 +308,7 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+ c[6] = (z.total_in >> 16) & 0xff;
+ c[7] = (z.total_in >> 24) & 0xff;
+ p->b->used += 8;
++ p->b->ptr[p->b->used++] = '\0';
+
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+@@ -339,10 +340,10 @@ static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_d
+ z.avail_in = st_size;
+ z.total_in = 0;
+
+- buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
++ buffer_string_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
+
+ z.next_out = (unsigned char *)p->b->ptr;
+- z.avail_out = p->b->size;
++ z.avail_out = p->b->size - 1;
+ z.total_out = 0;
+
+ if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
+@@ -350,13 +351,13 @@ static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_d
+ return -1;
+ }
+
+- /* trailer */
+- p->b->used = z.total_out;
+-
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+ }
+
++ /* trailer */
++ buffer_commit(p->b, z.total_out);
++
+ return 0;
+ }
+
+@@ -385,10 +386,10 @@ static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_dat
+ bz.total_in_lo32 = 0;
+ bz.total_in_hi32 = 0;
+
+- buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
++ buffer_string_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
+
+ bz.next_out = p->b->ptr;
+- bz.avail_out = p->b->size;
++ bz.avail_out = p->b->size - 1;
+ bz.total_out_lo32 = 0;
+ bz.total_out_hi32 = 0;
+
+@@ -402,6 +403,7 @@ static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_dat
+
+ /* trailer */
+ p->b->used = bz.total_out_lo32;
++ p->b->ptr[p->b->used++] = '\0';
+
+ if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
+ return -1;
+@@ -434,7 +436,6 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
+
+ if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
+ buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
+- buffer_copy_buffer(p->b, p->ofn);
+ } else {
+ buffer_append_string_buffer(p->ofn, con->uri.path);
+ }
+@@ -546,11 +547,11 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
+ }
+
+ if (ret == 0) {
+- r = write(ofd, p->b->ptr, p->b->used);
++ r = write(ofd, CONST_BUF_LEN(p->b));
+ if (-1 == r) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "writing cachefile", p->ofn, "failed:", strerror(errno));
+ ret = -1;
+- } else if ((size_t)r != p->b->used) {
++ } else if ((size_t)r != buffer_string_length(p->b)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "writing cachefile", p->ofn, "failed: not enough bytes written");
+ ret = -1;
+ }
+@@ -650,7 +651,7 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
+ if (ret != 0) return -1;
+
+ chunkqueue_reset(con->write_queue);
+- chunkqueue_append_mem(con->write_queue, p->b->ptr, p->b->used);
++ chunkqueue_append_buffer(con->write_queue, p->b);
+
+ buffer_reset(con->physical.path);
+
+diff --git a/src/mod_expire.c b/src/mod_expire.c
+index 41895f9..31a81b7 100644
+--- a/src/mod_expire.c
++++ b/src/mod_expire.c
+@@ -43,7 +43,7 @@ INIT_FUNC(mod_expire_init) {
+
+ p->expire_tstmp = buffer_init();
+
+- buffer_prepare_copy(p->expire_tstmp, 255);
++ buffer_string_prepare_copy(p->expire_tstmp, 255);
+
+ return p;
+ }
+diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
+index e7b62f6..a935961 100644
+--- a/src/mod_fastcgi.c
++++ b/src/mod_fastcgi.c
+@@ -311,7 +311,6 @@ typedef struct {
+ buffer *fcgi_env;
+
+ buffer *path;
+- buffer *parse_response;
+
+ buffer *statuskey;
+
+@@ -672,7 +671,6 @@ INIT_FUNC(mod_fastcgi_init) {
+ p->fcgi_env = buffer_init();
+
+ p->path = buffer_init();
+- p->parse_response = buffer_init();
+
+ p->statuskey = buffer_init();
+
+@@ -687,7 +685,6 @@ FREE_FUNC(mod_fastcgi_free) {
+
+ buffer_free(p->fcgi_env);
+ buffer_free(p->path);
+- buffer_free(p->parse_response);
+ buffer_free(p->statuskey);
+
+ if (p->config_storage) {
+@@ -1578,6 +1575,8 @@ static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d)
+
+ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
+ size_t len;
++ char len_enc[8];
++ size_t len_enc_len = 0;
+
+ if (!key || !val) return -1;
+
+@@ -1586,7 +1585,7 @@ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char
+ len += key_len > 127 ? 4 : 1;
+ len += val_len > 127 ? 4 : 1;
+
+- if (env->used + len >= FCGI_MAX_LENGTH) {
++ if (buffer_string_length(env) + len >= FCGI_MAX_LENGTH) {
+ /**
+ * we can't append more headers, ignore it
+ */
+@@ -1598,33 +1597,32 @@ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char
+ *
+ * HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit
+ */
+- if (key_len > 0x7fffffff) key_len = 0x7fffffff;
+- if (val_len > 0x7fffffff) val_len = 0x7fffffff;
++ force_assert(key_len < 0x7fffffffu);
++ force_assert(val_len < 0x7fffffffu);
+
+- buffer_prepare_append(env, len);
++ buffer_string_prepare_append(env, len);
+
+ if (key_len > 127) {
+- env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
+- env->ptr[env->used++] = (key_len >> 16) & 0xff;
+- env->ptr[env->used++] = (key_len >> 8) & 0xff;
+- env->ptr[env->used++] = (key_len >> 0) & 0xff;
++ len_enc[len_enc_len++] = ((key_len >> 24) & 0xff) | 0x80;
++ len_enc[len_enc_len++] = (key_len >> 16) & 0xff;
++ len_enc[len_enc_len++] = (key_len >> 8) & 0xff;
++ len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
+ } else {
+- env->ptr[env->used++] = (key_len >> 0) & 0xff;
++ len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
+ }
+
+ if (val_len > 127) {
+- env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
+- env->ptr[env->used++] = (val_len >> 16) & 0xff;
+- env->ptr[env->used++] = (val_len >> 8) & 0xff;
+- env->ptr[env->used++] = (val_len >> 0) & 0xff;
++ len_enc[len_enc_len++] = ((val_len >> 24) & 0xff) | 0x80;
++ len_enc[len_enc_len++] = (val_len >> 16) & 0xff;
++ len_enc[len_enc_len++] = (val_len >> 8) & 0xff;
++ len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
+ } else {
+- env->ptr[env->used++] = (val_len >> 0) & 0xff;
++ len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
+ }
+
+- memcpy(env->ptr + env->used, key, key_len);
+- env->used += key_len;
+- memcpy(env->ptr + env->used, val, val_len);
+- env->used += val_len;
++ buffer_append_string_len(env, len_enc, len_enc_len);
++ buffer_append_string_len(env, key, key_len);
++ buffer_append_string_len(env, val, val_len);
+
+ return 0;
+ }
+@@ -1777,27 +1775,7 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+ ds = (data_string *)con->request.headers->data[i];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+- buffer_reset(srv->tmp_buf);
+-
+- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
+- buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
+- srv->tmp_buf->used--;
+- }
+-
+- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+- for (j = 0; j < ds->key->used - 1; j++) {
+- char c = '_';
+- if (light_isalpha(ds->key->ptr[j])) {
+- /* upper-case */
+- c = ds->key->ptr[j] & ~32;
+- } else if (light_isdigit(ds->key->ptr[j])) {
+- /* copy */
+- c = ds->key->ptr[j];
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);
+ }
+@@ -1809,22 +1787,7 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+ ds = (data_string *)con->environment->data[i];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+- buffer_reset(srv->tmp_buf);
+-
+- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+- for (j = 0; j < ds->key->used - 1; j++) {
+- char c = '_';
+- if (light_isalpha(ds->key->ptr[j])) {
+- /* upper-case */
+- c = ds->key->ptr[j] & ~32;
+- } else if (light_isdigit(ds->key->ptr[j])) {
+- /* copy */
+- c = ds->key->ptr[j];
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);
+ }
+@@ -1861,7 +1824,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
+
+ /* send FCGI_PARAMS */
+- buffer_prepare_copy(p->fcgi_env, 1024);
++ buffer_string_prepare_copy(p->fcgi_env, 1023);
+
+
+ if (buffer_is_empty(con->conf.server_tag)) {
+@@ -2052,9 +2015,9 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+
+ buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
+
+- fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
++ fcgi_header(&(header), FCGI_PARAMS, request_id, buffer_string_length(p->fcgi_env), 0);
+ buffer_append_string_len(b, (const char *)&header, sizeof(header));
+- buffer_append_string_len(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
++ buffer_append_string_buffer(b, p->fcgi_env);
+
+ fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
+ buffer_append_string_len(b, (const char *)&header, sizeof(header));
+@@ -2109,17 +2072,15 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf
+
+ UNUSED(srv);
+
+- buffer_copy_buffer(p->parse_response, in);
+-
+ /* search for \n */
+- for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
++ for (s = in->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
+ char *key, *value;
+ int key_len;
+ data_string *ds = NULL;
+
+ /* a good day. Someone has read the specs and is sending a \r\n to us */
+
+- if (ns > p->parse_response->ptr &&
++ if (ns > in->ptr &&
+ *(ns-1) == '\r') {
+ *(ns-1) = '\0';
+ }
+@@ -2315,7 +2276,7 @@ typedef struct {
+ } fastcgi_response_packet;
+
+ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {
+- chunk * c;
++ chunk *c;
+ size_t offset;
+ size_t toread;
+ FCGI_Header *header;
+@@ -2331,15 +2292,11 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
+ offset = 0; toread = 8;
+ /* get at least the FastCGI header */
+ for (c = hctx->rb->first; c; c = c->next) {
+- size_t weHave = c->mem->used - c->offset - 1;
++ size_t weHave = buffer_string_length(c->mem) - c->offset;
+
+ if (weHave > toread) weHave = toread;
+
+- if (packet->b->used == 0) {
+- buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, weHave);
+- } else {
+- buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave);
+- }
++ buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave);
+ toread -= weHave;
+ offset = weHave; /* skip offset bytes in chunk for "real" data */
+
+@@ -2478,7 +2435,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ /* is the header already finished */
+ if (0 == con->file_started) {
+ char *c;
+- size_t blen;
+ data_string *ds;
+
+ /* search for header terminator
+@@ -2489,20 +2445,20 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ * search for \n\n
+ */
+
+- if (hctx->response_header->used == 0) {
+- buffer_copy_buffer(hctx->response_header, packet.b);
+- } else {
+- buffer_append_string_buffer(hctx->response_header, packet.b);
+- }
++ buffer_append_string_buffer(hctx->response_header, packet.b);
+
+ if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
+- blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4 - 1;
+- hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
+- c += 4; /* point the the start of the response */
++ char *hend = c + 4; /* header end == body start */
++ size_t hlen = hend - hctx->response_header->ptr;
++ buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen);
++ hctx->response_header->used = hlen;
++ hctx->response_header->ptr[hctx->response_header->used++] = '\0';
+ } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
+- blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2 - 1;
+- hctx->response_header->used = c - hctx->response_header->ptr + 2;
+- c += 2; /* point the the start of the response */
++ char *hend = c + 2; /* header end == body start */
++ size_t hlen = hend - hctx->response_header->ptr;
++ buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen);
++ hctx->response_header->used = hlen;
++ hctx->response_header->ptr[hctx->response_header->used++] = '\0';
+ } else {
+ /* no luck, no header found */
+ break;
+@@ -2559,14 +2515,14 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ }
+
+
+- if (hctx->send_content_body && blen > 0) {
++ if (hctx->send_content_body && buffer_string_length(packet.b) > 0) {
+ /* enable chunked-transfer-encoding */
+ if (con->request.http_version == HTTP_VERSION_1_1 &&
+ !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
+ }
+
+- http_chunk_append_mem(srv, con, c, blen);
++ http_chunk_append_buffer(srv, con, packet.b);
+ joblist_append(srv, con);
+ }
+ } else if (hctx->send_content_body && packet.b->used > 1) {
+diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
+index 8442f76..7d679fb 100644
+--- a/src/mod_mysql_vhost.c
++++ b/src/mod_mysql_vhost.c
+@@ -355,7 +355,7 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+ unsigned long to_len;
+
+ /* 'to' has to be 'from_len * 2 + 1' */
+- buffer_prepare_append(p->tmp_buf, (con->uri.authority->used - 1) * 2 + 1);
++ buffer_string_prepare_append(p->tmp_buf, (con->uri.authority->used - 1) * 2 + 1);
+
+ to_len = mysql_real_escape_string(p->conf.mysql,
+ p->tmp_buf->ptr + p->tmp_buf->used - 1,
+diff --git a/src/mod_proxy.c b/src/mod_proxy.c
+index 2b5a740..fc2ca1a 100644
+--- a/src/mod_proxy.c
++++ b/src/mod_proxy.c
+@@ -624,15 +624,9 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+ }
+
+ if (b > 0) {
+- if (hctx->response->used == 0) {
+- /* avoid too small buffer */
+- buffer_prepare_append(hctx->response, b + 1);
+- hctx->response->used = 1;
+- } else {
+- buffer_prepare_append(hctx->response, b);
+- }
++ buffer_string_prepare_append(hctx->response, b);
+
+- if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
++ if (-1 == (r = read(hctx->fd, hctx->response->ptr + buffer_string_length(hctx->response), buffer_string_space(hctx->response)))) {
+ if (errno == EAGAIN) return 0;
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "unexpected end-of-file (perhaps the proxy process died):",
+@@ -653,7 +647,7 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+
+ if (0 == con->got_response) {
+ con->got_response = 1;
+- buffer_prepare_copy(hctx->response_header, 128);
++ buffer_string_prepare_copy(hctx->response_header, 1023);
+ }
+
+ if (0 == con->file_started) {
+diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
+index 4986ea3..5eb0d9d 100644
+--- a/src/mod_rrdtool.c
++++ b/src/mod_rrdtool.c
+@@ -271,8 +271,8 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s)
+ return HANDLER_ERROR;
+ }
+
+- buffer_prepare_copy(p->resp, 4096);
+- if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) {
++ buffer_string_prepare_copy(p->resp, 4095);
++ if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size - 1))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-read: failed", strerror(errno));
+
+@@ -280,6 +280,7 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s)
+ }
+
+ p->resp->used = r;
++ p->resp->ptr[p->resp->used++] = '\0';
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+@@ -434,7 +435,7 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ return HANDLER_ERROR;
+ }
+
+- buffer_prepare_copy(p->resp, 4096);
++ buffer_string_prepare_copy(p->resp, 4096);
+ if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size - 1))) {
+ p->rrdtool_running = 0;
+
+@@ -444,8 +445,8 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ return HANDLER_ERROR;
+ }
+
+- p->resp->used = r + 1;
+- p->resp->ptr[r] = '\0';
++ p->resp->used = r;
++ p->resp->ptr[p->resp->used++] = '\0';
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+diff --git a/src/mod_scgi.c b/src/mod_scgi.c
+index 2fa265d..9ea16a4 100644
+--- a/src/mod_scgi.c
++++ b/src/mod_scgi.c
+@@ -1301,14 +1301,12 @@ static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char
+
+ len = key_len + val_len + 2;
+
+- buffer_prepare_append(env, len);
++ buffer_string_prepare_append(env, len);
+
+- memcpy(env->ptr + env->used, key, key_len);
+- env->ptr[env->used + key_len] = '\0';
+- env->used += key_len + 1;
+- memcpy(env->ptr + env->used, val, val_len);
+- env->ptr[env->used + val_len] = '\0';
+- env->used += val_len + 1;
++ buffer_append_string_len(env, key, key_len);
++ buffer_append_string_len(env, "", 1);
++ buffer_append_string_len(env, val, val_len);
++ buffer_append_string_len(env, "", 1);
+
+ return 0;
+ }
+@@ -1419,21 +1417,7 @@ static int scgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+ ds = (data_string *)con->request.headers->data[i];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+- buffer_reset(srv->tmp_buf);
+-
+- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
+- buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
+- srv->tmp_buf->used--;
+- }
+-
+- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+- for (j = 0; j < ds->key->used - 1; j++) {
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
+- light_isalpha(ds->key->ptr[j]) ?
+- ds->key->ptr[j] & ~32 : '_';
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
+ }
+@@ -1445,16 +1429,7 @@ static int scgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+ ds = (data_string *)con->environment->data[i];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+- buffer_reset(srv->tmp_buf);
+-
+- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+- for (j = 0; j < ds->key->used - 1; j++) {
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
+- light_isalnum((unsigned char)ds->key->ptr[j]) ?
+- toupper((unsigned char)ds->key->ptr[j]) : '_';
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
+ }
+@@ -1481,7 +1456,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ sock_addr our_addr;
+ socklen_t our_addr_len;
+
+- buffer_prepare_copy(p->scgi_env, 1024);
++ buffer_string_prepare_copy(p->scgi_env, 1023);
+
+ /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
+
+@@ -1631,9 +1606,9 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+
+ b = buffer_init();
+
+- buffer_append_int(b, p->scgi_env->used);
++ buffer_append_int(b, buffer_string_length(p->scgi_env));
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+- buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
++ buffer_append_string_buffer(b, p->scgi_env);
+ buffer_append_string_len(b, CONST_STR_LEN(","));
+
+ hctx->wb->bytes_in += b->used - 1;
+@@ -1759,7 +1734,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ while(1) {
+ int n;
+
+- buffer_prepare_copy(hctx->response, 1024);
++ buffer_string_prepare_copy(hctx->response, 1023);
+ if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
+ if (errno == EAGAIN || errno == EINTR) {
+ /* would block, wait for signal */
+diff --git a/src/mod_simple_vhost.c b/src/mod_simple_vhost.c
+index 7245fd5..6bb850f 100644
+--- a/src/mod_simple_vhost.c
++++ b/src/mod_simple_vhost.c
+@@ -126,7 +126,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
+ stat_cache_entry *sce = NULL;
+ force_assert(p->conf.server_root->used > 1);
+
+- buffer_prepare_copy(out, 128);
++ buffer_string_prepare_copy(out, 127);
+ buffer_copy_buffer(out, p->conf.server_root);
+
+ if (host->used) {
+diff --git a/src/mod_ssi.c b/src/mod_ssi.c
+index ecdfb99..981fd76 100644
+--- a/src/mod_ssi.c
++++ b/src/mod_ssi.c
+@@ -173,32 +173,12 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
+ ds = (data_string *)con->request.headers->data[i];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+- buffer_reset(srv->tmp_buf);
+-
+ /* don't forward the Authorization: Header */
+ if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
+ continue;
+ }
+
+- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
+- buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
+- srv->tmp_buf->used--;
+- }
+-
+- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+- for (j = 0; j < ds->key->used - 1; j++) {
+- char c = '_';
+- if (light_isalpha(ds->key->ptr[j])) {
+- /* upper-case */
+- c = ds->key->ptr[j] & ~32;
+- } else if (light_isdigit(ds->key->ptr[j])) {
+- /* copy */
+- c = ds->key->ptr[j];
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
+ }
+@@ -210,23 +190,7 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
+ ds = (data_string *)con->environment->data[i];
+
+ if (ds->value->used && ds->key->used) {
+- size_t j;
+-
+- buffer_reset(srv->tmp_buf);
+- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+-
+- for (j = 0; j < ds->key->used - 1; j++) {
+- char c = '_';
+- if (light_isalpha(ds->key->ptr[j])) {
+- /* upper-case */
+- c = ds->key->ptr[j] & ~32;
+- } else if (light_isdigit(ds->key->ptr[j])) {
+- /* copy */
+- c = ds->key->ptr[j];
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
+- }
+- srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
++ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
+ }
+diff --git a/src/network_write.c b/src/network_write.c
+index 930644e..d46649b 100644
+--- a/src/network_write.c
++++ b/src/network_write.c
+@@ -145,7 +145,7 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqu
+
+ munmap(p, sce->st.st_size);
+ #else /* USE_MMAP */
+- buffer_prepare_copy(srv->tmp_buf, toSend);
++ buffer_string_prepare_copy(srv->tmp_buf, toSend);
+
+ if (-1 == lseek(ifd, offset, SEEK_SET)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
+diff --git a/src/proc_open.c b/src/proc_open.c
+index e28b479..c29b9c6 100644
+--- a/src/proc_open.c
++++ b/src/proc_open.c
+@@ -280,13 +280,13 @@ static void proc_read_fd_to_buffer(int fd, buffer *b) {
+ ssize_t s;
+
+ for (;;) {
+- buffer_prepare_append(b, 512);
+- if ((s = read(fd, (void *)(b->ptr + b->used), 512 - 1)) <= 0) {
++ buffer_string_prepare_append(b, 1024);
++ if ((s = read(fd, (void *)(b->ptr + buffer_string_length(b)), buffer_string_space(b))) <= 0) {
+ break;
+ }
+ b->used += s;
++ b->ptr[b->used-1] = '\0';
+ }
+- b->ptr[b->used] = '\0';
+ }
+ /* }}} */
+ /* {{{ proc_open_buffer */
+diff --git a/src/response.c b/src/response.c
+index 31bcd69..5072d05 100644
+--- a/src/response.c
++++ b/src/response.c
+@@ -97,7 +97,7 @@ int http_response_write_header(server *srv, connection *con) {
+
+ /* cache the generated timestamp */
+ if (srv->cur_ts != srv->last_generated_date_ts) {
+- buffer_prepare_copy(srv->ts_date_str, 255);
++ buffer_string_prepare_copy(srv->ts_date_str, 255);
+
+ strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
+ "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
+@@ -201,7 +201,7 @@ static void https_add_ssl_entries(connection *con) {
+ }
+
+ buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
+- buffer_prepare_copy(envds->value, n);
++ buffer_string_prepare_copy(envds->value, n);
+ BIO_read(bio, envds->value->ptr, n);
+ BIO_free(bio);
+ envds->value->ptr[n] = '\0';
+diff --git a/src/stat_cache.c b/src/stat_cache.c
+index b5aa9ce..b63140e 100644
+--- a/src/stat_cache.c
++++ b/src/stat_cache.c
+@@ -219,8 +219,7 @@ static int stat_cache_attr_get(buffer *buf, char *name) {
+ int attrlen;
+ int ret;
+
+- attrlen = 1024;
+- buffer_prepare_copy(buf, attrlen);
++ buffer_string_prepare_copy(buf, 1023);
+ attrlen = buf->size - 1;
+ if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) {
+ buf->used = attrlen + 1;
+@@ -230,9 +229,9 @@ static int stat_cache_attr_get(buffer *buf, char *name) {
+ }
+ #elif defined(HAVE_EXTATTR)
+ static int stat_cache_attr_get(buffer *buf, char *name) {
+- ssize_t attrlen = 1024;
++ ssize_t attrlen;
+
+- buffer_prepare_copy(buf, attrlen);
++ buffer_prepare_copy(buf, 1023);
+
+ if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, "Content-Type", buf->ptr, buf->size - 1))) {
+ buf->used = attrlen + 1;
+--
+2.4.5
+
diff --git a/main/lighttpd/0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch b/main/lighttpd/0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch
new file mode 100644
index 0000000000..e56fa44244
--- /dev/null
+++ b/main/lighttpd/0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch
@@ -0,0 +1,79 @@
+From adfa06de996944b495b878540464dd6e74563052 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:41 +0000
+Subject: [PATCH 18/29] [tests] improve valgrind and strace TRACEME, disable
+ condition logging in normal configs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+- condition logging is way too noisy and rarely useful
+- increate timeout to wait for port bind; if the process dies we fail
+ early anyway
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2978 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ tests/LightyTest.pm | 6 +++---
+ tests/lighttpd.conf | 2 +-
+ tests/var-include.conf | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm
+index b92af87..36029dc 100755
+--- a/tests/LightyTest.pm
++++ b/tests/LightyTest.pm
+@@ -87,7 +87,7 @@ sub wait_for_port_with_proc {
+ my $self = shift;
+ my $port = shift;
+ my $child = shift;
+- my $timeout = 5*10; # 5 secs, select waits 0.1 s
++ my $timeout = 10*10; # 10 secs (valgrind might take a while), select waits 0.1 s
+
+ while (0 == $self->listening_on($port)) {
+ select(undef, undef, undef, 0.1);
+@@ -125,13 +125,13 @@ sub start_proc {
+
+ my @cmdline = ($self->{LIGHTTPD_PATH}, "-D", "-f", $self->{SRCDIR}."/".$self->{CONFIGFILE}, "-m", $self->{MODULES_PATH});
+ if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
+- @cmdline = (qw(strace -tt -s 512 -o strace), @cmdline);
++ @cmdline = (qw(strace -tt -s 4096 -o strace -f -v), @cmdline);
+ } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'truss') {
+ @cmdline = (qw(truss -a -l -w all -v all -o strace), @cmdline);
+ } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'gdb') {
+ @cmdline = ('gdb', '--batch', '--ex', 'run', '--ex', 'bt full', '--args', @cmdline);
+ } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
+- @cmdline = (qw(valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind), @cmdline);
++ @cmdline = (qw(valgrind --tool=memcheck --track-origins=yes --show-reachable=yes --leak-check=yes --log-file=valgrind.%p), @cmdline);
+ }
+ # diag("\nstarting lighttpd at :".$self->{PORT}.", cmdline: ".@cmdline );
+ my $child = fork();
+diff --git a/tests/lighttpd.conf b/tests/lighttpd.conf
+index a4b5cd8..a140002 100644
+--- a/tests/lighttpd.conf
++++ b/tests/lighttpd.conf
+@@ -1,7 +1,7 @@
+ debug.log-request-handling = "enable"
+ debug.log-request-header = "enable"
+ debug.log-response-header = "enable"
+-debug.log-condition-handling = "enable"
++#debug.log-condition-handling = "enable"
+ server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
+
+ ## 64 Mbyte ... nice limit
+diff --git a/tests/var-include.conf b/tests/var-include.conf
+index 04b8271..6a107c5 100644
+--- a/tests/var-include.conf
++++ b/tests/var-include.conf
+@@ -1,6 +1,6 @@
+
+ debug.log-request-handling = "enable"
+-debug.log-condition-handling = "enable"
++#debug.log-condition-handling = "enable"
+
+ server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
+
+--
+2.4.5
+
diff --git a/main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch b/main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch
new file mode 100644
index 0000000000..d455ff9a67
--- /dev/null
+++ b/main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch
@@ -0,0 +1,4346 @@
+From ad3e93ea96d1cbaab00d07245dbd02f790060f85 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:44 +0000
+Subject: [PATCH 19/29] Use buffer API to read and modify "used" member
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+- a lot of code tried to handle manually adding terminating zeroes and
+ keeping track of the correct "used" count.
+ Replaced all "external" usages with simple wrapper functions:
+ * buffer_string_is_empty (used <= 1), buffer_is_empty (used == 0);
+ prefer buffer_string_is_empty
+ * buffer_string_set_length
+ * buffer_string_length
+ * CONST_BUF_LEN() macro
+- removed "static" buffer hacks (buffers pointing to constant/stack
+ memory instead of malloc()ed data)
+- buffer_append_strftime(): refactor buffer+strftime uses
+- li_tohex(): no need for a buffer for binary-to-hex conversion:
+ the output data length is easy to predict
+- remove "-Winline" from extra warnings: the "inline" keyword just
+ supresses the warning about unused but defined (static) functions;
+ don't care whether it actually gets inlined or not.
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2979 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ configure.ac | 2 +-
+ src/CMakeLists.txt | 2 +-
+ src/array.c | 12 +--
+ src/buffer.c | 128 ++++++++++++++++++++-----------
+ src/buffer.h | 13 ++++
+ src/chunk.c | 11 +--
+ src/configfile-glue.c | 2 +-
+ src/configfile.c | 4 +-
+ src/connections.c | 79 ++++---------------
+ src/data_string.c | 11 +--
+ src/etag.c | 5 +-
+ src/http-header-glue.c | 7 +-
+ src/http_auth.c | 71 ++++++++---------
+ src/http_chunk.c | 5 +-
+ src/log.c | 19 ++---
+ src/mod_access.c | 8 +-
+ src/mod_accesslog.c | 64 ++++++++--------
+ src/mod_alias.c | 14 ++--
+ src/mod_auth.c | 20 ++---
+ src/mod_cgi.c | 47 ++++++------
+ src/mod_cml.c | 12 ++-
+ src/mod_cml_funcs.c | 9 +--
+ src/mod_cml_lua.c | 22 ++----
+ src/mod_compress.c | 34 ++++-----
+ src/mod_dirlisting.c | 22 +++---
+ src/mod_evasive.c | 2 +-
+ src/mod_evhost.c | 11 +--
+ src/mod_expire.c | 21 ++---
+ src/mod_extforward.c | 2 +-
+ src/mod_fastcgi.c | 99 ++++++++++++------------
+ src/mod_flv_streaming.c | 13 ++--
+ src/mod_indexfile.c | 4 +-
+ src/mod_magnet.c | 43 +++++------
+ src/mod_mysql_vhost.c | 51 ++++---------
+ src/mod_proxy.c | 47 +++++-------
+ src/mod_redirect.c | 4 +-
+ src/mod_rewrite.c | 4 +-
+ src/mod_rrdtool.c | 12 ++-
+ src/mod_scgi.c | 61 +++++++--------
+ src/mod_secure_download.c | 9 +--
+ src/mod_simple_vhost.c | 16 ++--
+ src/mod_ssi.c | 16 ++--
+ src/mod_ssi_expr.c | 2 +-
+ src/mod_staticfile.c | 14 ++--
+ src/mod_status.c | 4 +-
+ src/mod_trigger_b4_dl.c | 16 ++--
+ src/mod_userdir.c | 4 +-
+ src/mod_usertrack.c | 16 ++--
+ src/mod_webdav.c | 177 ++++++++++++++++++++-----------------------
+ src/network_linux_sendfile.c | 4 +-
+ src/network_openssl.c | 6 +-
+ src/network_write.c | 6 +-
+ src/network_writev.c | 4 +-
+ src/proc_open.c | 7 +-
+ src/request.c | 49 ++++++------
+ src/response.c | 53 +++++--------
+ src/server.c | 23 +++---
+ src/stat_cache.c | 23 +++---
+ 58 files changed, 668 insertions(+), 778 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 63261ca..c846d1a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -666,7 +666,7 @@ AC_ARG_ENABLE(extra-warnings,
+ esac],[extrawarnings=false])
+
+ if test x$extrawarnings = xtrue; then
+- TRY_CFLAGS([-g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security])
++ TRY_CFLAGS([-g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security])
+ fi
+
+ dnl build version-id
+diff --git a/src/array.c b/src/array.c
+index 9a15abd..50f5e03 100644
+--- a/src/array.c
++++ b/src/array.c
+@@ -98,7 +98,7 @@ static int array_get_index(array *a, const char *key, size_t keylen, int *rndx)
+ } else if (pos >= (int)a->used) {
+ pos -= i;
+ } else {
+- cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
++ cmp = buffer_caseless_compare(key, keylen, CONST_BUF_LEN(a->data[a->sorted[pos]]->key));
+
+ if (cmp == 0) {
+ /* found */
+@@ -121,7 +121,7 @@ static int array_get_index(array *a, const char *key, size_t keylen, int *rndx)
+ data_unset *array_get_element(array *a, const char *key) {
+ int ndx;
+
+- if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
++ if (-1 != (ndx = array_get_index(a, key, strlen(key), NULL))) {
+ /* found, leave here */
+
+ return a->data[ndx];
+@@ -171,7 +171,7 @@ data_unset *array_replace(array *a, data_unset *du) {
+ int ndx;
+
+ force_assert(NULL != du);
+- if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
++ if (-1 == (ndx = array_get_index(a, CONST_BUF_LEN(du->key), NULL))) {
+ array_insert_unique(a, du);
+ return NULL;
+ } else {
+@@ -187,13 +187,13 @@ int array_insert_unique(array *a, data_unset *str) {
+ size_t j;
+
+ /* generate unique index if neccesary */
+- if (str->key->used == 0 || str->is_index_key) {
++ if (buffer_is_empty(str->key) || str->is_index_key) {
+ buffer_copy_int(str->key, a->unique_ndx++);
+ str->is_index_key = 1;
+ }
+
+ /* try to find the string */
+- if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
++ if (-1 != (ndx = array_get_index(a, CONST_BUF_LEN(str->key), &pos))) {
+ /* found, leave here */
+ if (a->data[ndx]->type == str->type) {
+ str->insert_dup(a->data[ndx], str);
+@@ -235,7 +235,7 @@ int array_insert_unique(array *a, data_unset *str) {
+
+ if (pos != ndx &&
+ ((pos < 0) ||
+- buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
++ buffer_caseless_compare(CONST_BUF_LEN(str->key), CONST_BUF_LEN(a->data[a->sorted[pos]]->key)) > 0)) {
+ pos++;
+ }
+
+diff --git a/src/buffer.c b/src/buffer.c
+index 979d954..d343731 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -9,7 +9,6 @@
+
+ static const char hex_chars[] = "0123456789abcdef";
+
+-
+ /**
+ * init the buffer
+ *
+@@ -83,37 +82,44 @@ static size_t buffer_align_size(size_t size) {
+ return size + align;
+ }
+
+-static char* buffer_prepare_copy(buffer *b, size_t size) {
++/* make sure buffer is at least "size" big. discard old data */
++static void buffer_alloc(buffer *b, size_t size) {
+ force_assert(NULL != b);
++ if (0 == size) size = 1;
+
+- /* also allocate space for terminating 0 */
+- /* check for overflow: unsigned overflow is defined to wrap around */
+- force_assert(1 + size > size);
+- ++size;
++ if (size <= b->size) return;
+
+- if (0 == b->size || size > b->size) {
+- if (NULL != b->ptr) free(b->ptr);
+- b->ptr = NULL;
++ if (NULL != b->ptr) free(b->ptr);
+
+- b->size = buffer_align_size(size);
+- force_assert(b->size > 0);
++ b->used = 0;
++ b->size = buffer_align_size(size);
++ b->ptr = malloc(b->size);
+
+- b->ptr = malloc(b->size);
+- force_assert(NULL != b->ptr);
+- }
++ force_assert(NULL != b->ptr);
++}
+
+- /* reset */
+- b->used = 0;
+- b->ptr[0] = '\0';
++/* make sure buffer is at least "size" big. keep old data */
++static void buffer_realloc(buffer *b, size_t size) {
++ force_assert(NULL != b);
++ if (0 == size) size = 1;
+
+- return b->ptr;
++ if (size <= b->size) return;
++
++ b->size = buffer_align_size(size);
++ b->ptr = realloc(b->ptr, b->size);
++
++ force_assert(NULL != b->ptr);
+ }
+
++
+ char* buffer_string_prepare_copy(buffer *b, size_t size) {
+ force_assert(NULL != b);
++ force_assert(size + 1 > size);
++
++ buffer_alloc(b, size + 1);
+
+- buffer_prepare_copy(b, size);
+ b->used = 1;
++ b->ptr[0] = '\0';
+
+ return b->ptr;
+ }
+@@ -124,28 +130,29 @@ char* buffer_string_prepare_append(buffer *b, size_t size) {
+ if (buffer_string_is_empty(b)) {
+ return buffer_string_prepare_copy(b, size);
+ } else {
+- /* not empty, b->used already includes a terminating 0 */
+ size_t req_size = b->used + size;
+
+- /* check for overflow: unsigned overflow is defined to wrap around */
++ /* not empty, b->used already includes a terminating 0 */
+ force_assert(req_size >= b->used);
+
+- /* only append to 0-terminated string */
+- force_assert('\0' == b->ptr[b->used - 1]);
+-
+- if (req_size > b->size) {
+- char *ptr;
+- b->size = buffer_align_size(req_size);
++ /* check for overflow: unsigned overflow is defined to wrap around */
++ force_assert(req_size >= b->used);
+
+- ptr = realloc(b->ptr, b->size);
+- force_assert(NULL != ptr);
+- b->ptr = ptr;
+- }
++ buffer_realloc(b, req_size);
+
+ return b->ptr + b->used - 1;
+ }
+ }
+
++void buffer_string_set_length(buffer *b, size_t len) {
++ force_assert(NULL != b);
++ force_assert(len + 1 > len);
++
++ buffer_realloc(b, len + 1);
++
++ b->used = len + 1;
++ b->ptr[len] = '\0';
++}
+
+ void buffer_commit(buffer *b, size_t size)
+ {
+@@ -182,7 +189,8 @@ void buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
+
+ void buffer_copy_buffer(buffer *b, const buffer *src) {
+ if (NULL == src || 0 == src->used) {
+- buffer_prepare_copy(b, 0);
++ buffer_string_prepare_copy(b, 0);
++ b->used = 0; /* keep special empty state for now */
+ } else {
+ buffer_copy_string_len(b, src->ptr, buffer_string_length(src));
+ }
+@@ -301,6 +309,37 @@ void buffer_copy_int(buffer *b, intmax_t val) {
+ buffer_append_int(b, val);
+ }
+
++void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm) {
++ size_t r;
++ char* buf;
++ force_assert(NULL != b);
++ force_assert(NULL != tm);
++
++ if (NULL == format || '\0' == format[0]) {
++ /* empty format */
++ buffer_string_prepare_append(b, 0);
++ return;
++ }
++
++ buf = buffer_string_prepare_append(b, 255);
++ r = strftime(buf, buffer_string_space(b), format, tm);
++
++ /* 0 (in some apis buffer_string_space(b)) signals the string may have
++ * been too small; but the format could also just have lead to an empty
++ * string
++ */
++ if (0 == r || r >= buffer_string_space(b)) {
++ /* give it a second try with a larger string */
++ buf = buffer_string_prepare_append(b, 4095);
++ r = strftime(buf, buffer_string_space(b), format, tm);
++ }
++
++ if (r >= buffer_string_space(b)) r = 0;
++
++ buffer_commit(b, r);
++}
++
++
+ void li_itostrn(char *buf, size_t buf_len, intmax_t val) {
+ char p_buf[LI_ITOSTRING_LENGTH];
+ char* const p_buf_end = p_buf + sizeof(p_buf);
+@@ -446,20 +485,22 @@ int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
+ return 0 == memcmp(b1->ptr + b1->used - 1 - len, b2->ptr + b2->used - 1 - len, len);
+ }
+
+-void buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
++void li_tohex(char *buf, const char *s, size_t s_len) {
+ size_t i;
+
+- /* overflow protection */
+- force_assert(in_len * 2 + 1 > in_len);
++ for (i = 0; i < s_len; i++) {
++ buf[2*i] = hex_chars[(s[i] >> 4) & 0x0F];
++ buf[2*i+1] = hex_chars[s[i] & 0x0F];
++ }
++ buf[2*s_len] = '\0';
++}
+
+- buffer_prepare_copy(b, in_len * 2);
++void buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
++ /* overflow protection */
++ force_assert(in_len * 2 > in_len);
+
+- b->used = 0;
+- for (i = 0; i < in_len; i++) {
+- b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
+- b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
+- }
+- b->ptr[b->used++] = '\0';
++ buffer_string_set_length(b, 2 * in_len);
++ li_tohex(b->ptr, in, in_len);
+ }
+
+ /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
+@@ -882,8 +923,7 @@ void buffer_path_simplify(buffer *dest, buffer *src)
+ walk++;
+ }
+
+- *out = '\0';
+- dest->used = (out - start) + 1;
++ buffer_string_set_length(dest, out - start);
+ }
+
+ int light_isdigit(int c) {
+diff --git a/src/buffer.h b/src/buffer.h
+index 7ea27f1..e2ac778 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -10,6 +10,7 @@
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <stdio.h>
++#include <time.h>
+
+ #if defined HAVE_STDINT_H
+ # include <stdint.h>
+@@ -71,6 +72,13 @@ char* buffer_string_prepare_append(buffer *b, size_t size);
+ */
+ void buffer_commit(buffer *b, size_t size);
+
++/* sets string length:
++ * - always stores a terminating zero to terminate the "new" string
++ * - does not modify the string data apart from terminating zero
++ * - reallocates the buffer iff needed
++ */
++void buffer_string_set_length(buffer *b, size_t len);
++
+ void buffer_copy_string(buffer *b, const char *s);
+ void buffer_copy_string_len(buffer *b, const char *s, size_t s_len);
+ void buffer_copy_buffer(buffer *b, const buffer *src);
+@@ -85,6 +93,8 @@ void buffer_append_long_hex(buffer *b, unsigned long len);
+ void buffer_append_int(buffer *b, intmax_t val);
+ void buffer_copy_int(buffer *b, intmax_t val);
+
++void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm);
++
+ /* '-', log_10 (2^bits) = bits * log 2 / log 10 < bits * 0.31, terminating 0 */
+ #define LI_ITOSTRING_LENGTH (2 + (8 * sizeof(intmax_t) * 31 + 99) / 100)
+
+@@ -93,6 +103,9 @@ void li_itostr(char *buf, intmax_t val); /* buf must have at least LI_ITOSTRING_
+ void li_utostrn(char *buf, size_t buf_len, uintmax_t val);
+ void li_utostr(char *buf, uintmax_t val); /* buf must have at least LI_ITOSTRING_LENGTH bytes */
+
++/* buf must be (at least) 2*s_len + 1 big. uses lower-case hex letters. */
++void li_tohex(char *buf, const char *s, size_t s_len);
++
+ char * buffer_search_string_len(buffer *b, const char *needle, size_t len);
+
+ /* NULL buffer or empty buffer (used == 0);
+diff --git a/src/chunk.c b/src/chunk.c
+index 83adc15..ccdae9a 100644
+--- a/src/chunk.c
++++ b/src/chunk.c
+@@ -264,10 +264,11 @@ void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_s
+ }
+ /* if buffer is really small just make it bigger */
+ else if (have < min_size && b->size <= REALLOC_MAX_SIZE) {
+- size_t new_size = b->used + min_size, append;
++ size_t cur_len = buffer_string_length(b);
++ size_t new_size = cur_len + min_size, append;
+ if (new_size < alloc_size) new_size = alloc_size;
+
+- append = new_size - b->used;
++ append = new_size - cur_len;
+ if (append >= min_size) {
+ buffer_string_prepare_append(b, append);
+ have = buffer_string_space(b);
+@@ -301,12 +302,8 @@ void chunkqueue_use_memory(chunkqueue *cq, size_t len) {
+ force_assert(NULL != cq->last && MEM_CHUNK == cq->last->type);
+ b = cq->last->mem;
+
+- force_assert(b->used > 0);
+- force_assert(len <= buffer_string_space(b));
+-
+ if (len > 0) {
+- b->used += len;
+- b->ptr[b->used - 1] = '\0';
++ buffer_commit(b, len);
+ } else if (buffer_string_is_empty(b)) {
+ /* unused buffer: can't remove chunk easily from
+ * end of list, so just reset the buffer
+diff --git a/src/configfile-glue.c b/src/configfile-glue.c
+index 2fb8c62..f411d72 100644
+--- a/src/configfile-glue.c
++++ b/src/configfile-glue.c
+@@ -491,7 +491,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
+ #ifndef elementsof
+ #define elementsof(x) (sizeof(x) / sizeof(x[0]))
+ #endif
+- n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
++ n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0,
+ cache->matches, elementsof(cache->matches));
+
+ cache->patterncount = n;
+diff --git a/src/configfile.c b/src/configfile.c
+index 1c36c3e..929d292 100644
+--- a/src/configfile.c
++++ b/src/configfile.c
+@@ -1130,7 +1130,7 @@ int config_read(server *srv, const char *fn) {
+ dcwd = data_string_init();
+ buffer_string_prepare_copy(dcwd->value, 1023);
+ if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
+- dcwd->value->used = strlen(dcwd->value->ptr) + 1;
++ buffer_commit(dcwd->value, strlen(dcwd->value->ptr));
+ buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
+ array_insert_unique(srv->config, (data_unset *)dcwd);
+ } else {
+@@ -1320,7 +1320,7 @@ int config_set_defaults(server *srv) {
+ srv->srvconf.port = s->ssl_enabled ? 443 : 80;
+ }
+
+- if (srv->srvconf.event_handler->used == 0) {
++ if (buffer_string_is_empty(srv->srvconf.event_handler)) {
+ /* choose a good default
+ *
+ * the event_handler list is sorted by 'goodness'
+diff --git a/src/connections.c b/src/connections.c
+index 3fab768..8f26a30 100644
+--- a/src/connections.c
++++ b/src/connections.c
+@@ -400,7 +400,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
+ * 403 is from the response handler when noone else catched it
+ *
+ * */
+- if ((!con->http_status || con->http_status == 200) && con->uri.path->used &&
++ if ((!con->http_status || con->http_status == 200) && !buffer_string_is_empty(con->uri.path) &&
+ con->uri.path->ptr[0] != '*') {
+ response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
+
+@@ -873,42 +873,7 @@ static int connection_handle_read_state(server *srv, connection *con) {
+ }
+ }
+
+- /* the last chunk might be empty */
+- for (c = cq->first; c;) {
+- if (cq->first == c && c->mem->used == 0) {
+- /* the first node is empty */
+- /* ... and it is empty, move it to unused */
+-
+- cq->first = c->next;
+- if (cq->first == NULL) cq->last = NULL;
+-
+- c->next = cq->unused;
+- cq->unused = c;
+- cq->unused_chunks++;
+-
+- c = cq->first;
+- } else if (c->next && c->next->mem->used == 0) {
+- chunk *fc;
+- /* next node is the last one */
+- /* ... and it is empty, move it to unused */
+-
+- fc = c->next;
+- c->next = fc->next;
+-
+- fc->next = cq->unused;
+- cq->unused = fc;
+- cq->unused_chunks++;
+-
+- /* the last node was empty */
+- if (c->next == NULL) {
+- cq->last = c;
+- }
+-
+- c = c->next;
+- } else {
+- c = c->next;
+- }
+- }
++ chunkqueue_remove_finished_chunks(cq);
+
+ /* we might have got several packets at once
+ */
+@@ -927,15 +892,12 @@ static int connection_handle_read_state(server *srv, connection *con) {
+ last_offset = 0;
+
+ for (c = cq->first; c; c = c->next) {
+- buffer b;
+ size_t i;
++ size_t len = buffer_string_length(c->mem) - c->offset;
++ const char *b = c->mem->ptr + c->offset;
+
+- b.ptr = c->mem->ptr + c->offset;
+- b.used = c->mem->used - c->offset;
+- if (b.used > 0) b.used--; /* buffer "used" includes terminating zero */
+-
+- for (i = 0; i < b.used; i++) {
+- char ch = b.ptr[i];
++ for (i = 0; i < len; ++i) {
++ char ch = b[i];
+
+ if ('\r' == ch) {
+ /* chec if \n\r\n follows */
+@@ -945,13 +907,11 @@ static int connection_handle_read_state(server *srv, connection *con) {
+ int header_end_match_pos = 1;
+
+ for ( ; cc; cc = cc->next, j = 0 ) {
+- buffer bb;
+- bb.ptr = cc->mem->ptr + cc->offset;
+- bb.used = cc->mem->used - cc->offset;
+- if (bb.used > 0) bb.used--; /* buffer "used" includes terminating zero */
++ size_t bblen = buffer_string_length(cc->mem) - cc->offset;
++ const char *bb = c->mem->ptr + cc->offset;
+
+- for ( ; j < bb.used; j++) {
+- ch = bb.ptr[j];
++ for ( ; j < bblen; j++) {
++ ch = bb[j];
+
+ if (ch == header_end[header_end_match_pos]) {
+ header_end_match_pos++;
+@@ -976,25 +936,16 @@ found_header_end:
+ buffer_reset(con->request.request);
+
+ for (c = cq->first; c; c = c->next) {
+- buffer b;
+-
+- b.ptr = c->mem->ptr + c->offset;
+- b.used = c->mem->used - c->offset;
++ size_t len = buffer_string_length(c->mem) - c->offset;
+
+ if (c == last_chunk) {
+- b.used = last_offset + 1;
++ len = last_offset;
+ }
+
+- buffer_append_string_buffer(con->request.request, &b);
++ buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, len);
++ c->offset += len;
+
+- if (c == last_chunk) {
+- c->offset += last_offset;
+-
+- break;
+- } else {
+- /* the whole packet was copied */
+- c->offset = c->mem->used - 1;
+- }
++ if (c == last_chunk) break;
+ }
+
+ connection_set_state(srv, con, CON_STATE_REQUEST_END);
+diff --git a/src/data_string.c b/src/data_string.c
+index fc57de2..d65b3be 100644
+--- a/src/data_string.c
++++ b/src/data_string.c
+@@ -36,7 +36,7 @@ static int data_string_insert_dup(data_unset *dst, data_unset *src) {
+ data_string *ds_dst = (data_string *)dst;
+ data_string *ds_src = (data_string *)src;
+
+- if (ds_dst->value->used) {
++ if (!buffer_is_empty(ds_dst->value)) {
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(", "));
+ buffer_append_string_buffer(ds_dst->value, ds_src->value);
+ } else {
+@@ -52,7 +52,7 @@ static int data_response_insert_dup(data_unset *dst, data_unset *src) {
+ data_string *ds_dst = (data_string *)dst;
+ data_string *ds_src = (data_string *)src;
+
+- if (ds_dst->value->used) {
++ if (!buffer_is_empty(ds_dst->value)) {
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN("\r\n"));
+ buffer_append_string_buffer(ds_dst->value, ds_dst->key);
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(": "));
+@@ -69,18 +69,19 @@ static int data_response_insert_dup(data_unset *dst, data_unset *src) {
+
+ static void data_string_print(const data_unset *d, int depth) {
+ data_string *ds = (data_string *)d;
+- unsigned int i;
++ size_t i, len;
+ UNUSED(depth);
+
+ /* empty and uninitialized strings */
+- if (ds->value->used < 1) {
++ if (buffer_string_is_empty(ds->value)) {
+ fputs("\"\"", stdout);
+ return;
+ }
+
+ /* print out the string as is, except prepend " with backslash */
+ putc('"', stdout);
+- for (i = 0; i < ds->value->used - 1; i++) {
++ len = buffer_string_length(ds->value);
++ for (i = 0; i < len; i++) {
+ unsigned char c = ds->value->ptr[i];
+ if (c == '"') {
+ fputs("\\\"", stdout);
+diff --git a/src/etag.c b/src/etag.c
+index bf63d94..f8fb609 100644
+--- a/src/etag.c
++++ b/src/etag.c
+@@ -37,10 +37,11 @@ int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
+ }
+
+ int etag_mutate(buffer *mut, buffer *etag) {
+- size_t i;
++ size_t i, len;
+ uint32_t h;
+
+- for (h=0, i=0; i < etag->used-1; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
++ len = buffer_string_length(etag);
++ for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
+
+ buffer_reset(mut);
+ buffer_copy_string_len(mut, CONST_STR_LEN("\""));
+diff --git a/src/http-header-glue.c b/src/http-header-glue.c
+index f910f3f..752d91e 100644
+--- a/src/http-header-glue.c
++++ b/src/http-header-glue.c
+@@ -125,7 +125,7 @@ int http_response_redirect_to_directory(server *srv, connection *con) {
+
+ buffer_copy_buffer(o, con->uri.scheme);
+ buffer_append_string_len(o, CONST_STR_LEN("://"));
+- if (con->uri.authority->used) {
++ if (!buffer_is_empty(con->uri.authority)) {
+ buffer_append_string_buffer(o, con->uri.authority);
+ } else {
+ /* get the name of the currently connected socket */
+@@ -237,10 +237,7 @@ buffer * strftime_cache_get(server *srv, time_t last_mod) {
+ srv->mtime_cache[i].mtime = last_mod;
+ buffer_string_prepare_copy(srv->mtime_cache[i].str, 1023);
+ tm = gmtime(&(srv->mtime_cache[i].mtime));
+- srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
+- srv->mtime_cache[i].str->size - 1,
+- "%a, %d %b %Y %H:%M:%S GMT", tm);
+- srv->mtime_cache[i].str->used++;
++ buffer_append_strftime(srv->mtime_cache[i].str, "%a, %d %b %Y %H:%M:%S GMT", tm);
+
+ return srv->mtime_cache[i].str;
+ }
+diff --git a/src/http_auth.c b/src/http_auth.c
+index c693645..a98ea62 100644
+--- a/src/http_auth.c
++++ b/src/http_auth.c
+@@ -39,13 +39,7 @@ typedef unsigned char HASH[HASHLEN];
+ typedef char HASHHEX[HASHHEXLEN+1];
+
+ 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';
++ li_tohex(Hex, (const char*) Bin, 16);
+ }
+
+ /**
+@@ -97,9 +91,7 @@ static unsigned char * base64_decode(buffer *out, const char *in) {
+
+ size_t in_len = strlen(in);
+
+- buffer_string_prepare_copy(out, in_len);
+-
+- result = (unsigned char *)out->ptr;
++ result = (unsigned char *) buffer_string_prepare_copy(out, in_len);
+
+ /* run through the whole string, converting as we go */
+ for (i = 0; i < in_len; i++) {
+@@ -157,8 +149,7 @@ static unsigned char * base64_decode(buffer *out, const char *in) {
+ break;
+ }
+
+- result[j] = '\0';
+- out->used = j;
++ buffer_commit(out, j);
+
+ return result;
+ }
+@@ -166,7 +157,7 @@ static unsigned char * base64_decode(buffer *out, const char *in) {
+ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
+ int ret = -1;
+
+- if (!username->used|| !realm->used) return -1;
++ if (buffer_is_empty(username) || buffer_is_empty(realm)) return -1;
+
+ if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
+ stream f;
+@@ -226,8 +217,8 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *
+ pwd_len = f.size - (f_pwd - f.start);
+ }
+
+- if (username->used - 1 == u_len &&
+- (realm->used - 1 == r_len) &&
++ if (buffer_string_length(username) == u_len &&
++ (buffer_string_length(realm) == r_len) &&
+ (0 == strncmp(username->ptr, f_user, u_len)) &&
+ (0 == strncmp(realm->ptr, f_realm, r_len))) {
+ /* found */
+@@ -296,7 +287,7 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *
+ pwd_len = f.size - (f_pwd - f.start);
+ }
+
+- if (username->used - 1 == u_len &&
++ if (buffer_string_length(username) == u_len &&
+ (0 == strncmp(username->ptr, f_user, u_len))) {
+ /* found */
+
+@@ -652,10 +643,10 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
+ char a1[256];
+
+ 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, CONST_BUF_LEN(username));
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
++ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(realm));
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
+ li_MD5_Final(HA1, &Md5Ctx);
+
+@@ -682,7 +673,7 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
+ char *crypted;
+
+ /* a simple DES password is 2 + 11 characters. everything else should be longer. */
+- if (password->used < 13 + 1) {
++ if (buffer_string_length(password) < 13) {
+ return -1;
+ }
+
+@@ -707,7 +698,7 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
+ char *dn;
+ int ret;
+ char *attrs[] = { LDAP_NO_ATTRS, NULL };
+- size_t i;
++ size_t i, len;
+
+ /* for now we stay synchronous */
+
+@@ -726,7 +717,8 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
+ * a unpleasant way
+ */
+
+- for (i = 0; i < username->used - 1; i++) {
++ len = buffer_string_length(username);
++ for (i = 0; i < len; i++) {
+ char c = username->ptr[i];
+
+ if (!isalpha(c) &&
+@@ -863,9 +855,8 @@ int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p,
+ return 0;
+ }
+
+- *pw++ = '\0';
+-
+- username->used = pw - username->ptr;
++ buffer_string_set_length(username, pw - username->ptr);
++ pw++;
+
+ password = buffer_init();
+ /* copy password to r1 */
+@@ -1084,10 +1075,10 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
+ /* generate password from plain-text */
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ 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_Update(&Md5Ctx, CONST_STR_LEN(":"));
++ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(password));
+ li_MD5_Final(HA1, &Md5Ctx);
+ } else if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
+ /* HA1 */
+@@ -1109,9 +1100,9 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
+ /* Errata ID 1649: http://www.rfc-editor.org/errata_search.php?rfc=2617 */
+ CvtHex(HA1, a1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, 32);
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
+ li_MD5_Final(HA1, &Md5Ctx);
+ }
+@@ -1121,12 +1112,12 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
+ /* calculate H(A2) */
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
+ /* qop=auth-int not supported, already checked above */
+ /*
+ if (qop && strcasecmp(qop, "auth-int") == 0) {
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *) [body checksum], HASHHEXLEN);
+ }
+ */
+@@ -1136,16 +1127,16 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
+ /* calculate response */
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ if (qop && *qop) {
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
+- li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ };
+ li_MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
+ li_MD5_Final(RespHash, &Md5Ctx);
+@@ -1198,8 +1189,8 @@ int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer
+
+ /* generate shared-secret */
+ li_MD5_Init(&Md5Ctx);
+- li_MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
+- li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
++ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(fn));
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN("+"));
+
+ /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
+ li_itostr(hh, srv->cur_ts);
+diff --git a/src/http_chunk.c b/src/http_chunk.c
+index dd6a043..79e4586 100644
+--- a/src/http_chunk.c
++++ b/src/http_chunk.c
+@@ -42,8 +42,7 @@ static void http_chunk_append_len(server *srv, connection *con, size_t len) {
+ b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
+ len >>= 4;
+ }
+- b->used = i;
+- b->ptr[b->used++] = '\0';
++ buffer_commit(b, i);
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ }
+@@ -82,7 +81,7 @@ void http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
+ cq = con->write_queue;
+
+ if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
+- http_chunk_append_len(srv, con, mem->used - 1);
++ http_chunk_append_len(srv, con, buffer_string_length(mem));
+ }
+
+ chunkqueue_append_buffer(cq, mem);
+diff --git a/src/log.c b/src/log.c
+index 097e59e..6c9c38d 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -333,8 +333,7 @@ static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsi
+ /* cache the generated timestamp */
+ if (srv->cur_ts != srv->last_generated_debug_ts) {
+ buffer_string_prepare_copy(srv->ts_debug_str, 255);
+- strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
+- srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
++ buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
+
+ srv->last_generated_debug_ts = srv->cur_ts;
+ }
+@@ -362,8 +361,7 @@ static void log_write(server *srv, buffer *b) {
+ case ERRORLOG_FILE:
+ case ERRORLOG_FD:
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+- force_assert(b->used > 0);
+- write(srv->errorlog_fd, b->ptr, b->used - 1);
++ write(srv->errorlog_fd, CONST_BUF_LEN(b));
+ break;
+ case ERRORLOG_SYSLOG:
+ syslog(LOG_ERR, "%s", b->ptr);
+@@ -387,11 +385,11 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const
+
+ int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
+ va_list ap;
+- size_t prefix_used;
++ size_t prefix_len;
+ buffer *b = srv->errorlog_buf;
+ char *pos, *end, *current_line;
+
+- if (multiline->used < 2) return 0;
++ if (buffer_string_is_empty(multiline)) return 0;
+
+ if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
+
+@@ -399,20 +397,19 @@ int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned
+ log_buffer_append_printf(b, fmt, ap);
+ va_end(ap);
+
+- prefix_used = b->used;
++ prefix_len = buffer_string_length(b);
+
+ current_line = pos = multiline->ptr;
+- end = multiline->ptr + multiline->used;
++ end = multiline->ptr + buffer_string_length(multiline);
+
+- for ( ; pos < end ; ++pos) {
++ for ( ; pos <= end ; ++pos) {
+ switch (*pos) {
+ case '\n':
+ case '\r':
+ case '\0': /* handles end of string */
+ if (current_line < pos) {
+ /* truncate to prefix */
+- b->used = prefix_used;
+- b->ptr[b->used - 1] = '\0';
++ buffer_string_set_length(b, prefix_len);
+
+ buffer_append_string_len(b, current_line, pos - current_line);
+ log_write(srv, b);
+diff --git a/src/mod_access.c b/src/mod_access.c
+index 7b88e19..a6c25a4 100644
+--- a/src/mod_access.c
++++ b/src/mod_access.c
+@@ -125,11 +125,11 @@ URIHANDLER_FUNC(mod_access_uri_handler) {
+ int s_len;
+ size_t k;
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_access_patch_connection(srv, con, p);
+
+- s_len = con->uri.path->used - 1;
++ s_len = buffer_string_length(con->uri.path);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+@@ -138,12 +138,12 @@ URIHANDLER_FUNC(mod_access_uri_handler) {
+
+ for (k = 0; k < p->conf.access_deny->used; k++) {
+ data_string *ds = (data_string *)p->conf.access_deny->data[k];
+- int ct_len = ds->value->used - 1;
++ int ct_len = buffer_string_length(ds->value);
+ int denied = 0;
+
+
+ if (ct_len > s_len) continue;
+- if (ds->value->used == 0) continue;
++ if (buffer_is_empty(ds->value)) continue;
+
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+
+diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
+index 20d52b9..9bb3fe2 100644
+--- a/src/mod_accesslog.c
++++ b/src/mod_accesslog.c
+@@ -223,9 +223,9 @@ static void accesslog_append_escaped(buffer *dest, buffer *str) {
+ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
+ size_t i, j, k = 0, start = 0;
+
+- if (format->used == 0) return -1;
++ if (buffer_is_empty(format)) return -1;
+
+- for (i = 0; i < format->used - 1; i++) {
++ for (i = 0; i < buffer_string_length(format); i++) {
+ switch(format->ptr[i]) {
+ case '%':
+ if (i > 0 && start != i) {
+@@ -297,11 +297,11 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
+ case '{':
+ /* go forward to } */
+
+- for (k = i+2; k < format->used - 1; k++) {
++ for (k = i+2; k < buffer_string_length(format); k++) {
+ if (format->ptr[k] == '}') break;
+ }
+
+- if (k == format->used - 1) {
++ if (k == buffer_string_length(format)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{ has to be terminated by a }");
+ return -1;
+ }
+@@ -416,9 +416,9 @@ FREE_FUNC(mod_accesslog_free) {
+
+ if (!s) continue;
+
+- if (s->access_logbuffer->used) {
++ if (!buffer_string_is_empty(s->access_logbuffer)) {
+ if (s->log_access_fd != -1) {
+- write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
++ write(s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
+ }
+ }
+
+@@ -502,7 +502,7 @@ SETDEFAULTS_FUNC(log_access_open) {
+
+ /* parse */
+
+- if (s->format->used) {
++ if (!buffer_is_empty(s->format)) {
+ size_t j, count;
+
+ s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
+@@ -572,7 +572,7 @@ SETDEFAULTS_FUNC(log_access_open) {
+ continue;
+ }
+
+- if (s->access_logfile->used < 2) continue;
++ if (buffer_string_is_empty(s->access_logfile)) continue;
+
+ if (-1 == (s->log_access_fd = open_logfile_or_pipe(srv, s->access_logfile->ptr)))
+ return HANDLER_ERROR;
+@@ -591,17 +591,17 @@ SIGHUP_FUNC(log_access_cycle) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (s->access_logbuffer->used) {
++ if (!buffer_string_is_empty(s->access_logbuffer)) {
+ if (s->log_access_fd != -1) {
+- write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
++ write(s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
+ }
+
+ buffer_reset(s->access_logbuffer);
+ }
+
+- if (s->use_syslog == 0 &&
+- s->access_logfile->used > 1 &&
+- s->access_logfile->ptr[0] != '|') {
++ if (s->use_syslog == 0
++ && !buffer_string_is_empty(s->access_logfile)
++ && s->access_logfile->ptr[0] != '|') {
+
+ if (-1 != s->log_access_fd) close(s->log_access_fd);
+
+@@ -691,8 +691,8 @@ REQUESTDONE_FUNC(log_access_write) {
+ b = p->conf.access_logbuffer;
+ }
+
+- if (b->used == 0) {
+- buffer_copy_string_len(b, CONST_STR_LEN(""));
++ if (buffer_is_empty(b)) {
++ buffer_string_set_length(b, 0);
+ }
+
+ for (j = 0; j < p->conf.parsed_format->used; j++) {
+@@ -715,11 +715,10 @@ REQUESTDONE_FUNC(log_access_write) {
+ #if defined(HAVE_STRUCT_TM_GMTOFF)
+ # ifdef HAVE_LOCALTIME_R
+ localtime_r(&(srv->cur_ts), &tm);
+- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, &tm);
++ buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, &tm);
+ # else /* HAVE_LOCALTIME_R */
+- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, localtime_r(&(srv->cur_ts)));
++ buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, localtime(&(srv->cur_ts)));
+ # endif /* HAVE_LOCALTIME_R */
+- p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
+
+ if (p->conf.append_tz_offset) {
+ buffer_append_string_len(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-", 1);
+@@ -739,11 +738,10 @@ REQUESTDONE_FUNC(log_access_write) {
+ #else /* HAVE_STRUCT_TM_GMTOFF */
+ # ifdef HAVE_GMTIME_R
+ gmtime_r(&(srv->cur_ts), &tm);
+- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, &tm);
++ buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, &tm);
+ # else /* HAVE_GMTIME_R */
+- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, gmtime(&(srv->cur_ts)));
++ buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, gmtime(&(srv->cur_ts)));
+ # endif /* HAVE_GMTIME_R */
+- p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
+ #endif /* HAVE_STRUCT_TM_GMTOFF */
+
+ *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
+@@ -765,14 +763,14 @@ REQUESTDONE_FUNC(log_access_write) {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ break;
+ case FORMAT_REMOTE_USER:
+- if (NULL != (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER")) && ds->value->used > 1) {
++ if (NULL != (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER")) && !buffer_string_is_empty(ds->value)) {
+ accesslog_append_escaped(b, ds->value);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_REQUEST_LINE:
+- if (con->request.request_line->used) {
++ if (!buffer_string_is_empty(con->request.request_line)) {
+ accesslog_append_escaped(b, con->request.request_line);
+ }
+ break;
+@@ -810,7 +808,7 @@ REQUESTDONE_FUNC(log_access_write) {
+ }
+ break;
+ case FORMAT_FILENAME:
+- if (con->physical.path->used > 1) {
++ if (!buffer_string_is_empty(con->physical.path)) {
+ buffer_append_string_buffer(b, con->physical.path);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+@@ -834,14 +832,14 @@ REQUESTDONE_FUNC(log_access_write) {
+ buffer_append_int(b, srv->cur_ts - con->request_start);
+ break;
+ case FORMAT_SERVER_NAME:
+- if (con->server_name->used > 1) {
++ if (!buffer_string_is_empty(con->server_name)) {
+ buffer_append_string_buffer(b, con->server_name);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_HTTP_HOST:
+- if (con->uri.authority->used > 1) {
++ if (!buffer_string_is_empty(con->uri.authority)) {
+ accesslog_append_escaped(b, con->uri.authority);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+@@ -849,7 +847,7 @@ REQUESTDONE_FUNC(log_access_write) {
+ break;
+ case FORMAT_REQUEST_PROTOCOL:
+ buffer_append_string_len(b,
+- con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0", 8);
++ con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0", 8);
+ break;
+ case FORMAT_REQUEST_METHOD:
+ buffer_append_string(b, get_http_method_name(con->request.http_method));
+@@ -904,19 +902,19 @@ REQUESTDONE_FUNC(log_access_write) {
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ if (p->conf.use_syslog || /* syslog doesn't cache */
+- (p->conf.access_logfile->used && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */
++ (!buffer_string_is_empty(p->conf.access_logfile) && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */
+ newts ||
+- b->used > BUFFER_MAX_REUSE_SIZE) {
++ buffer_string_length(b) >= BUFFER_MAX_REUSE_SIZE) {
+ if (p->conf.use_syslog) {
+ #ifdef HAVE_SYSLOG_H
+- if (b->used > 2) {
++ if (!buffer_string_is_empty(b)) {
+ /* syslog appends a \n on its own */
+- syslog(p->conf.syslog_level, "%*s", (int) b->used - 2, b->ptr);
++ buffer_string_set_length(b, buffer_string_length(b) - 1);
++ syslog(p->conf.syslog_level, "%s", b->ptr);
+ }
+ #endif
+ } else if (p->conf.log_access_fd != -1) {
+- force_assert(b->used > 0);
+- write(p->conf.log_access_fd, b->ptr, b->used - 1);
++ write(p->conf.log_access_fd, CONST_BUF_LEN(b));
+ }
+ buffer_reset(b);
+ }
+diff --git a/src/mod_alias.c b/src/mod_alias.c
+index bf22b5f..4625973 100644
+--- a/src/mod_alias.c
++++ b/src/mod_alias.c
+@@ -95,10 +95,10 @@ SETDEFAULTS_FUNC(mod_alias_set_defaults) {
+ for (k = j + 1; k < a->used; k ++) {
+ const buffer *key = a->data[a->sorted[k]]->key;
+
+- if (key->used < prefix->used) {
++ if (buffer_string_length(key) < buffer_string_length(prefix)) {
+ break;
+ }
+- if (memcmp(key->ptr, prefix->ptr, prefix->used - 1) != 0) {
++ if (memcmp(key->ptr, prefix->ptr, buffer_string_length(prefix)) != 0) {
+ break;
+ }
+ /* ok, they have same prefix. check position */
+@@ -151,22 +151,22 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) {
+ char *uri_ptr;
+ size_t k;
+
+- if (con->physical.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_alias_patch_connection(srv, con, p);
+
+ /* not to include the tailing slash */
+- basedir_len = (con->physical.basedir->used - 1);
++ basedir_len = buffer_string_length(con->physical.basedir);
+ if ('/' == con->physical.basedir->ptr[basedir_len-1]) --basedir_len;
+- uri_len = con->physical.path->used - 1 - basedir_len;
++ uri_len = buffer_string_length(con->physical.path) - basedir_len;
+ uri_ptr = con->physical.path->ptr + basedir_len;
+
+ for (k = 0; k < p->conf.alias->used; k++) {
+ data_string *ds = (data_string *)p->conf.alias->data[k];
+- int alias_len = ds->key->used - 1;
++ int alias_len = buffer_string_length(ds->key);
+
+ if (alias_len > uri_len) continue;
+- if (ds->key->used == 0) continue;
++ if (buffer_is_empty(ds->key)) continue;
+
+ if (0 == (con->conf.force_lowercase_filenames ?
+ strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
+diff --git a/src/mod_auth.c b/src/mod_auth.c
+index d5a3f1c..1870893 100644
+--- a/src/mod_auth.c
++++ b/src/mod_auth.c
+@@ -206,18 +206,18 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
+ for (k = 0; k < p->conf.auth_require->used; k++) {
+ buffer *require = p->conf.auth_require->data[k]->key;
+
+- if (require->used == 0) continue;
+- if (con->uri.path->used < require->used) continue;
++ if (buffer_is_empty(require)) continue;
++ if (buffer_string_length(con->uri.path) < buffer_string_length(require)) continue;
+
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+
+ if (con->conf.force_lowercase_filenames) {
+- if (0 == strncasecmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
++ if (0 == strncasecmp(con->uri.path->ptr, require->ptr, buffer_string_length(require))) {
+ auth_required = 1;
+ break;
+ }
+ } else {
+- if (0 == strncmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
++ if (0 == strncmp(con->uri.path->ptr, require->ptr, buffer_string_length(require))) {
+ auth_required = 1;
+ break;
+ }
+@@ -248,7 +248,7 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
+
+ /* try to get Authorization-header */
+
+- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization")) && ds->value->used) {
++ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization")) && !buffer_is_empty(ds->value)) {
+ char *auth_realm;
+
+ http_authorization = ds->value->ptr;
+@@ -419,7 +419,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (s->auth_backend_conf->used) {
++ if (!buffer_string_is_empty(s->auth_backend_conf)) {
+ if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
+ s->auth_backend = AUTH_BACKEND_HTPASSWD;
+ } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
+@@ -436,7 +436,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
+ }
+
+ #ifdef USE_LDAP
+- if (s->auth_ldap_filter->used) {
++ if (!buffer_string_is_empty(s->auth_ldap_filter)) {
+ char *dollar;
+
+ /* parse filter */
+@@ -562,7 +562,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
+ }
+ }
+
+- switch(s->auth_ldap_hostname->used) {
++ switch(s->auth_backend) {
+ case AUTH_BACKEND_LDAP: {
+ handler_t ret = auth_ldap_init(srv, s);
+ if (ret == HANDLER_ERROR)
+@@ -588,7 +588,7 @@ handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
+ }
+ #endif
+
+- if (s->auth_ldap_hostname->used) {
++ if (!buffer_string_is_empty(s->auth_ldap_hostname)) {
+ /* free old context */
+ if (NULL != s->ldap) ldap_unbind_s(s->ldap);
+
+@@ -627,7 +627,7 @@ handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
+
+
+ /* 1. */
+- if (s->auth_ldap_binddn->used) {
++ if (!buffer_string_is_empty(s->auth_ldap_binddn)) {
+ if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
+
+diff --git a/src/mod_cgi.c b/src/mod_cgi.c
+index f132b8a..8a7cc2b 100644
+--- a/src/mod_cgi.c
++++ b/src/mod_cgi.c
+@@ -376,8 +376,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ return FDEVENT_HANDLED_FINISHED;
+ }
+
+- hctx->response->ptr[n] = '\0';
+- hctx->response->used = n+1;
++ buffer_commit(hctx->response, n);
+
+ /* split header from body */
+
+@@ -385,7 +384,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ int is_header = 0;
+ int is_header_end = 0;
+ size_t last_eol = 0;
+- size_t i;
++ size_t i, header_len;
+
+ buffer_append_string_buffer(hctx->response_header, hctx->response);
+
+@@ -412,8 +411,9 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+
+ /* nph (non-parsed headers) */
+ if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1;
+-
+- for (i = 0; !is_header_end && i < hctx->response_header->used - 1; i++) {
++
++ header_len = buffer_string_length(hctx->response_header);
++ for (i = 0; !is_header_end && i < header_len; i++) {
+ char c = hctx->response_header->ptr[i];
+
+ switch (c) {
+@@ -463,26 +463,25 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ } else {
+ const char *bstart;
+ size_t blen;
+-
++
++ /* the body starts after the EOL */
++ bstart = hctx->response_header->ptr + i;
++ blen = header_len - i;
++
+ /**
+ * i still points to the char after the terminating EOL EOL
+ *
+ * put it on the last \n again
+ */
+ i--;
+-
+- /* the body starts after the EOL */
+- bstart = hctx->response_header->ptr + (i + 1);
+- blen = (hctx->response_header->used - 1) - (i + 1);
+-
++
+ /* string the last \r?\n */
+ if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) {
+ i--;
+ }
+
+- hctx->response_header->ptr[i] = '\0';
+- hctx->response_header->used = i + 1; /* the string + \0 */
+-
++ buffer_string_set_length(hctx->response_header, i);
++
+ /* parse the response header */
+ cgi_response_parse(srv, con, p, hctx->response_header);
+
+@@ -738,7 +737,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+
+ #ifndef __WIN32
+
+- if (cgi_handler->used > 1) {
++ if (!buffer_string_is_empty(cgi_handler)) {
+ /* stat the exec file */
+ if (-1 == (stat(cgi_handler->ptr, &st))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+@@ -800,7 +799,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ }
+
+ if (!buffer_string_is_empty(con->server_name)) {
+- size_t len = con->server_name->used - 1;
++ size_t len = buffer_string_length(con->server_name);
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+@@ -938,7 +937,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+
+ ds = (data_string *)con->request.headers->data[n];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
+@@ -950,7 +949,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+
+ ds = (data_string *)con->environment->data[n];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
+@@ -969,7 +968,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ args = malloc(sizeof(*args) * argc);
+ i = 0;
+
+- if (cgi_handler->used > 1) {
++ if (!buffer_string_is_empty(cgi_handler)) {
+ args[i++] = cgi_handler->ptr;
+ }
+ args[i++] = con->physical.path->ptr;
+@@ -1071,7 +1070,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ }
+ break;
+ case MEM_CHUNK:
+- if ((r = write(to_cgi_fds[1], c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
++ if ((r = write(to_cgi_fds[1], c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
+ switch(errno) {
+ case ENOSPC:
+ con->http_status = 507;
+@@ -1185,7 +1184,7 @@ URIHANDLER_FUNC(cgi_is_handled) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (fn->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(fn)) return HANDLER_GO_ON;
+
+ mod_cgi_patch_connection(srv, con, p);
+
+@@ -1193,13 +1192,13 @@ URIHANDLER_FUNC(cgi_is_handled) {
+ if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
+ if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
+
+- s_len = fn->used - 1;
++ s_len = buffer_string_length(fn);
+
+ for (k = 0; k < p->conf.cgi->used; k++) {
+ data_string *ds = (data_string *)p->conf.cgi->data[k];
+- size_t ct_len = ds->key->used - 1;
++ size_t ct_len = buffer_string_length(ds->key);
+
+- if (ds->key->used == 0) continue;
++ if (buffer_is_empty(ds->key)) continue;
+ if (s_len < ct_len) continue;
+
+ if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
+diff --git a/src/mod_cml.c b/src/mod_cml.c
+index 3033d42..baa23b3 100644
+--- a/src/mod_cml.c
++++ b/src/mod_cml.c
+@@ -185,20 +185,18 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *
+ /* cleanup basedir */
+ b = p->baseurl;
+ buffer_copy_buffer(b, con->uri.path);
+- for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
++ for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
+
+ if (*c == '/') {
+- b->used = c - b->ptr + 2;
+- *(c+1) = '\0';
++ buffer_string_set_length(b, c - b->ptr + 1);
+ }
+
+ b = p->basedir;
+ buffer_copy_buffer(b, con->physical.path);
+- for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
++ for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
+
+ if (*c == '/') {
+- b->used = c - b->ptr + 2;
+- *(c+1) = '\0';
++ buffer_string_set_length(b, c - b->ptr + 1);
+ }
+
+
+@@ -274,7 +272,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
+
+ if (buffer_string_is_empty(p->conf.ext)) return HANDLER_GO_ON;
+
+- if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
++ if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, buffer_string_length(p->conf.ext))) {
+ return HANDLER_GO_ON;
+ }
+
+diff --git a/src/mod_cml_funcs.c b/src/mod_cml_funcs.c
+index 9d859c7..a377edd 100644
+--- a/src/mod_cml_funcs.c
++++ b/src/mod_cml_funcs.c
+@@ -35,14 +35,9 @@ typedef char HASHHEX[HASHHEXLEN+1];
+ int f_crypto_md5(lua_State *L) {
+ li_MD5_CTX Md5Ctx;
+ HASH HA1;
+- buffer b;
+ char hex[33];
+ int n = lua_gettop(L);
+
+- b.ptr = hex;
+- b.used = 0;
+- b.size = sizeof(hex);
+-
+ if (n != 1) {
+ lua_pushstring(L, "md5: expected one argument");
+ lua_error(L);
+@@ -57,9 +52,9 @@ int f_crypto_md5(lua_State *L) {
+ 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);
++ li_tohex(hex, (const char*) HA1, 16);
+
+- lua_pushstring(L, b.ptr);
++ lua_pushstring(L, hex);
+
+ return 1;
+ }
+diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
+index 63dd1e7..895a709 100644
+--- a/src/mod_cml_lua.c
++++ b/src/mod_cml_lua.c
+@@ -102,13 +102,14 @@ static int c_to_lua_push(lua_State *L, int tbl, const char *key, size_t key_len,
+
+ static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) {
+ size_t is_key = 1;
+- size_t i;
++ size_t i, len;
+ char *key = NULL, *val = NULL;
+
+ key = qrystr->ptr;
+
+ /* we need the \0 */
+- for (i = 0; i < qrystr->used; i++) {
++ len = buffer_string_length(qrystr);
++ for (i = 0; i <= len; i++) {
+ switch(qrystr->ptr[i]) {
+ case '=':
+ if (is_key) {
+@@ -129,8 +130,8 @@ static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) {
+ qrystr->ptr[i] = '\0';
+
+ c_to_lua_push(L, tbl,
+- key, strlen(key),
+- val, strlen(val));
++ key, strlen(key),
++ val, strlen(val));
+ }
+
+ key = qrystr->ptr + i + 1;
+@@ -398,7 +399,6 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ if (ret == 0) {
+ data_string *ds;
+ char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
+- buffer tbuf;
+
+ con->file_finished = 1;
+
+@@ -411,17 +411,11 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
+-
+- tbuf.ptr = timebuf;
+- tbuf.used = sizeof(timebuf);
+- tbuf.size = sizeof(timebuf);
+- } else {
+- tbuf.ptr = ds->value->ptr;
+- tbuf.used = ds->value->used;
+- tbuf.size = ds->value->size;
++ ds = (data_string *)array_get_element(con->response.headers, "Last-Modified");
++ force_assert(NULL != ds);
+ }
+
+- if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
++ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, ds->value)) {
+ /* ok, the client already has our content,
+ * no need to send it again */
+
+diff --git a/src/mod_compress.c b/src/mod_compress.c
+index 120b379..f0ffa1c 100644
+--- a/src/mod_compress.c
++++ b/src/mod_compress.c
+@@ -244,6 +244,7 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+ unsigned char *c;
+ unsigned long crc;
+ z_stream z;
++ size_t outlen;
+
+ UNUSED(srv);
+ UNUSED(con);
+@@ -282,9 +283,9 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+ c[8] = 0x00; /* extra flags */
+ c[9] = 0x03; /* UNIX */
+
+- p->b->used = 10;
+- z.next_out = (unsigned char *)p->b->ptr + p->b->used;
+- z.avail_out = p->b->size - p->b->used - 9;
++ outlen = 10;
++ z.next_out = (unsigned char *)p->b->ptr + outlen;
++ z.avail_out = p->b->size - outlen - 9;
+ z.total_out = 0;
+
+ if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
+@@ -293,11 +294,11 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+ }
+
+ /* trailer */
+- p->b->used += z.total_out;
++ outlen += z.total_out;
+
+ crc = generate_crc32c(start, st_size);
+
+- c = (unsigned char *)p->b->ptr + p->b->used;
++ c = (unsigned char *)p->b->ptr + outlen;
+
+ c[0] = (crc >> 0) & 0xff;
+ c[1] = (crc >> 8) & 0xff;
+@@ -307,8 +308,8 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
+ c[5] = (z.total_in >> 8) & 0xff;
+ c[6] = (z.total_in >> 16) & 0xff;
+ c[7] = (z.total_in >> 24) & 0xff;
+- p->b->used += 8;
+- p->b->ptr[p->b->used++] = '\0';
++ outlen += 8;
++ buffer_commit(p->b, outlen);
+
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+@@ -398,16 +399,15 @@ static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_dat
+ return -1;
+ }
+
++ if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
++ return -1;
++ }
++
+ /* file is too large for now */
+ if (bz.total_out_hi32) return -1;
+
+ /* trailer */
+- p->b->used = bz.total_out_lo32;
+- p->b->ptr[p->b->used++] = '\0';
+-
+- if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
+- return -1;
+- }
++ buffer_commit(p->b, bz.total_out_lo32);
+
+ return 0;
+ }
+@@ -434,8 +434,8 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
+ buffer_copy_buffer(p->ofn, p->conf.compress_cache_dir);
+ buffer_append_slash(p->ofn);
+
+- if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
+- buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
++ if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, buffer_string_length(con->physical.doc_root))) {
++ buffer_append_string(p->ofn, con->physical.path->ptr + buffer_string_length(con->physical.doc_root));
+ } else {
+ buffer_append_string_buffer(p->ofn, con->uri.path);
+ }
+@@ -883,7 +883,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
+ }
+
+ /* deflate it */
+- if (use_etag && p->conf.compress_cache_dir->used) {
++ if (use_etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) {
+ if (0 != deflate_file_to_file(srv, con, p, con->physical.path, sce, compression_type))
+ return HANDLER_GO_ON;
+ } else {
+@@ -897,7 +897,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
+ }
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ /* let mod_staticfile handle the cached compressed files, physical path was modified */
+- return (use_etag && p->conf.compress_cache_dir->used) ? HANDLER_GO_ON : HANDLER_FINISHED;
++ return (use_etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) ? HANDLER_GO_ON : HANDLER_FINISHED;
+ }
+ }
+ }
+diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
+index e2e0bfa..d8bf3a3 100644
+--- a/src/mod_dirlisting.c
++++ b/src/mod_dirlisting.c
+@@ -492,7 +492,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</title>\n"));
+
+- if (p->conf.external_css->used > 1) {
++ if (!buffer_string_is_empty(p->conf.external_css)) {
+ buffer_append_string_len(out, CONST_STR_LEN("<link rel=\"stylesheet\" type=\"text/css\" href=\""));
+ buffer_append_string_buffer(out, p->conf.external_css);
+ buffer_append_string_len(out, CONST_STR_LEN("\" />\n"));
+@@ -614,7 +614,7 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
+ "<div class=\"foot\">"
+ ));
+
+- if (p->conf.set_footer->used > 1) {
++ if (buffer_string_is_empty(p->conf.set_footer)) {
+ buffer_append_string_buffer(out, p->conf.set_footer);
+ } else if (buffer_is_empty(con->conf.server_tag)) {
+ buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_DESC));
+@@ -653,9 +653,9 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ struct tm tm;
+ #endif
+
+- if (dir->used == 0) return -1;
++ if (buffer_string_is_empty(dir)) return -1;
+
+- i = dir->used - 1;
++ i = buffer_string_length(dir);
+
+ #ifdef HAVE_PATHCONF
+ if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
+@@ -672,8 +672,8 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ name_max = NAME_MAX;
+ #endif
+
+- path = malloc(dir->used + name_max);
+- force_assert(path);
++ path = malloc(buffer_string_length(dir) + name_max + 1);
++ force_assert(NULL != path);
+ strcpy(path, dir->ptr);
+ path_file = path + i;
+
+@@ -846,10 +846,10 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+ size_t ct_len;
+
+- if (ds->key->used == 0)
++ if (buffer_is_empty(ds->key))
+ continue;
+
+- ct_len = ds->key->used - 1;
++ ct_len = buffer_string_length(ds->key);
+ if (tmp->namelen < ct_len)
+ continue;
+
+@@ -925,9 +925,9 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (con->physical.path->used == 0) return HANDLER_GO_ON;
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
+- if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
++ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
++ if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON;
+
+ mod_dirlisting_patch_connection(srv, con, p);
+
+diff --git a/src/mod_evasive.c b/src/mod_evasive.c
+index a20aff5..d9b8732 100644
+--- a/src/mod_evasive.c
++++ b/src/mod_evasive.c
+@@ -138,7 +138,7 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) {
+ size_t conns_by_ip = 0;
+ size_t j;
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_evasive_patch_connection(srv, con, p);
+
+diff --git a/src/mod_evhost.c b/src/mod_evhost.c
+index 5281523..e728551 100644
+--- a/src/mod_evhost.c
++++ b/src/mod_evhost.c
+@@ -146,7 +146,7 @@ SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
+ return HANDLER_ERROR;
+ }
+
+- if (s->path_pieces_raw->used != 0) {
++ if (!buffer_string_is_empty(s->path_pieces_raw)) {
+ mod_evhost_parse_pattern(s);
+ }
+ }
+@@ -164,8 +164,7 @@ SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
+ */
+
+ static int mod_evhost_parse_host(connection *con,array *host) {
+- /* con->uri.authority->used is always > 0 if we come here */
+- register char *ptr = con->uri.authority->ptr + con->uri.authority->used - 1;
++ register char *ptr = con->uri.authority->ptr + buffer_string_length(con->uri.authority);
+ char *colon = ptr; /* needed to filter out the colon (if exists) */
+ int first = 1;
+ data_string *ds;
+@@ -265,7 +264,7 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
+ stat_cache_entry *sce = NULL;
+
+ /* not authority set */
+- if (con->uri.authority->used == 0) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
+
+ mod_evhost_patch_connection(srv, con, p);
+
+@@ -300,9 +299,7 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
+ buffer_append_string_len(p->tmp_buf, con->uri.authority->ptr, colon - con->uri.authority->ptr); /* adds fqdn */
+ }
+ } else if (NULL != (ds = (data_string *)array_get_element(parsed_host,p->conf.path_pieces[i]->ptr))) {
+- if (ds->value->used) {
+- buffer_append_string_buffer(p->tmp_buf,ds->value);
+- }
++ buffer_append_string_buffer(p->tmp_buf,ds->value);
+ } else {
+ /* unhandled %-sequence */
+ }
+diff --git a/src/mod_expire.c b/src/mod_expire.c
+index 31a81b7..e26c3c6 100644
+--- a/src/mod_expire.c
++++ b/src/mod_expire.c
+@@ -90,7 +90,7 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, ti
+ * e.g. 'access 1 years'
+ */
+
+- if (expire->used == 0) {
++ if (buffer_string_is_empty(expire)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "empty:");
+ return -1;
+@@ -288,22 +288,21 @@ URIHANDLER_FUNC(mod_expire_path_handler) {
+ int s_len;
+ size_t k;
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_expire_patch_connection(srv, con, p);
+
+- s_len = con->uri.path->used - 1;
++ s_len = buffer_string_length(con->uri.path);
+
+ for (k = 0; k < p->conf.expire_url->used; k++) {
+ data_string *ds = (data_string *)p->conf.expire_url->data[k];
+- int ct_len = ds->key->used - 1;
++ int ct_len = buffer_string_length(ds->key);
+
+ if (ct_len > s_len) continue;
+- if (ds->key->used == 0) continue;
++ if (buffer_is_empty(ds->key)) continue;
+
+ if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
+ time_t ts, expires;
+- size_t len;
+ stat_cache_entry *sce = NULL;
+
+ /* if stat fails => sce == NULL, ignore return value */
+@@ -332,14 +331,8 @@ URIHANDLER_FUNC(mod_expire_path_handler) {
+ /* expires should be at least srv->cur_ts */
+ if (expires < srv->cur_ts) expires = srv->cur_ts;
+
+- if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
+- "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires))))) {
+- /* could not set expire header, out of mem */
+-
+- return HANDLER_GO_ON;
+- }
+-
+- p->expire_tstmp->used = len + 1;
++ buffer_string_prepare_copy(p->expire_tstmp, 255);
++ buffer_append_strftime(p->expire_tstmp, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires)));
+
+ /* HTTP/1.0 */
+ response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
+diff --git a/src/mod_extforward.c b/src/mod_extforward.c
+index 99c4af5..7f77982 100644
+--- a/src/mod_extforward.c
++++ b/src/mod_extforward.c
+@@ -236,7 +236,7 @@ static void put_string_into_array_len(array *ary, const char *str, int len)
+ static array *extract_forward_array(buffer *pbuffer)
+ {
+ array *result = array_init();
+- if (pbuffer->used > 0) {
++ if (!buffer_string_is_empty(pbuffer)) {
+ char *base, *curr;
+ /* state variable, 0 means not in string, 1 means in string */
+ int in_str = 0;
+diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
+index a935961..d16306c 100644
+--- a/src/mod_fastcgi.c
++++ b/src/mod_fastcgi.c
+@@ -784,7 +784,7 @@ static int parse_binpath(char_array *env, buffer *b) {
+ /* search for spaces */
+
+ start = b->ptr;
+- for (i = 0; i < b->used - 1; i++) {
++ for (i = 0; i < buffer_string_length(b); i++) {
+ switch(b->ptr[i]) {
+ case ' ':
+ case '\t':
+@@ -863,19 +863,19 @@ static int fcgi_spawn_connection(server *srv,
+
+ #ifdef HAVE_SYS_UN_H
+ fcgi_addr_un.sun_family = AF_UNIX;
+- if (proc->unixsocket->used > sizeof(fcgi_addr_un.sun_path)) {
++ if (buffer_string_length(proc->unixsocket) + 1 > sizeof(fcgi_addr_un.sun_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sB",
+ "ERROR: Unix Domain socket filename too long:",
+ proc->unixsocket);
+ return -1;
+ }
+- memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, proc->unixsocket->used);
++ memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, buffer_string_length(proc->unixsocket) + 1);
+
+ #ifdef SUN_LEN
+ servlen = SUN_LEN(&fcgi_addr_un);
+ #else
+ /* stevens says: */
+- servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
++ servlen = buffer_string_length(proc->unixsocket) + 1 + sizeof(fcgi_addr_un.sun_family);
+ #endif
+ socket_type = AF_UNIX;
+ fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+@@ -1324,7 +1324,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ /* unix domain socket */
+ struct sockaddr_un un;
+
+- if (host->unixsocket->used > sizeof(un.sun_path) - 2) {
++ if (buffer_string_length(host->unixsocket) + 1 > sizeof(un.sun_path) - 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "unixsocket is too long in:",
+ da->key, "= (",
+@@ -1667,19 +1667,19 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
+ #ifdef HAVE_SYS_UN_H
+ /* use the unix domain socket */
+ fcgi_addr_un.sun_family = AF_UNIX;
+- if (proc->unixsocket->used > sizeof(fcgi_addr_un.sun_path)) {
++ if (buffer_string_length(proc->unixsocket) + 1 > sizeof(fcgi_addr_un.sun_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sB",
+ "ERROR: Unix Domain socket filename too long:",
+ proc->unixsocket);
+ return -1;
+ }
+- memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, proc->unixsocket->used);
++ memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, buffer_string_length(proc->unixsocket) + 1);
+
+ #ifdef SUN_LEN
+ servlen = SUN_LEN(&fcgi_addr_un);
+ #else
+ /* stevens says: */
+- servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
++ servlen = buffer_string_length(proc->unixsocket) + 1 + sizeof(fcgi_addr_un.sun_family);
+ #endif
+ fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+@@ -1774,7 +1774,7 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+
+ ds = (data_string *)con->request.headers->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);
+@@ -1786,7 +1786,7 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+
+ ds = (data_string *)con->environment->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);
+@@ -1833,8 +1833,8 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con)
+ }
+
+- if (con->server_name->used) {
+- size_t len = con->server_name->used - 1;
++ if (!buffer_is_empty(con->server_name)) {
++ size_t len = buffer_string_length(con->server_name);
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+@@ -1961,7 +1961,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con)
+ }
+
+- if (host->strip_request_uri->used > 1) {
++ if (!buffer_string_is_empty(host->strip_request_uri)) {
+ /* we need at least one char to strip off */
+ /**
+ * /app1/index/list
+@@ -1971,18 +1971,18 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ * /index/list
+ *
+ */
+- if ('/' != host->strip_request_uri->ptr[host->strip_request_uri->used - 2]) {
++ if ('/' != host->strip_request_uri->ptr[buffer_string_length(host->strip_request_uri) - 1]) {
+ /* fix the user-input to have / as last char */
+ buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));
+ }
+
+- if (con->request.orig_uri->used >= host->strip_request_uri->used &&
+- 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
++ if (buffer_string_length(con->request.orig_uri) >= buffer_string_length(host->strip_request_uri) &&
++ 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, buffer_string_length(host->strip_request_uri))) {
+ /* the left is the same */
+
+ fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
+- con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
+- con->request.orig_uri->used - (host->strip_request_uri->used - 2) - 1);
++ con->request.orig_uri->ptr + (buffer_string_length(host->strip_request_uri) - 1),
++ buffer_string_length(con->request.orig_uri) - (buffer_string_length(host->strip_request_uri) - 1));
+ } else {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
+ }
+@@ -2022,7 +2022,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
+ fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
+ buffer_append_string_len(b, (const char *)&header, sizeof(header));
+
+- hctx->wb->bytes_in += b->used - 1;
++ hctx->wb->bytes_in += buffer_string_length(b);
+ chunkqueue_append_buffer(hctx->wb, b);
+ buffer_free(b);
+ }
+@@ -2303,11 +2303,10 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
+ if (0 == toread) break;
+ }
+
+- if ((packet->b->used == 0) ||
+- (packet->b->used - 1 < sizeof(FCGI_Header))) {
++ if (buffer_string_length(packet->b) < sizeof(FCGI_Header)) {
+ /* no header */
+ if (hctx->plugin_data->conf.debug) {
+- log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");
++ log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", buffer_string_length(packet->b), "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");
+ }
+
+ buffer_free(packet->b);
+@@ -2324,13 +2323,13 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
+ packet->padding = header->paddingLength;
+
+ /* ->b should only be the content */
+- buffer_copy_string_len(packet->b, CONST_STR_LEN("")); /* used == 1 */
++ buffer_string_set_length(packet->b, 0);
+
+ if (packet->len) {
+ /* copy the content */
+- for (; c && (packet->b->used < packet->len + 1); c = c->next) {
+- size_t weWant = packet->len - (packet->b->used - 1);
+- size_t weHave = c->mem->used - c->offset - offset - 1;
++ for (; c && (buffer_string_length(packet->b) < packet->len); c = c->next) {
++ size_t weWant = packet->len - buffer_string_length(packet->b);
++ size_t weHave = buffer_string_length(c->mem) - c->offset - offset;
+
+ if (weHave > weWant) weHave = weWant;
+
+@@ -2340,24 +2339,23 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
+ offset = 0;
+ }
+
+- if (packet->b->used < packet->len + 1) {
++ if (buffer_string_length(packet->b) < packet->len) {
+ /* we didn't get the full packet */
+
+ buffer_free(packet->b);
+ return -1;
+ }
+
+- packet->b->used -= packet->padding;
+- packet->b->ptr[packet->b->used - 1] = '\0';
++ buffer_string_set_length(packet->b, buffer_string_length(packet->b) - packet->padding);
+ }
+
+ /* tag the chunks as read */
+ toread = packet->len + sizeof(FCGI_Header);
+ for (c = hctx->rb->first; c && toread; c = c->next) {
+- if (c->mem->used - c->offset - 1 <= toread) {
++ if (buffer_string_length(c->mem) - c->offset <= toread) {
+ /* we read this whole buffer, move it to unused */
+- toread -= c->mem->used - c->offset - 1;
+- c->offset = c->mem->used - 1; /* everthing has been written */
++ toread -= buffer_string_length(c->mem) - c->offset;
++ c->offset = buffer_string_length(c->mem); /* everthing has been written */
+ } else {
+ c->offset += toread;
+ toread = 0;
+@@ -2451,14 +2449,12 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ char *hend = c + 4; /* header end == body start */
+ size_t hlen = hend - hctx->response_header->ptr;
+ buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen);
+- hctx->response_header->used = hlen;
+- hctx->response_header->ptr[hctx->response_header->used++] = '\0';
++ buffer_string_set_length(hctx->response_header, hlen);
+ } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
+ char *hend = c + 2; /* header end == body start */
+ size_t hlen = hend - hctx->response_header->ptr;
+ buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen);
+- hctx->response_header->used = hlen;
+- hctx->response_header->ptr[hctx->response_header->used++] = '\0';
++ buffer_string_set_length(hctx->response_header, hlen);
+ } else {
+ /* no luck, no header found */
+ break;
+@@ -2525,7 +2521,7 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
+ http_chunk_append_buffer(srv, con, packet.b);
+ joblist_append(srv, con);
+ }
+- } else if (hctx->send_content_body && packet.b->used > 1) {
++ } else if (hctx->send_content_body && !buffer_string_is_empty(packet.b)) {
+ if (con->request.http_version == HTTP_VERSION_1_1 &&
+ !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
+ /* enable chunked-transfer-encoding */
+@@ -2721,7 +2717,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");
+ return HANDLER_ERROR;
+ }
+- if ((!host->port && !host->unixsocket->used)) {
++ if ((!host->port && buffer_string_is_empty(host->unixsocket))) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set");
+ return HANDLER_ERROR;
+ }
+@@ -2794,7 +2790,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
+ if (proc->load < hctx->proc->load) hctx->proc = proc;
+ }
+
+- ret = host->unixsocket->used ? AF_UNIX : AF_INET;
++ ret = buffer_string_is_empty(host->unixsocket) ? AF_INET : AF_UNIX;
+
+ if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
+ if (errno == EMFILE ||
+@@ -3335,7 +3331,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
+
+ if (buffer_string_is_empty(fn)) return HANDLER_GO_ON;
+
+- s_len = fn->used - 1;
++ s_len = buffer_string_length(fn);
+
+ fcgi_patch_connection(srv, con, p);
+
+@@ -3352,9 +3348,9 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
+ data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
+ size_t ct_len; /* length of the config entry */
+
+- if (ds->key->used == 0) continue;
++ if (buffer_is_empty(ds->key)) continue;
+
+- ct_len = ds->key->used - 1;
++ ct_len = buffer_string_length(ds->key);
+
+ if (s_len < ct_len) continue;
+
+@@ -3380,18 +3376,20 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
+ }
+
+ if (extension == NULL) {
++ size_t uri_path_len = buffer_string_length(con->uri.path);
++
+ /* check if extension matches */
+ for (k = 0; k < p->conf.exts->used; k++) {
+ size_t ct_len; /* length of the config entry */
+ fcgi_extension *ext = p->conf.exts->exts[k];
+
+- if (ext->key->used == 0) continue;
++ if (buffer_is_empty(ext->key)) continue;
+
+- ct_len = ext->key->used - 1;
++ ct_len = buffer_string_length(ext->key);
+
+ /* check _url_ in the form "/fcgi_pattern" */
+ if (ext->key->ptr[0] == '/') {
+- if ((ct_len <= con->uri.path->used -1) &&
++ if ((ct_len <= uri_path_len) &&
+ (strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) {
+ extension = ext;
+ break;
+@@ -3506,17 +3504,14 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
+ /* the rewrite is only done for /prefix/? matches */
+ if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {
+ buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);
+- con->uri.path->used = 1;
+- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
++ buffer_string_set_length(con->uri.path, 0);
+ } else if (extension->key->ptr[0] == '/' &&
+- con->uri.path->used > extension->key->used &&
+- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
++ buffer_string_length(con->uri.path) > buffer_string_length(extension->key) &&
++ NULL != (pathinfo = strchr(con->uri.path->ptr + buffer_string_length(extension->key), '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+-
+- con->uri.path->used -= con->request.pathinfo->used - 1;
+- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
++ buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - buffer_string_length(con->request.pathinfo));
+ }
+ }
+ }
+diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
+index 1c1a356..db041e2 100644
+--- a/src/mod_flv_streaming.c
++++ b/src/mod_flv_streaming.c
+@@ -136,13 +136,14 @@ static int mod_flv_streaming_patch_connection(server *srv, connection *con, plug
+
+ static int split_get_params(array *get_params, buffer *qrystr) {
+ size_t is_key = 1;
+- size_t i;
++ size_t i, len;
+ char *key = NULL, *val = NULL;
+
+ key = qrystr->ptr;
+
+ /* we need the \0 */
+- for (i = 0; i < qrystr->used; i++) {
++ len = buffer_string_length(qrystr);
++ for (i = 0; i <= len; i++) {
+ switch(qrystr->ptr[i]) {
+ case '=':
+ if (is_key) {
+@@ -195,14 +196,14 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+
+ mod_flv_streaming_patch_connection(srv, con, p);
+
+- s_len = con->physical.path->used - 1;
++ s_len = buffer_string_length(con->physical.path);
+
+ 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;
++ int ct_len = buffer_string_length(ds->value);
+
+ if (ct_len > s_len) continue;
+- if (ds->value->used == 0) continue;
++ if (buffer_is_empty(ds->value)) continue;
+
+ if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ data_string *get_param;
+@@ -221,7 +222,7 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+ }
+
+ /* too short */
+- if (get_param->value->used < 2) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(get_param->value)) return HANDLER_GO_ON;
+
+ /* check if it is a number */
+ start = strtol(get_param->value->ptr, &err, 10);
+diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
+index fe750c1..13d18e2 100644
+--- a/src/mod_indexfile.c
++++ b/src/mod_indexfile.c
+@@ -141,8 +141,8 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
+- if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
++ if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON;
+
+ mod_indexfile_patch_connection(srv, con, p);
+
+diff --git a/src/mod_magnet.c b/src/mod_magnet.c
+index 80cb799..8f89d4e 100644
+--- a/src/mod_magnet.c
++++ b/src/mod_magnet.c
+@@ -189,17 +189,12 @@ static int magnet_array_next(lua_State *L) {
+
+ if (pos >= a->used) return 0;
+ if (NULL != (du = a->data[pos])) {
+- if (du->key->used) {
+- lua_pushlstring(L, du->key->ptr, du->key->used - 1);
+- }
+- else {
+- lua_pushlstring(L, "", 0);
+- }
++ lua_pushlstring(L, CONST_BUF_LEN(du->key));
+ switch (du->type) {
+ case TYPE_STRING:
+ ds = (data_string *)du;
+- if (ds->value && ds->value->used) {
+- lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
++ if (!buffer_is_empty(ds->value)) {
++ lua_pushlstring(L, CONST_BUF_LEN(ds->value));
+ } else {
+ lua_pushnil(L);
+ }
+@@ -252,8 +247,9 @@ static int magnet_stat(lua_State *L) {
+ const char *s = luaL_checkstring(L, 1);
+ server *srv;
+ connection *con;
+- buffer sb;
++ buffer *sb;
+ stat_cache_entry *sce = NULL;
++ handler_t res;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+@@ -265,12 +261,12 @@ static int magnet_stat(lua_State *L) {
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+- sb.ptr = (char *)s;
+- sb.used = sb.size = strlen(s) + 1;
+-
+- if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) {
+- lua_pushnil(L);
++ sb = buffer_init_string(s);
++ res = stat_cache_get_entry(srv, con, sb, &sce);
++ buffer_free(sb);
+
++ if (HANDLER_GO_ON != res) {
++ lua_pushnil(L);
+ return 1;
+ }
+
+@@ -324,7 +320,7 @@ static int magnet_stat(lua_State *L) {
+ buffer *b = buffer_init();
+ etag_mutate(b, sce->etag);
+
+- lua_pushlstring(L, b->ptr, b->used - 1);
++ lua_pushlstring(L, CONST_BUF_LEN(b));
+ buffer_free(b);
+ } else {
+ lua_pushnil(L);
+@@ -332,7 +328,7 @@ static int magnet_stat(lua_State *L) {
+ lua_setfield(L, -2, "etag");
+
+ if (!buffer_string_is_empty(sce->content_type)) {
+- lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1);
++ lua_pushlstring(L, CONST_BUF_LEN(sce->content_type));
+ } else {
+ lua_pushnil(L);
+ }
+@@ -369,8 +365,8 @@ static int magnet_reqhdr_get(lua_State *L) {
+ lua_pop(L, 1);
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) {
+- if (ds->value->used) {
+- lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
++ if (!buffer_is_empty(ds->value)) {
++ lua_pushlstring(L, CONST_BUF_LEN(ds->value));
+ } else {
+ lua_pushnil(L);
+ }
+@@ -555,8 +551,8 @@ static int magnet_env_get(lua_State *L) {
+
+ dest = magnet_env_get_buffer(srv, con, key);
+
+- if (dest && dest->used) {
+- lua_pushlstring(L, dest->ptr, dest->used - 1);
++ if (!buffer_is_empty(dest)) {
++ lua_pushlstring(L, CONST_BUF_LEN(dest));
+ } else {
+ lua_pushnil(L);
+ }
+@@ -617,8 +613,8 @@ static int magnet_env_next(lua_State *L) {
+ lua_pushstring(L, magnet_env[pos].name);
+
+ dest = magnet_env_get_buffer_by_id(srv, con, magnet_env[pos].type);
+- if (dest && dest->used) {
+- lua_pushlstring(L, dest->ptr, dest->used - 1);
++ if (!buffer_is_empty(dest)) {
++ lua_pushlstring(L, CONST_BUF_LEN(dest));
+ } else {
+ lua_pushnil(L);
+ }
+@@ -649,7 +645,8 @@ static int magnet_cgi_get(lua_State *L) {
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+- if (NULL != (ds = (data_string *)array_get_element(con->environment, key)) && ds->value->used)
++ ds = (data_string *)array_get_element(con->environment, key);
++ if (!buffer_is_empty(ds->value))
+ lua_pushlstring(L, CONST_BUF_LEN(ds->value));
+ else
+ lua_pushnil(L);
+diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
+index 7d679fb..21260d5 100644
+--- a/src/mod_mysql_vhost.c
++++ b/src/mod_mysql_vhost.c
+@@ -25,10 +25,6 @@
+ * for domain to directory lookups,
+ * i.e virtual hosts (vhosts).
+ *
+- * Optionally sets fcgi_offset and fcgi_arg
+- * in preparation for fcgi.c to handle
+- * per-user fcgi chroot jails.
+- *
+ * /ada@riksnet.se 2004-12-06
+ */
+
+@@ -63,8 +59,6 @@ typedef struct {
+ typedef struct {
+ buffer *server_name;
+ buffer *document_root;
+- buffer *fcgi_arg;
+- unsigned fcgi_offset;
+ } plugin_connection_data;
+
+ /* init the plugin data */
+@@ -136,8 +130,6 @@ static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void
+
+ c->server_name = buffer_init();
+ c->document_root = buffer_init();
+- c->fcgi_arg = buffer_init();
+- c->fcgi_offset = 0;
+
+ return con->plugin_ctx[p->id] = c;
+ }
+@@ -158,8 +150,6 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
+
+ buffer_free(c->server_name);
+ buffer_free(c->document_root);
+- buffer_free(c->fcgi_arg);
+- c->fcgi_offset = 0;
+
+ free(c);
+
+@@ -222,7 +212,7 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
+ s->mysql_pre = buffer_init();
+ s->mysql_post = buffer_init();
+
+- if (sel->used && (qmark = strchr(sel->ptr, '?'))) {
++ if (!buffer_string_is_empty(sel) && (qmark = strchr(sel->ptr, '?'))) {
+ *qmark = '\0';
+ buffer_copy_string(s->mysql_pre, sel->ptr);
+ buffer_copy_string(s->mysql_post, qmark+1);
+@@ -258,7 +248,7 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
+ mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
+ #endif
+
+-#define FOO(x) (s->x->used ? s->x->ptr : NULL)
++#define FOO(x) (buffer_string_is_empty(s->x) ? NULL : s->x->ptr)
+
+ #if MYSQL_VERSION_ID >= 40100
+ /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
+@@ -334,37 +324,35 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+ MYSQL_RES *result = NULL;
+
+ /* no host specified? */
+- if (!con->uri.authority->used) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
+
+ mod_mysql_vhost_patch_connection(srv, con, p);
+
+ if (!p->conf.mysql) return HANDLER_GO_ON;
+- if (0 == p->conf.mysql_pre->used) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(p->conf.mysql_pre)) return HANDLER_GO_ON;
+
+ /* sets up connection data if not done yet */
+ c = mod_mysql_vhost_connection_data(srv, con, p_d);
+
+ /* check if cached this connection */
+- if (c->server_name->used && /* con->uri.authority->used && */
+- buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
++ if (buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
+
+ /* build and run SQL query */
+ buffer_copy_buffer(p->tmp_buf, p->conf.mysql_pre);
+- if (p->conf.mysql_post->used) {
++ if (!buffer_is_empty(p->conf.mysql_post)) {
+ /* escape the uri.authority */
+ unsigned long to_len;
+
+- /* 'to' has to be 'from_len * 2 + 1' */
+- buffer_string_prepare_append(p->tmp_buf, (con->uri.authority->used - 1) * 2 + 1);
++ buffer_string_prepare_append(p->tmp_buf, buffer_string_length(con->uri.authority) * 2);
+
+ to_len = mysql_real_escape_string(p->conf.mysql,
+- p->tmp_buf->ptr + p->tmp_buf->used - 1,
+- con->uri.authority->ptr, con->uri.authority->used - 1);
+- p->tmp_buf->used += to_len;
++ p->tmp_buf->ptr + buffer_string_length(p->tmp_buf),
++ CONST_BUF_LEN(con->uri.authority));
++ buffer_commit(p->tmp_buf, to_len);
+
+ buffer_append_string_buffer(p->tmp_buf, p->conf.mysql_post);
+ }
+- if (mysql_real_query(p->conf.mysql, p->tmp_buf->ptr, p->tmp_buf->used - 1)) {
++ if (mysql_real_query(p->conf.mysql, CONST_BUF_LEN(p->tmp_buf))) {
+ log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
+ goto ERR500;
+ }
+@@ -397,18 +385,6 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+ buffer_copy_buffer(c->server_name, con->uri.authority);
+ buffer_copy_buffer(c->document_root, p->tmp_buf);
+
+- /* fcgi_offset and fcgi_arg are optional */
+- if (cols > 1 && row[1]) {
+- c->fcgi_offset = atoi(row[1]);
+-
+- if (cols > 2 && row[2]) {
+- buffer_copy_string(c->fcgi_arg, row[2]);
+- } else {
+- c->fcgi_arg->used = 0;
+- }
+- } else {
+- c->fcgi_offset = c->fcgi_arg->used = 0;
+- }
+ mysql_free_result(result);
+ #if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+@@ -420,10 +396,9 @@ GO_ON:
+ buffer_copy_buffer(con->physical.doc_root, c->document_root);
+
+ #ifdef DEBUG
+- log_error_write(srv, __FILE__, __LINE__, "sbbdb",
++ log_error_write(srv, __FILE__, __LINE__, "sbb",
+ result ? "NOT CACHED" : "cached",
+- con->server_name, con->physical.doc_root,
+- c->fcgi_offset, c->fcgi_arg);
++ con->server_name, con->physical.doc_root);
+ #endif
+ return HANDLER_GO_ON;
+
+diff --git a/src/mod_proxy.c b/src/mod_proxy.c
+index fc2ca1a..dfdc636 100644
+--- a/src/mod_proxy.c
++++ b/src/mod_proxy.c
+@@ -472,7 +472,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
+
+ ds = (data_string *)con->request.headers->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
+ if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;
+
+@@ -485,7 +485,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+
+- hctx->wb->bytes_in += b->used - 1;
++ hctx->wb->bytes_in += buffer_string_length(b);
+ chunkqueue_append_buffer(hctx->wb, b);
+ buffer_free(b);
+
+@@ -620,7 +620,7 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+- "proxy - have to read:", b);
++ "proxy - have to read:", b);
+ }
+
+ if (b > 0) {
+@@ -637,8 +637,7 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+ /* this should be catched by the b > 0 above */
+ force_assert(r);
+
+- hctx->response->used += r;
+- hctx->response->ptr[hctx->response->used - 1] = '\0';
++ buffer_commit(hctx->response, r);
+
+ #if 0
+ log_error_write(srv, __FILE__, __LINE__, "sdsbs",
+@@ -656,7 +655,7 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+ /* search for the \r\n\r\n in the string */
+ if (NULL != (c = buffer_search_string_len(hctx->response, CONST_STR_LEN("\r\n\r\n")))) {
+ size_t hlen = c - hctx->response->ptr + 4;
+- size_t blen = hctx->response->used - hlen - 1;
++ size_t blen = buffer_string_length(hctx->response) - hlen;
+ /* found */
+
+ buffer_append_string_len(hctx->response_header, hctx->response->ptr, hlen);
+@@ -674,13 +673,13 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+
+ con->file_started = 1;
+ if (blen > 0) http_chunk_append_mem(srv, con, c + 4, blen);
+- hctx->response->used = 0;
++ buffer_reset(hctx->response);
+ joblist_append(srv, con);
+ }
+ } else {
+ http_chunk_append_buffer(srv, con, hctx->response);
+ joblist_append(srv, con);
+- hctx->response->used = 0;
++ buffer_reset(hctx->response);
+ }
+
+ } else {
+@@ -703,8 +702,7 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
+
+ int ret;
+
+- if (!host ||
+- (!host->host->used || !host->port)) return -1;
++ if (!host || buffer_string_is_empty(host->host) || !host->port) return -1;
+
+ switch(hctx->state) {
+ case PROXY_STATE_CONNECT:
+@@ -721,17 +719,17 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
+ case PROXY_STATE_INIT:
+ #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+ if (strstr(host->host->ptr,":")) {
+- if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
+- log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
+- return HANDLER_ERROR;
+- }
++ if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
++ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
++ return HANDLER_ERROR;
++ }
+ } else
+ #endif
+ {
+- if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
+- log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
+- return HANDLER_ERROR;
+- }
++ if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
++ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
++ return HANDLER_ERROR;
++ }
+ }
+ hctx->fde_ndx = -1;
+
+@@ -1078,13 +1076,8 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
+ mod_proxy_patch_connection(srv, con, p);
+
+ fn = con->uri.path;
+-
+- if (fn->used == 0) {
+- return HANDLER_ERROR;
+- }
+-
+- s_len = fn->used - 1;
+-
++ if (buffer_string_is_empty(fn)) return HANDLER_ERROR;
++ s_len = buffer_string_length(fn);
+
+ path_info_offset = 0;
+
+@@ -1099,9 +1092,9 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
+
+ ext = (data_array *)p->conf.extensions->data[k];
+
+- if (ext->key->used == 0) continue;
++ if (buffer_is_empty(ext->key)) continue;
+
+- ct_len = ext->key->used - 1;
++ ct_len = buffer_string_length(ext->key);
+
+ if (s_len < ct_len) continue;
+
+diff --git a/src/mod_redirect.c b/src/mod_redirect.c
+index 93cecb7..615c7db 100644
+--- a/src/mod_redirect.c
++++ b/src/mod_redirect.c
+@@ -198,9 +198,9 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
+ match = kv->key;
+ extra = kv->key_extra;
+ pattern = kv->value->ptr;
+- pattern_len = kv->value->used - 1;
++ pattern_len = buffer_string_length(kv->value);
+
+- if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
++ if ((n = pcre_exec(match, extra, CONST_BUF_LEN(p->match_buf), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching: ", n);
+diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
+index 48c0987..5191a64 100644
+--- a/src/mod_rewrite.c
++++ b/src/mod_rewrite.c
+@@ -372,9 +372,9 @@ static int process_rewrite_rules(server *srv, connection *con, plugin_data *p, r
+
+ match = rule->key;
+ pattern = rule->value->ptr;
+- pattern_len = rule->value->used - 1;
++ pattern_len = buffer_string_length(rule->value);
+
+- if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
++ if ((n = pcre_exec(match, NULL, CONST_BUF_LEN(p->match_buf), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching: ", n);
+diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
+index 5eb0d9d..0532e4d 100644
+--- a/src/mod_rrdtool.c
++++ b/src/mod_rrdtool.c
+@@ -264,7 +264,7 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s)
+ "RRA:MIN:0.5:24:775 "
+ "RRA:MIN:0.5:288:797\n"));
+
+- if (-1 == (safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
++ if (-1 == (safe_write(p->write_fd, CONST_BUF_LEN(p->cmd)))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-write: failed", strerror(errno));
+
+@@ -279,8 +279,7 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s)
+ return HANDLER_ERROR;
+ }
+
+- p->resp->used = r;
+- p->resp->ptr[p->resp->used++] = '\0';
++ buffer_commit(p->resp, r);
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+@@ -426,7 +425,7 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ buffer_append_int(p->cmd, s->requests);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN("\n"));
+
+- if (-1 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
++ if (-1 == (r = safe_write(p->write_fd, CONST_BUF_LEN(p->cmd)))) {
+ p->rrdtool_running = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+@@ -435,7 +434,7 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ return HANDLER_ERROR;
+ }
+
+- buffer_string_prepare_copy(p->resp, 4096);
++ buffer_string_prepare_copy(p->resp, 4095);
+ if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size - 1))) {
+ p->rrdtool_running = 0;
+
+@@ -445,8 +444,7 @@ TRIGGER_FUNC(mod_rrd_trigger) {
+ return HANDLER_ERROR;
+ }
+
+- p->resp->used = r;
+- p->resp->ptr[p->resp->used++] = '\0';
++ buffer_commit(p->resp, r);
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+diff --git a/src/mod_scgi.c b/src/mod_scgi.c
+index 9ea16a4..9e88de3 100644
+--- a/src/mod_scgi.c
++++ b/src/mod_scgi.c
+@@ -664,19 +664,19 @@ static int scgi_spawn_connection(server *srv,
+
+ #ifdef HAVE_SYS_UN_H
+ scgi_addr_un.sun_family = AF_UNIX;
+- if (proc->socket->used > sizeof(scgi_addr_un.sun_path)) {
++ if (buffer_string_length(proc->socket) + 1 > sizeof(scgi_addr_un.sun_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sB",
+ "ERROR: Unix Domain socket filename too long:",
+ proc->socket);
+ return -1;
+ }
+- memcpy(scgi_addr_un.sun_path, proc->socket->ptr, proc->socket->used);
++ memcpy(scgi_addr_un.sun_path, proc->socket->ptr, buffer_string_length(proc->socket) + 1);
+
+ #ifdef SUN_LEN
+ servlen = SUN_LEN(&scgi_addr_un);
+ #else
+ /* stevens says: */
+- servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
++ servlen = buffer_string_length(proc->socket) + 1 + sizeof(scgi_addr_un.sun_family);
+ #endif
+ socket_type = AF_UNIX;
+ scgi_addr = (struct sockaddr *) &scgi_addr_un;
+@@ -1072,7 +1072,7 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ /* unix domain socket */
+ struct sockaddr_un un;
+
+- if (df->unixsocket->used > sizeof(un.sun_path) - 2) {
++ if (buffer_string_length(df->unixsocket) + 1 > sizeof(un.sun_path) - 2) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "path of the unixdomain socket is too large");
+ goto error;
+@@ -1338,19 +1338,19 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
+ #ifdef HAVE_SYS_UN_H
+ /* use the unix domain socket */
+ scgi_addr_un.sun_family = AF_UNIX;
+- if (proc->socket->used > sizeof(scgi_addr_un.sun_path)) {
++ if (buffer_string_length(proc->socket) + 1 > sizeof(scgi_addr_un.sun_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sB",
+ "ERROR: Unix Domain socket filename too long:",
+ proc->socket);
+ return -1;
+ }
+- memcpy(scgi_addr_un.sun_path, proc->socket->ptr, proc->socket->used);
++ memcpy(scgi_addr_un.sun_path, proc->socket->ptr, buffer_string_length(proc->socket) + 1);
+
+ #ifdef SUN_LEN
+ servlen = SUN_LEN(&scgi_addr_un);
+ #else
+ /* stevens says: */
+- servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
++ servlen = buffer_string_length(proc->socket) + 1 + sizeof(scgi_addr_un.sun_family);
+ #endif
+ scgi_addr = (struct sockaddr *) &scgi_addr_un;
+ #else
+@@ -1416,7 +1416,7 @@ static int scgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+
+ ds = (data_string *)con->request.headers->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
+
+ scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
+@@ -1428,7 +1428,7 @@ static int scgi_env_add_request_headers(server *srv, connection *con, plugin_dat
+
+ ds = (data_string *)con->environment->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
+@@ -1471,8 +1471,8 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
+ }
+
+- if (con->server_name->used) {
+- size_t len = con->server_name->used - 1;
++ if (!buffer_is_empty(con->server_name)) {
++ size_t len = buffer_string_length(con->server_name);
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+@@ -1611,7 +1611,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
+ buffer_append_string_buffer(b, p->scgi_env);
+ buffer_append_string_len(b, CONST_STR_LEN(","));
+
+- hctx->wb->bytes_in += b->used - 1;
++ hctx->wb->bytes_in += buffer_string_length(b);
+ chunkqueue_append_buffer(hctx->wb, b);
+ buffer_free(b);
+
+@@ -1757,8 +1757,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ return 1;
+ }
+
+- hctx->response->ptr[n] = '\0';
+- hctx->response->used = n+1;
++ buffer_commit(hctx->response, n);
+
+ /* split header from body */
+
+@@ -1776,7 +1775,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
+
+ /* search for the \r\n\r\n or \n\n in the string */
+- for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
++ for (c = hctx->response_header->ptr, cp = 0, used = buffer_string_length(hctx->response_header); used; c++, cp++, used--) {
+ if (*c == ':') in_header = 1;
+ else if (*c == '\n') {
+ if (in_header == 0) {
+@@ -1832,11 +1831,10 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ http_chunk_append_buffer(srv, con, hctx->response_header);
+ joblist_append(srv, con);
+ } else {
+- size_t blen = hctx->response_header->used - hlen - 1;
++ size_t blen = buffer_string_length(hctx->response_header) - hlen;
+
+ /* a small hack: terminate after at the second \r */
+- hctx->response_header->used = hlen;
+- hctx->response_header->ptr[hlen - 1] = '\0';
++ buffer_string_set_length(hctx->response_header, hlen - 1);
+
+ /* parse the response header */
+ scgi_response_parse(srv, con, p, hctx->response_header, eol);
+@@ -1847,7 +1845,7 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
+ con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
+ }
+
+- if ((hctx->response->used != hlen) && blen > 0) {
++ if (blen > 0) {
+ http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen);
+ joblist_append(srv, con);
+ }
+@@ -2110,20 +2108,20 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");
+ return HANDLER_ERROR;
+ }
+- if (((!host->host->used || !host->port) && !host->unixsocket->used)) {
++ if (((buffer_string_is_empty(host->host) || !host->port) && buffer_string_is_empty(host->unixsocket))) {
+ log_error_write(srv, __FILE__, __LINE__, "sxddd",
+ "write-req: error",
+ host,
+- host->host->used,
++ buffer_string_length(host->host),
+ host->port,
+- host->unixsocket->used);
++ buffer_string_length(host->unixsocket));
+ return HANDLER_ERROR;
+ }
+
+
+ switch(hctx->state) {
+ case FCGI_STATE_INIT:
+- ret = host->unixsocket->used ? AF_UNIX : AF_INET;
++ ret = buffer_string_is_empty(host->unixsocket) ? AF_INET : AF_UNIX;
+
+ if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
+ if (errno == EMFILE ||
+@@ -2653,7 +2651,7 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
+
+ if (buffer_string_is_empty(fn)) return HANDLER_GO_ON;
+
+- s_len = fn->used - 1;
++ s_len = buffer_string_length(fn);
+
+ scgi_patch_connection(srv, con, p);
+
+@@ -2662,9 +2660,9 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
+ size_t ct_len;
+ scgi_extension *ext = p->conf.exts->exts[k];
+
+- if (ext->key->used == 0) continue;
++ if (buffer_is_empty(ext->key)) continue;
+
+- ct_len = ext->key->used - 1;
++ ct_len = buffer_string_length(ext->key);
+
+ if (s_len < ct_len) continue;
+
+@@ -2778,17 +2776,14 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
+ /* the rewrite is only done for /prefix/? matches */
+ if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {
+ buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);
+- con->uri.path->used = 1;
+- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
++ buffer_string_set_length(con->uri.path, 0);
+ } else if (extension->key->ptr[0] == '/' &&
+- con->uri.path->used > extension->key->used &&
+- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
++ buffer_string_length(con->uri.path) > buffer_string_length(extension->key) &&
++ NULL != (pathinfo = strchr(con->uri.path->ptr + buffer_string_length(extension->key), '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+-
+- con->uri.path->used -= con->request.pathinfo->used - 1;
+- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
++ buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - buffer_string_length(con->request.pathinfo));
+ }
+ }
+ } else {
+diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
+index d94482e..da98b61 100644
+--- a/src/mod_secure_download.c
++++ b/src/mod_secure_download.c
+@@ -198,7 +198,7 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_secdownload_patch_connection(srv, con, p);
+
+@@ -220,9 +220,9 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+ * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
+ */
+
+- if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
++ if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, buffer_string_length(p->conf.uri_prefix))) return HANDLER_GO_ON;
+
+- md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
++ md5_str = con->uri.path->ptr + buffer_string_length(p->conf.uri_prefix);
+
+ if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
+ if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
+@@ -255,10 +255,9 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+ buffer_copy_buffer(p->md5, p->conf.secret);
+ buffer_append_string(p->md5, rel_uri);
+ buffer_append_string_len(p->md5, ts_str, 8);
+- force_assert(p->md5->used > 0);
+
+ li_MD5_Init(&Md5Ctx);
+- li_MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
++ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(p->md5));
+ li_MD5_Final(HA1, &Md5Ctx);
+
+ buffer_copy_string_hex(p->md5, (char *)HA1, 16);
+diff --git a/src/mod_simple_vhost.c b/src/mod_simple_vhost.c
+index 6bb850f..fec8d54 100644
+--- a/src/mod_simple_vhost.c
++++ b/src/mod_simple_vhost.c
+@@ -124,12 +124,12 @@ SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
+
+ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
+ stat_cache_entry *sce = NULL;
+- force_assert(p->conf.server_root->used > 1);
++ force_assert(!buffer_string_is_empty(p->conf.server_root));
+
+ buffer_string_prepare_copy(out, 127);
+ buffer_copy_buffer(out, p->conf.server_root);
+
+- if (host->used) {
++ if (!buffer_string_is_empty(host)) {
+ /* a hostname has to start with a alpha-numerical character
+ * and must not contain a slash "/"
+ */
+@@ -145,8 +145,8 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
+ }
+ buffer_append_slash(out);
+
+- if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
+- buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
++ if (buffer_string_length(p->conf.document_root) > 1 && p->conf.document_root->ptr[0] == '/') {
++ buffer_append_string_len(out, p->conf.document_root->ptr + 1, buffer_string_length(p->conf.document_root) - 1);
+ } else {
+ buffer_append_string_buffer(out, p->conf.document_root);
+ buffer_append_slash(out);
+@@ -227,17 +227,17 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_
+ /* build_doc_root() requires a server_root; skip module if simple-vhost.server-root is not set
+ * or set to an empty string (especially don't cache any results!)
+ */
+- if (p->conf.server_root->used < 2) return HANDLER_GO_ON;
++ if (buffer_string_is_empty(p->conf.server_root)) return HANDLER_GO_ON;
+
+- if (p->conf.docroot_cache_key->used &&
+- con->uri.authority->used &&
++ if (!buffer_string_is_empty(p->conf.docroot_cache_key) &&
++ !buffer_string_is_empty(con->uri.authority) &&
+ buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
+ /* cache hit */
+ buffer_copy_buffer(con->server_name, p->conf.docroot_cache_servername);
+ buffer_copy_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
+ } else {
+ /* build document-root */
+- if ((con->uri.authority->used == 0) ||
++ if (buffer_string_is_empty(con->uri.authority) ||
+ build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
+ /* not found, fallback the default-host */
+ if (0 == build_doc_root(srv, con, p,
+diff --git a/src/mod_ssi.c b/src/mod_ssi.c
+index 981fd76..ed3b75c 100644
+--- a/src/mod_ssi.c
++++ b/src/mod_ssi.c
+@@ -172,7 +172,7 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
+
+ ds = (data_string *)con->request.headers->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ /* don't forward the Authorization: Header */
+ if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
+ continue;
+@@ -189,7 +189,7 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
+
+ ds = (data_string *)con->environment->data[i];
+
+- if (ds->value->used && ds->key->used) {
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
+
+ ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
+@@ -264,7 +264,7 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
+ * parameter.
+ */
+
+- if (con->request.pathinfo->used) {
++ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
+ }
+
+@@ -272,7 +272,7 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
+
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
+- ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
++ ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), buffer_is_empty(con->uri.query) ? "" : con->uri.query->ptr);
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
+@@ -1029,7 +1029,7 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
+ con->file_finished = 1;
+ con->mode = p->id;
+
+- if (p->conf.content_type->used <= 1) {
++ if (buffer_string_is_empty(p->conf.content_type)) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type));
+@@ -1100,16 +1100,16 @@ URIHANDLER_FUNC(mod_ssi_physical_path) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (con->physical.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_ssi_patch_connection(srv, con, p);
+
+ for (k = 0; k < p->conf.ssi_extension->used; k++) {
+ data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
+
+- if (ds->value->used == 0) continue;
++ if (buffer_is_empty(ds->value)) continue;
+
+- if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
++ if (buffer_is_equal_right_len(con->physical.path, ds->value, buffer_string_length(ds->value))) {
+ /* handle ssi-request */
+
+ if (mod_ssi_handle_request(srv, con, p)) {
+diff --git a/src/mod_ssi_expr.c b/src/mod_ssi_expr.c
+index 140d086..489fde4 100644
+--- a/src/mod_ssi_expr.c
++++ b/src/mod_ssi_expr.c
+@@ -35,7 +35,7 @@ void ssi_val_free(ssi_val_t *s) {
+
+ int ssi_val_tobool(ssi_val_t *B) {
+ if (B->type == SSI_TYPE_STRING) {
+- return B->str->used > 1 ? 1 : 0;
++ return !buffer_string_is_empty(B->str);
+ } else {
+ return B->bo;
+ }
+diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
+index e36c697..d40aa31 100644
+--- a/src/mod_staticfile.c
++++ b/src/mod_staticfile.c
+@@ -304,7 +304,7 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+ /* write END-OF-HEADER */
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+- con->response.content_length += b->used - 1;
++ con->response.content_length += buffer_string_length(b);
+ chunkqueue_append_buffer(con->write_queue, b);
+ buffer_free(b);
+ }
+@@ -325,7 +325,7 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
+ buffer_append_string(b, boundary);
+ buffer_append_string_len(b, "--\r\n", 4);
+
+- con->response.content_length += b->used - 1;
++ con->response.content_length += buffer_string_length(b);
+ chunkqueue_append_buffer(con->write_queue, b);
+ buffer_free(b);
+
+@@ -363,8 +363,8 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
+
+ /* someone else has done a decision for us */
+ if (con->http_status != 0) return HANDLER_GO_ON;
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
+- if (con->physical.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ /* someone else has handled this request */
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+@@ -381,7 +381,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
+
+ mod_staticfile_patch_connection(srv, con, p);
+
+- if (p->conf.disable_pathinfo && 0 != con->request.pathinfo->used) {
++ if (p->conf.disable_pathinfo && !buffer_string_is_empty(con->request.pathinfo)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, pathinfo forbidden");
+ }
+@@ -392,9 +392,9 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
+ for (k = 0; k < p->conf.exclude_ext->used; k++) {
+ ds = (data_string *)p->conf.exclude_ext->data[k];
+
+- if (ds->value->used == 0) continue;
++ if (buffer_is_empty(ds->value)) continue;
+
+- if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
++ if (buffer_is_equal_right_len(con->physical.path, ds->value, buffer_string_length(ds->value))) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, extension forbidden");
+ }
+diff --git a/src/mod_status.c b/src/mod_status.c
+index 99b332a..daecb08 100644
+--- a/src/mod_status.c
++++ b/src/mod_status.c
+@@ -449,7 +449,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+ connection *c = srv->conns->ptr[j];
+ const char *state;
+
+- if (CON_STATE_READ == c->state && c->request.orig_uri->used > 0) {
++ if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri)) {
+ state = "k";
+ } else {
+ state = connection_get_short_state(c->state);
+@@ -501,7 +501,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+- if (CON_STATE_READ == c->state && c->request.orig_uri->used > 0) {
++ if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri)) {
+ buffer_append_string_len(b, CONST_STR_LEN("keep-alive"));
+ } else {
+ buffer_append_string(b, connection_get_state(c->state));
+diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c
+index cff125c..e1fa993 100644
+--- a/src/mod_trigger_b4_dl.c
++++ b/src/mod_trigger_b4_dl.c
+@@ -320,7 +320,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_trigger_b4_dl_patch_connection(srv, con, p);
+
+@@ -356,7 +356,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+ }
+
+ /* check if URL is a trigger -> insert IP into DB */
+- if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
++ if ((n = pcre_exec(p->conf.trigger_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching:", n);
+@@ -383,11 +383,12 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+ # endif
+ # if defined(HAVE_MEMCACHE_H)
+ if (p->conf.mc) {
+- size_t i;
++ size_t i, len;
+ buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
+ buffer_append_string(p->tmp_buf, remote_ip);
+
+- for (i = 0; i < p->tmp_buf->used - 1; i++) {
++ len = buffer_string_length(p->tmp_buf);
++ for (i = 0; i < len; i++) {
+ if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
+ }
+
+@@ -407,7 +408,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+ }
+
+ /* check if URL is a download -> check IP in DB, update timestamp */
+- if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
++ if ((n = pcre_exec(p->conf.download_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching: ", n);
+@@ -469,12 +470,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+ # if defined(HAVE_MEMCACHE_H)
+ if (p->conf.mc) {
+ void *r;
+- size_t i;
++ size_t i, len;
+
+ buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
+ buffer_append_string(p->tmp_buf, remote_ip);
+
+- for (i = 0; i < p->tmp_buf->used - 1; i++) {
++ len = buffer_string_length(p->tmp_buf);
++ for (i = 0; i < len; i++) {
+ if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
+ }
+
+diff --git a/src/mod_userdir.c b/src/mod_userdir.c
+index 392f4b2..682f950 100644
+--- a/src/mod_userdir.c
++++ b/src/mod_userdir.c
+@@ -181,14 +181,14 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+ struct passwd *pwd = NULL;
+ #endif
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_userdir_patch_connection(srv, con, p);
+
+ /* enforce the userdir.path to be set in the config, ugly fix for #1587;
+ * should be replaced with a clean .enabled option in 1.5
+ */
+- if (!p->conf.active || p->conf.path->used == 0) return HANDLER_GO_ON;
++ if (!p->conf.active || buffer_is_empty(p->conf.path)) return HANDLER_GO_ON;
+
+ /* /~user/foo.html -> /home/user/public_html/foo.html */
+
+diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c
+index 29e9fdf..11aad95 100644
+--- a/src/mod_usertrack.c
++++ b/src/mod_usertrack.c
+@@ -101,8 +101,8 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
+ if (buffer_string_is_empty(s->cookie_name)) {
+ buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
+ } else {
+- size_t j;
+- for (j = 0; j < s->cookie_name->used - 1; j++) {
++ size_t j, len = buffer_string_length(s->cookie_name);
++ for (j = 0; j < len; j++) {
+ char c = s->cookie_name->ptr[j] | 32;
+ if (c < 'a' || c > 'z') {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+@@ -115,8 +115,8 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
+ }
+
+ if (!buffer_string_is_empty(s->cookie_domain)) {
+- size_t j;
+- for (j = 0; j < s->cookie_domain->used - 1; j++) {
++ size_t j, len = buffer_string_length(s->cookie_domain);
++ for (j = 0; j < len; j++) {
+ char c = s->cookie_domain->ptr[j];
+ if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+@@ -175,7 +175,7 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ li_MD5_CTX Md5Ctx;
+ char hh[LI_ITOSTRING_LENGTH];
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_usertrack_patch_connection(srv, con, p);
+
+@@ -193,7 +193,7 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ char *nc;
+
+ /* skip WS */
+- for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
++ for (nc = g + buffer_string_length(p->conf.cookie_name); *nc == ' ' || *nc == '\t'; nc++);
+
+ if (*nc == '=') {
+ /* ok, found the key of our own cookie */
+@@ -219,8 +219,8 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+
+ /* generate shared-secret */
+ 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);
++ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(con->uri.path));
++ li_MD5_Update(&Md5Ctx, CONST_STR_LEN("+"));
+
+ /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
+ li_itostr(hh, srv->cur_ts);
+diff --git a/src/mod_webdav.c b/src/mod_webdav.c
+index 433b904..654108a 100644
+--- a/src/mod_webdav.c
++++ b/src/mod_webdav.c
+@@ -446,7 +446,7 @@ URIHANDLER_FUNC(mod_webdav_uri_handler) {
+
+ UNUSED(srv);
+
+- if (con->uri.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_webdav_patch_connection(srv, con, p);
+
+@@ -558,9 +558,8 @@ static int webdav_delete_file(server *srv, connection *con, plugin_data *p, phys
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+- dst->rel_path->ptr,
+- dst->rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(dst->rel_path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+@@ -590,7 +589,7 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
+ int status = 0;
+
+ if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
++ (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
+ continue;
+ /* ignore the parent dir */
+ }
+@@ -636,9 +635,8 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+- d.rel_path->ptr,
+- d.rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(d.rel_path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+@@ -714,14 +712,12 @@ static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physic
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+- dst->rel_path->ptr,
+- dst->rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(dst->rel_path),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+- src->rel_path->ptr,
+- src->rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(src->rel_path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+@@ -751,8 +747,8 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
+ while (NULL != (de = readdir(srcdir))) {
+ struct stat st;
+
+- if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
++ if ((de->d_name[0] == '.' && de->d_name[1] == '\0')
++ || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
+ continue;
+ }
+
+@@ -793,14 +789,12 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+- dst->rel_path->ptr,
+- dst->rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(dst->rel_path),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+- src->rel_path->ptr,
+- src->rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(src->rel_path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+@@ -851,9 +845,9 @@ static int webdav_get_live_property(server *srv, connection *con, plugin_data *p
+ for (k = 0; k < con->conf.mimetypes->used; k++) {
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+
+- if (ds->key->used == 0) continue;
++ if (buffer_is_empty(ds->key)) continue;
+
+- if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
++ if (buffer_is_equal_right_len(dst->path, ds->key, buffer_string_length(ds->key))) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontenttype>"));
+ buffer_append_string_buffer(b, ds->value);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
+@@ -907,17 +901,16 @@ static int webdav_get_property(server *srv, connection *con, plugin_data *p, phy
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+- dst->rel_path->ptr,
+- dst->rel_path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(dst->rel_path),
++ SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 2,
+- prop_name,
+- strlen(prop_name),
+- SQLITE_TRANSIENT);
++ prop_name,
++ strlen(prop_name),
++ SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 3,
+- prop_ns,
+- strlen(prop_ns),
+- SQLITE_TRANSIENT);
++ prop_ns,
++ strlen(prop_ns),
++ SQLITE_TRANSIENT);
+
+ /* it is the PK */
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+@@ -1046,7 +1039,7 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
+ break;
+ case MEM_CHUNK:
+ /* append to the buffer */
+- weHave = c->mem->used - 1 - c->offset;
++ weHave = buffer_string_length(c->mem) - c->offset;
+
+ if (weHave > weWant) weHave = weWant;
+
+@@ -1190,8 +1183,8 @@ static int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+- CONST_BUF_LEN(uri),
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(uri),
++ SQLITE_TRANSIENT);
+
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ has_lock = 0;
+@@ -1223,7 +1216,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ if (!p->conf.enabled) return HANDLER_GO_ON;
+ /* physical path is setup */
+- if (con->physical.path->used == 0) return HANDLER_GO_ON;
++ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ /* PROPFIND need them */
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Depth"))) {
+@@ -1274,7 +1267,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ if (prop->type == XML_TEXT_NODE) continue; /* ignore WS */
+
+ if (prop->ns &&
+- (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
++ (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
+ (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
+ size_t i;
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+@@ -1318,9 +1311,8 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+- con->uri.path->ptr,
+- con->uri.path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(con->uri.path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ }
+@@ -1757,7 +1749,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ }
+ break;
+ case MEM_CHUNK:
+- if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
++ if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
+ switch(errno) {
+ case ENOSPC:
+ con->http_status = 507;
+@@ -1810,7 +1802,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ }
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Overwrite"))) {
+- if (ds->value->used != 2 ||
++ if (buffer_string_length(ds->value) != 1 ||
+ (ds->value->ptr[0] != 'F' &&
+ ds->value->ptr[0] != 'T') ) {
+ con->http_status = 400;
+@@ -1884,7 +1876,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ /* don't add a second / */
+ if (p->physical.rel_path->ptr[0] == '/') {
+- buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
++ buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, buffer_string_length(p->physical.rel_path) - 1);
+ } else {
+ buffer_append_string_buffer(p->physical.path, p->physical.rel_path);
+ }
+@@ -1993,9 +1985,8 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+- con->uri.path->ptr,
+- con->uri.path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(con->uri.path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move(delete old) failed:", sqlite3_errmsg(p->conf.sql));
+@@ -2009,14 +2000,12 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+- p->uri.path->ptr,
+- p->uri.path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(p->uri.path),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+- con->uri.path->ptr,
+- con->uri.path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(con->uri.path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
+@@ -2121,29 +2110,28 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+- con->uri.path->ptr,
+- con->uri.path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(con->uri.path),
++ SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 2,
+- (char *)prop->name,
+- strlen((char *)prop->name),
+- SQLITE_TRANSIENT);
++ (char *)prop->name,
++ strlen((char *)prop->name),
++ SQLITE_TRANSIENT);
+ if (prop->ns) {
+ sqlite3_bind_text(stmt, 3,
+- (char *)prop->ns->href,
+- strlen((char *)prop->ns->href),
+- SQLITE_TRANSIENT);
++ (char *)prop->ns->href,
++ strlen((char *)prop->ns->href),
++ SQLITE_TRANSIENT);
+ } else {
+ sqlite3_bind_text(stmt, 3,
+- "",
+- 0,
+- SQLITE_TRANSIENT);
++ "",
++ 0,
++ SQLITE_TRANSIENT);
+ }
+ if (stmt == p->conf.stmt_update_prop) {
+ sqlite3_bind_text(stmt, 4,
+- (char *)xmlNodeGetContent(prop),
+- strlen((char *)xmlNodeGetContent(prop)),
+- SQLITE_TRANSIENT);
++ (char *)xmlNodeGetContent(prop),
++ strlen((char *)xmlNodeGetContent(prop)),
++ SQLITE_TRANSIENT);
+ }
+
+ if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
+@@ -2290,9 +2278,8 @@ propmatch_cleanup:
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+- p->uri.path->ptr,
+- p->uri.path->used - 1,
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(p->uri.path),
++ SQLITE_TRANSIENT);
+
+ /* it is the PK */
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+@@ -2339,32 +2326,32 @@ propmatch_cleanup:
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+- CONST_BUF_LEN(p->tmp_buf),
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(p->tmp_buf),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+- CONST_BUF_LEN(con->uri.path),
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(con->uri.path),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 3,
+- (const char *)lockscope,
+- xmlStrlen(lockscope),
+- SQLITE_TRANSIENT);
++ (const char *)lockscope,
++ xmlStrlen(lockscope),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 4,
+- (const char *)locktype,
+- xmlStrlen(locktype),
+- SQLITE_TRANSIENT);
++ (const char *)locktype,
++ xmlStrlen(locktype),
++ SQLITE_TRANSIENT);
+
+ /* owner */
+ sqlite3_bind_text(stmt, 5,
+- "",
+- 0,
+- SQLITE_TRANSIENT);
++ "",
++ 0,
++ SQLITE_TRANSIENT);
+
+ /* depth */
+ sqlite3_bind_int(stmt, 6,
+- depth);
++ depth);
+
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+@@ -2394,19 +2381,19 @@ propmatch_cleanup:
+ sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
+
+ /* remove the < > around the token */
+- if (locktoken->used < 6) {
++ if (buffer_string_length(locktoken) < 5) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+- buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
++ buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, buffer_string_length(locktoken) - 4);
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+- CONST_BUF_LEN(p->tmp_buf),
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(p->tmp_buf),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+@@ -2437,7 +2424,7 @@ propmatch_cleanup:
+ sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
+
+ /* remove the < > around the token */
+- if (locktoken->used < 4) {
++ if (buffer_string_length(locktoken) < 3) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+@@ -2453,17 +2440,17 @@ propmatch_cleanup:
+ * - 412
+ * */
+
+- buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
++ buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, buffer_string_length(locktoken) - 2);
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+- CONST_BUF_LEN(p->tmp_buf),
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(p->tmp_buf),
++ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+- CONST_BUF_LEN(con->uri.path),
+- SQLITE_TRANSIENT);
++ CONST_BUF_LEN(con->uri.path),
++ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c
+index 8d7598a..b967f3c 100644
+--- a/src/network_linux_sendfile.c
++++ b/src/network_linux_sendfile.c
+@@ -54,12 +54,12 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
+ tc = tc->next, num_chunks++);
+
+ for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
+- if (tc->mem->used == 0) {
++ if (buffer_string_is_empty(tc->mem)) {
+ chunks[i].iov_base = tc->mem->ptr;
+ chunks[i].iov_len = 0;
+ } else {
+ offset = tc->mem->ptr + tc->offset;
+- toSend = tc->mem->used - 1 - tc->offset;
++ toSend = buffer_string_length(tc->mem) - tc->offset;
+
+ chunks[i].iov_base = offset;
+
+diff --git a/src/network_openssl.c b/src/network_openssl.c
+index 04c29c0..d9ae33c 100644
+--- a/src/network_openssl.c
++++ b/src/network_openssl.c
+@@ -67,13 +67,13 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
+ off_t toSend;
+ ssize_t r;
+
+- if (c->mem->used == 0 || c->mem->used == 1) {
++ if (buffer_string_is_empty(c->mem)) {
+ chunk_finished = 1;
+ break;
+ }
+
+ offset = c->mem->ptr + c->offset;
+- toSend = c->mem->used - 1 - c->offset;
++ toSend = buffer_string_length(c->mem) - c->offset;
+ if (toSend > max_bytes) toSend = max_bytes;
+
+ /**
+@@ -149,7 +149,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
+ max_bytes -= r;
+ }
+
+- if (c->offset == (off_t)c->mem->used - 1) {
++ if (c->offset == (off_t)buffer_string_length(c->mem)) {
+ chunk_finished = 1;
+ }
+
+diff --git a/src/network_write.c b/src/network_write.c
+index d46649b..6a89b50 100644
+--- a/src/network_write.c
++++ b/src/network_write.c
+@@ -36,13 +36,13 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqu
+ off_t toSend;
+ ssize_t r;
+
+- if (c->mem->used == 0) {
++ if (buffer_string_is_empty(c->mem)) {
+ chunk_finished = 1;
+ break;
+ }
+
+ offset = c->mem->ptr + c->offset;
+- toSend = c->mem->used - 1 - c->offset;
++ toSend = buffer_string_length(c->mem) - c->offset;
+ if (toSend > max_bytes) toSend = max_bytes;
+
+ #ifdef __WIN32
+@@ -75,7 +75,7 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqu
+ cq->bytes_out += r;
+ max_bytes -= r;
+
+- if (c->offset == (off_t)c->mem->used - 1) {
++ if (c->offset == (off_t)buffer_string_length(c->mem)) {
+ chunk_finished = 1;
+ }
+
+diff --git a/src/network_writev.c b/src/network_writev.c
+index 1b93547..895336c 100644
+--- a/src/network_writev.c
++++ b/src/network_writev.c
+@@ -69,12 +69,12 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
+ chunks = calloc(num_chunks, sizeof(*chunks));
+
+ for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
+- if (tc->mem->used == 0) {
++ if (buffer_string_is_empty(tc->mem)) {
+ chunks[i].iov_base = tc->mem->ptr;
+ chunks[i].iov_len = 0;
+ } else {
+ offset = tc->mem->ptr + tc->offset;
+- toSend = tc->mem->used - 1 - tc->offset;
++ toSend = buffer_string_length(tc->mem) - tc->offset;
+
+ chunks[i].iov_base = offset;
+
+diff --git a/src/proc_open.c b/src/proc_open.c
+index c29b9c6..167027a 100644
+--- a/src/proc_open.c
++++ b/src/proc_open.c
+@@ -284,8 +284,7 @@ static void proc_read_fd_to_buffer(int fd, buffer *b) {
+ if ((s = read(fd, (void *)(b->ptr + buffer_string_length(b)), buffer_string_space(b))) <= 0) {
+ break;
+ }
+- b->used += s;
+- b->ptr[b->used-1] = '\0';
++ buffer_commit(b, s);
+ }
+ }
+ /* }}} */
+@@ -298,7 +297,7 @@ int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err)
+ }
+
+ if (in) {
+- if (write(proc.in.fd, (void *)in->ptr, in->used) < 0) {
++ if (write(proc.in.fd, CONST_BUF_LEN(in)) < 0) {
+ perror("error writing pipe");
+ return -1;
+ }
+@@ -315,7 +314,7 @@ int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err)
+ } else {
+ buffer *tmp = buffer_init();
+ proc_read_fd_to_buffer(proc.err.fd, tmp);
+- if (tmp->used > 0 && write(2, (void*)tmp->ptr, tmp->used) < 0) {
++ if (!buffer_string_is_empty(tmp) && write(2, CONST_BUF_LEN(tmp)) < 0) {
+ perror("error writing pipe");
+ buffer_free(tmp);
+ return -1;
+diff --git a/src/request.c b/src/request.c
+index 65d0a0e..993cb28 100644
+--- a/src/request.c
++++ b/src/request.c
+@@ -34,9 +34,9 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
+ */
+
+ /* no Host: */
+- if (!host || host->used == 0) return 0;
++ if (buffer_is_empty(host)) return 0;
+
+- host_len = host->used - 1;
++ host_len = buffer_string_length(host);
+
+ /* IPv6 adress */
+ if (host->ptr[0] == '[') {
+@@ -92,10 +92,9 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
+ /* if the hostname ends in a "." strip it */
+ if (host->ptr[host_len-1] == '.') {
+ /* shift port info one left */
+- if (NULL != colon) memmove(colon-1, colon, host->used - host_len);
+- else host->ptr[host_len-1] = '\0';
++ if (NULL != colon) memmove(colon-1, colon, buffer_string_length(host) - host_len);
++ buffer_string_set_length(host, buffer_string_length(host) - 1);
+ host_len -= 1;
+- host->used -= 1;
+ }
+
+ if (host_len == 0) return -1;
+@@ -213,7 +212,7 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
+ #endif
+
+ static int http_request_split_value(array *vals, buffer *b) {
+- size_t i;
++ size_t i, len;
+ int state = 0;
+
+ const char *current;
+@@ -226,10 +225,11 @@ static int http_request_split_value(array *vals, buffer *b) {
+ * into a array (more or less a explode() incl. striping of whitespaces
+ */
+
+- if (b->used == 0) return 0;
++ if (buffer_string_is_empty(b)) return 0;
+
+ current = b->ptr;
+- for (i = 0; i < b->used; ++i, ++current) {
++ len = buffer_string_length(b);
++ for (i = 0; i <= len; ++i, ++current) {
+ data_string *ds;
+
+ switch (state) {
+@@ -297,7 +297,7 @@ int http_request_parse(server *srv, connection *con) {
+ int line = 0;
+
+ int request_line_stage = 0;
+- size_t i, first;
++ size_t i, first, ilen;
+
+ int done = 0;
+
+@@ -310,7 +310,7 @@ int http_request_parse(server *srv, connection *con) {
+ if (con->conf.log_request_header) {
+ log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
+ "fd:", con->fd,
+- "request-len:", con->request.request->used,
++ "request-len:", buffer_string_length(con->request.request),
+ "\n", con->request.request);
+ }
+
+@@ -319,7 +319,7 @@ int http_request_parse(server *srv, connection *con) {
+ con->request.request->ptr[1] == '\n') {
+ /* we are in keep-alive and might get \r\n after a previous POST request.*/
+
+- buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
++ buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, buffer_string_length(con->request.request) - 2);
+ } else {
+ /* fill the local request buffer */
+ buffer_copy_buffer(con->parse_request, con->request.request);
+@@ -334,15 +334,14 @@ int http_request_parse(server *srv, connection *con) {
+ *
+ * <method> <uri> <protocol>\r\n
+ * */
+- for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
+- char *cur = con->parse_request->ptr + i;
+-
+- switch(*cur) {
++ ilen = buffer_string_length(con->parse_request);
++ for (i = 0, first = 0; i < ilen && line == 0; i++) {
++ switch(con->parse_request->ptr[i]) {
+ case '\r':
+ if (con->parse_request->ptr[i+1] == '\n') {
+ http_method_t r;
+ char *nuri = NULL;
+- size_t j;
++ size_t j, jlen;
+
+ /* \r\n -> \0\0 */
+ con->parse_request->ptr[i] = '\0';
+@@ -476,7 +475,8 @@ int http_request_parse(server *srv, connection *con) {
+ }
+
+ /* check uri for invalid characters */
+- for (j = 0; j < con->request.uri->used - 1; j++) {
++ jlen = buffer_string_length(con->request.uri);
++ for (j = 0; j < jlen; j++) {
+ if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
+ unsigned char buf[2];
+ con->http_status = 400;
+@@ -551,7 +551,7 @@ int http_request_parse(server *srv, connection *con) {
+
+ in_folding = 0;
+
+- if (con->request.uri->used == 1) {
++ if (buffer_string_is_empty(con->request.uri)) {
+ con->http_status = 400;
+ con->response.keep_alive = 0;
+ con->keep_alive = 0;
+@@ -579,7 +579,7 @@ int http_request_parse(server *srv, connection *con) {
+ con->request.http_host = ds->value;
+ }
+
+- for (; i < con->parse_request->used && !done; i++) {
++ for (; i <= ilen && !done; i++) {
+ char *cur = con->parse_request->ptr + i;
+
+ if (is_key) {
+@@ -825,7 +825,7 @@ int http_request_parse(server *srv, connection *con) {
+ } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
+ char *err;
+ unsigned long int r;
+- size_t j;
++ size_t j, jlen;
+
+ if (con_length_set) {
+ con->http_status = 400;
+@@ -842,9 +842,8 @@ int http_request_parse(server *srv, connection *con) {
+ return 0;
+ }
+
+- if (ds->value->used == 0) SEGFAULT();
+-
+- for (j = 0; j < ds->value->used - 1; j++) {
++ jlen = buffer_string_length(ds->value);
++ for (j = 0; j < jlen; j++) {
+ char c = ds->value->ptr[j];
+ if (!isdigit((unsigned char)c)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+@@ -1177,9 +1176,9 @@ int http_request_parse(server *srv, connection *con) {
+ int http_request_header_finished(server *srv, connection *con) {
+ UNUSED(srv);
+
+- if (con->request.request->used < 5) return 0;
++ if (buffer_string_length(con->request.request) < 4) return 0;
+
+- if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
++ if (0 == memcmp(con->request.request->ptr + buffer_string_length(con->request.request) - 4, CONST_STR_LEN("\r\n\r\n"))) return 1;
+ if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
+
+ return 0;
+diff --git a/src/response.c b/src/response.c
+index 5072d05..357f43b 100644
+--- a/src/response.c
++++ b/src/response.c
+@@ -70,7 +70,7 @@ int http_response_write_header(server *srv, connection *con) {
+
+ ds = (data_string *)con->response.headers->data[i];
+
+- if (ds->value->used && ds->key->used &&
++ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key) &&
+ 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-")) &&
+ 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-Sendfile"))) {
+ if (0 == strcasecmp(ds->key->ptr, "Date")) have_date = 1;
+@@ -99,10 +99,7 @@ int http_response_write_header(server *srv, connection *con) {
+ if (srv->cur_ts != srv->last_generated_date_ts) {
+ buffer_string_prepare_copy(srv->ts_date_str, 255);
+
+- strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
+- "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
+-
+- srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
++ buffer_append_strftime(srv->ts_date_str, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
+
+ srv->last_generated_date_ts = srv->cur_ts;
+ }
+@@ -113,7 +110,7 @@ int http_response_write_header(server *srv, connection *con) {
+ if (!have_server) {
+ if (buffer_is_empty(con->conf.server_tag)) {
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_DESC));
+- } else if (con->conf.server_tag->used > 1) {
++ } else if (!buffer_string_is_empty(con->conf.server_tag)) {
+ 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);
+ }
+@@ -121,7 +118,7 @@ int http_response_write_header(server *srv, connection *con) {
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+- con->bytes_header = b->used - 1;
++ con->bytes_header = buffer_string_length(b);
+
+ if (con->conf.log_response_header) {
+ log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
+@@ -204,8 +201,7 @@ static void https_add_ssl_entries(connection *con) {
+ buffer_string_prepare_copy(envds->value, n);
+ BIO_read(bio, envds->value->ptr, n);
+ BIO_free(bio);
+- envds->value->ptr[n] = '\0';
+- envds->value->used = n+1;
++ buffer_commit(envds->value, n);
+ array_insert_unique(con->environment, (data_unset *)envds);
+ }
+ }
+@@ -229,7 +225,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ }
+
+ /* no decision yet, build conf->filename */
+- if (con->mode == DIRECT && con->physical.path->used == 0) {
++ if (con->mode == DIRECT && buffer_is_empty(con->physical.path)) {
+ char *qstr;
+
+ /* we only come here when we have the parse the full request again
+@@ -294,8 +290,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+
+ /** their might be a fragment which has to be cut away */
+ if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
+- con->request.uri->used = qstr - con->request.uri->ptr;
+- con->request.uri->ptr[con->request.uri->used++] = '\0';
++ buffer_string_set_length(con->request.uri, qstr - con->request.uri->ptr);
+ }
+
+ /** extract query string from request.uri */
+@@ -451,23 +446,18 @@ handler_t http_response_prepare(server *srv, connection *con) {
+
+ if (con->physical.rel_path->used > 1) {
+ buffer *b = con->physical.rel_path;
++ size_t len = buffer_string_length(b);
+ size_t i;
+
+- if (b->used > 2 &&
+- b->ptr[b->used-2] == '/' &&
+- (b->ptr[b->used-3] == ' ' ||
+- b->ptr[b->used-3] == '.')) {
+- b->ptr[b->used--] = '\0';
+- }
+-
+- for (i = b->used - 2; b->used > 1; i--) {
+- if (b->ptr[i] == ' ' ||
+- b->ptr[i] == '.') {
+- b->ptr[b->used--] = '\0';
+- } else {
+- break;
+- }
++ /* strip trailing " /" or "./" once */
++ if (len > 1 &&
++ b->ptr[len - 1] == '/' &&
++ (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) {
++ len -= 2;
+ }
++ /* strip all trailing " " and "." */
++ while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len;
++ buffer_string_set_length(b, len);
+ }
+ #endif
+
+@@ -515,9 +505,9 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ buffer_copy_buffer(con->physical.basedir, con->physical.doc_root);
+ buffer_copy_buffer(con->physical.path, con->physical.doc_root);
+ buffer_append_slash(con->physical.path);
+- if (con->physical.rel_path->used &&
++ if (!buffer_string_is_empty(con->physical.rel_path) &&
+ con->physical.rel_path->ptr[0] == '/') {
+- buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
++ buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, buffer_string_length(con->physical.rel_path) - 1);
+ } else {
+ buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
+ }
+@@ -589,7 +579,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ };
+ #endif
+ if (S_ISDIR(sce->st.st_mode)) {
+- if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
++ if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') {
+ /* redirect to .../ */
+
+ http_response_redirect_to_directory(srv, con);
+@@ -672,7 +662,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ }
+
+ 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) > (buffer_string_length(con->physical.basedir) - 1)));
+
+ if (found == 0) {
+ /* no it really doesn't exists */
+@@ -711,8 +701,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
+ * shorten uri.path
+ */
+
+- con->uri.path->used -= strlen(pathinfo);
+- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
++ buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - strlen(pathinfo));
+ }
+
+ if (con->conf.log_request_handling) {
+diff --git a/src/server.c b/src/server.c
+index 71d3538..5089375 100644
+--- a/src/server.c
++++ b/src/server.c
+@@ -666,7 +666,7 @@ int main (int argc, char **argv) {
+ #endif
+
+ /* check document-root */
+- if (srv->config_storage[0]->document_root->used <= 1) {
++ if (buffer_string_is_empty(srv->config_storage[0]->document_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "document-root is not set\n");
+
+@@ -686,7 +686,7 @@ int main (int argc, char **argv) {
+ }
+
+ /* open pid file BEFORE chroot */
+- if (srv->srvconf.pid_file->used) {
++ if (!buffer_string_is_empty(srv->srvconf.pid_file)) {
+ if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
+ struct stat st;
+ if (errno != EEXIST) {
+@@ -780,7 +780,7 @@ int main (int argc, char **argv) {
+
+ #ifdef HAVE_PWD_H
+ /* set user and group */
+- if (srv->srvconf.username->used) {
++ if (!buffer_string_is_empty(srv->srvconf.username)) {
+ if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "can't find username", srv->srvconf.username);
+@@ -794,7 +794,7 @@ int main (int argc, char **argv) {
+ }
+ }
+
+- if (srv->srvconf.groupname->used) {
++ if (!buffer_string_is_empty(srv->srvconf.groupname)) {
+ if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "can't find groupname", srv->srvconf.groupname);
+@@ -828,13 +828,13 @@ int main (int argc, char **argv) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setgroups failed: ", strerror(errno));
+ return -1;
+ }
+- if (srv->srvconf.username->used) {
++ if (!buffer_string_is_empty(srv->srvconf.username)) {
+ initgroups(srv->srvconf.username->ptr, grp->gr_gid);
+ }
+ }
+ #endif
+ #ifdef HAVE_CHROOT
+- if (srv->srvconf.changeroot->used) {
++ if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
+ tzset();
+
+ if (-1 == chroot(srv->srvconf.changeroot->ptr)) {
+@@ -1001,8 +1001,7 @@ int main (int argc, char **argv) {
+ if (pid_fd != -1) {
+ buffer_copy_int(srv->tmp_buf, getpid());
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
+- force_assert(srv->tmp_buf->used > 0);
+- write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
++ write(pid_fd, CONST_BUF_LEN(srv->tmp_buf));
+ close(pid_fd);
+ pid_fd = -1;
+ }
+@@ -1425,8 +1424,8 @@ int main (int argc, char **argv) {
+
+ /* network_close() will cleanup after us */
+
+- if (srv->srvconf.pid_file->used &&
+- srv->srvconf.changeroot->used == 0) {
++ if (!buffer_string_is_empty(srv->srvconf.pid_file) &&
++ buffer_string_is_empty(srv->srvconf.changeroot)) {
+ if (0 != unlink(srv->srvconf.pid_file->ptr)) {
+ if (errno != EACCES && errno != EPERM) {
+ log_error_write(srv, __FILE__, __LINE__, "sbds",
+@@ -1542,8 +1541,8 @@ int main (int argc, char **argv) {
+ srv->joblist->used = 0;
+ }
+
+- if (srv->srvconf.pid_file->used &&
+- srv->srvconf.changeroot->used == 0 &&
++ if (!buffer_string_is_empty(srv->srvconf.pid_file) &&
++ buffer_string_is_empty(srv->srvconf.changeroot) &&
+ 0 == graceful_shutdown) {
+ if (0 != unlink(srv->srvconf.pid_file->ptr)) {
+ if (errno != EACCES && errno != EPERM) {
+diff --git a/src/stat_cache.c b/src/stat_cache.c
+index b63140e..dedea4b 100644
+--- a/src/stat_cache.c
++++ b/src/stat_cache.c
+@@ -222,8 +222,7 @@ static int stat_cache_attr_get(buffer *buf, char *name) {
+ buffer_string_prepare_copy(buf, 1023);
+ attrlen = buf->size - 1;
+ if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) {
+- buf->used = attrlen + 1;
+- buf->ptr[attrlen] = '\0';
++ buffer_commit(buf, attrlen);
+ }
+ return ret;
+ }
+@@ -332,7 +331,7 @@ static int buffer_copy_dirname(buffer *dst, buffer *file) {
+
+ if (buffer_string_is_empty(file)) return -1;
+
+- for (i = file->used - 1; i+1 > 0; i--) {
++ for (i = buffer_string_length(file); i > 0; i--) {
+ if (file->ptr[i] == '/') {
+ buffer_copy_string_len(dst, file->ptr, i);
+ return 0;
+@@ -499,7 +498,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+
+ if (S_ISREG(st.st_mode)) {
+ /* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */
+- if (name->ptr[name->used-2] == '/') {
++ if (name->ptr[buffer_string_length(name) - 1] == '/') {
+ errno = ENOTDIR;
+ return HANDLER_ERROR;
+ }
+@@ -571,16 +570,15 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ * we assume "/" can not be symlink, so
+ * skip the symlink stuff if our path is /
+ **/
+- else if ((name->used > 2)) {
++ else if (buffer_string_length(name) > 1) {
+ buffer *dname;
+ char *s_cur;
+
+ dname = buffer_init();
+ buffer_copy_buffer(dname, name);
+
+- while ((s_cur = strrchr(dname->ptr,'/'))) {
+- *s_cur = '\0';
+- dname->used = s_cur - dname->ptr + 1;
++ while ((s_cur = strrchr(dname->ptr, '/'))) {
++ buffer_string_set_length(dname, s_cur - dname->ptr);
+ if (dname->ptr == s_cur) {
+ #ifdef DEBUG_STAT_CACHE
+ log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
+@@ -615,16 +613,19 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
+ #endif
+ /* xattr did not set a content-type. ask the config */
+ if (buffer_string_is_empty(sce->content_type)) {
++ size_t namelen = buffer_string_length(name);
++
+ for (k = 0; k < con->conf.mimetypes->used; k++) {
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+ buffer *type = ds->key;
++ size_t typelen = buffer_string_length(type);
+
+- if (type->used == 0) continue;
++ if (buffer_is_empty(type)) continue;
+
+ /* check if the right side is the same */
+- if (type->used > name->used) continue;
++ if (typelen > namelen) continue;
+
+- if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) {
++ if (0 == strncasecmp(name->ptr + namelen - typelen, type->ptr, typelen)) {
+ buffer_copy_buffer(sce->content_type, ds->value);
+ break;
+ }
+--
+2.4.5
+
diff --git a/main/lighttpd/0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch b/main/lighttpd/0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch
new file mode 100644
index 0000000000..16441ace75
--- /dev/null
+++ b/main/lighttpd/0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch
@@ -0,0 +1,117 @@
+From 91a9a6b3910df8be3936ed0a70b0ac6cbdc10079 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:46 +0000
+Subject: [PATCH 20/29] rename buffer_append_long_hex to buffer_append_uint_hex
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+* takes uintmax_t now
+* use in http_chunk_append_len
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2980 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/buffer.c | 4 ++--
+ src/buffer.h | 2 +-
+ src/http_chunk.c | 22 +++-------------------
+ src/log.c | 4 ++--
+ 4 files changed, 8 insertions(+), 24 deletions(-)
+
+diff --git a/src/buffer.c b/src/buffer.c
+index d343731..425d700 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -234,12 +234,12 @@ void buffer_append_string_buffer(buffer *b, const buffer *src) {
+ }
+ }
+
+-void buffer_append_long_hex(buffer *b, unsigned long value) {
++void buffer_append_uint_hex(buffer *b, uintmax_t value) {
+ char *buf;
+ int shift = 0;
+
+ {
+- unsigned long copy = value;
++ uintmax_t copy = value;
+ do {
+ copy >>= 8;
+ shift += 2; /* counting nibbles (4 bits) */
+diff --git a/src/buffer.h b/src/buffer.h
+index e2ac778..f5d0224 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -89,7 +89,7 @@ void buffer_append_string(buffer *b, const char *s);
+ void buffer_append_string_len(buffer *b, const char *s, size_t s_len);
+ void buffer_append_string_buffer(buffer *b, const buffer *src);
+
+-void buffer_append_long_hex(buffer *b, unsigned long len);
++void buffer_append_uint_hex(buffer *b, uintmax_t len);
+ void buffer_append_int(buffer *b, intmax_t val);
+ void buffer_copy_int(buffer *b, intmax_t val);
+
+diff --git a/src/http_chunk.c b/src/http_chunk.c
+index 79e4586..45db56c 100644
+--- a/src/http_chunk.c
++++ b/src/http_chunk.c
+@@ -21,31 +21,15 @@
+ #include <string.h>
+
+ static void http_chunk_append_len(server *srv, connection *con, size_t len) {
+- size_t i, olen = len, j;
+ buffer *b;
+
+ force_assert(NULL != srv);
+
+ b = srv->tmp_chunk_len;
+
+- if (len == 0) {
+- buffer_copy_string_len(b, CONST_STR_LEN("0\r\n"));
+- } else {
+- for (i = 0; i < 8 && len; i++) {
+- len >>= 4;
+- }
+-
+- /* i is the number of hex digits we have, + \r\n */
+- buffer_string_prepare_copy(b, i + 2);
+-
+- for (j = i-1, len = olen; j+1 > 0; j--) {
+- b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
+- len >>= 4;
+- }
+- buffer_commit(b, i);
+-
+- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+- }
++ buffer_string_set_length(b, 0);
++ buffer_append_uint_hex(b, len);
++ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+
+ chunkqueue_append_buffer(con->write_queue, b);
+ }
+diff --git a/src/log.c b/src/log.c
+index 6c9c38d..9322d2c 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -288,7 +288,7 @@ static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ case 'x': /* int (hex) */
+ d = va_arg(ap, int);
+ buffer_append_string_len(out, CONST_STR_LEN("0x"));
+- buffer_append_long_hex(out, d);
++ buffer_append_uint_hex(out, d);
+ buffer_append_string_len(out, CONST_STR_LEN(" "));
+ break;
+ case 'S': /* string */
+@@ -310,7 +310,7 @@ static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ case 'X': /* int (hex) */
+ d = va_arg(ap, int);
+ buffer_append_string_len(out, CONST_STR_LEN("0x"));
+- buffer_append_long_hex(out, d);
++ buffer_append_uint_hex(out, d);
+ break;
+ case '(':
+ case ')':
+--
+2.4.5
+
diff --git a/main/lighttpd/0021-buffer-constify-some-parameters.patch b/main/lighttpd/0021-buffer-constify-some-parameters.patch
new file mode 100644
index 0000000000..d99e114906
--- /dev/null
+++ b/main/lighttpd/0021-buffer-constify-some-parameters.patch
@@ -0,0 +1,98 @@
+From 66ad587f2f9e9d9ce44437c1e185a961cfc13290 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:49 +0000
+Subject: [PATCH 21/29] [buffer] constify some parameters
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2981 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/buffer.c | 12 ++++++------
+ src/buffer.h | 12 ++++++------
+ 2 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/src/buffer.c b/src/buffer.c
+index 425d700..57c1613 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -409,11 +409,11 @@ char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
+ return NULL;
+ }
+
+-int buffer_is_empty(buffer *b) {
++int buffer_is_empty(const buffer *b) {
+ return NULL == b || 0 == b->used;
+ }
+
+-int buffer_string_is_empty(buffer *b) {
++int buffer_string_is_empty(const buffer *b) {
+ return 0 == buffer_string_length(b);
+ }
+
+@@ -424,7 +424,7 @@ int buffer_string_is_empty(buffer *b) {
+ * alignment properly.
+ */
+
+-int buffer_is_equal(buffer *a, buffer *b) {
++int buffer_is_equal(const buffer *a, const buffer *b) {
+ force_assert(NULL != a && NULL != b);
+
+ if (a->used != b->used) return 0;
+@@ -433,7 +433,7 @@ int buffer_is_equal(buffer *a, buffer *b) {
+ return (0 == memcmp(a->ptr, b->ptr, a->used));
+ }
+
+-int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
++int buffer_is_equal_string(const buffer *a, const char *s, size_t b_len) {
+ force_assert(NULL != a && NULL != s);
+ force_assert(b_len + 1 > b_len);
+
+@@ -445,7 +445,7 @@ int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
+ }
+
+ /* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */
+-int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len) {
++int buffer_is_equal_caseless_string(const buffer *a, const char *s, size_t b_len) {
+ force_assert(NULL != a);
+ if (a->used != b_len + 1) return 0;
+ force_assert('\0' == a->ptr[a->used - 1]);
+@@ -472,7 +472,7 @@ int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b
+ return a_len < b_len ? -1 : 1;
+ }
+
+-int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
++int buffer_is_equal_right_len(const buffer *b1, const buffer *b2, size_t len) {
+ /* no len -> equal */
+ if (len == 0) return 1;
+
+diff --git a/src/buffer.h b/src/buffer.h
+index f5d0224..b6065d4 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -112,14 +112,14 @@ char * buffer_search_string_len(buffer *b, const char *needle, size_t len);
+ * unset "string" (buffer) config options are initialized to used == 0,
+ * while setting an empty string leads to used == 1
+ */
+-int buffer_is_empty(buffer *b);
++int buffer_is_empty(const buffer *b);
+ /* NULL buffer, empty buffer (used == 0) or empty string (used == 1) */
+-int buffer_string_is_empty(buffer *b);
++int buffer_string_is_empty(const buffer *b);
+
+-int buffer_is_equal(buffer *a, buffer *b);
+-int buffer_is_equal_right_len(buffer *a, buffer *b, size_t len);
+-int buffer_is_equal_string(buffer *a, const char *s, size_t b_len);
+-int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len);
++int buffer_is_equal(const buffer *a, const buffer *b);
++int buffer_is_equal_right_len(const buffer *a, const buffer *b, size_t len);
++int buffer_is_equal_string(const buffer *a, const char *s, size_t b_len);
++int buffer_is_equal_caseless_string(const buffer *a, const char *s, size_t b_len);
+ int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len);
+
+ typedef enum {
+--
+2.4.5
+
diff --git a/main/lighttpd/0022-bitset-unused-remove.patch b/main/lighttpd/0022-bitset-unused-remove.patch
new file mode 100644
index 0000000000..572f7a5e25
--- /dev/null
+++ b/main/lighttpd/0022-bitset-unused-remove.patch
@@ -0,0 +1,170 @@
+From bfce99aacc99d962a9855fbbae61c309728122fe Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:51 +0000
+Subject: [PATCH 22/29] [bitset] unused -> remove
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2982 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/CMakeLists.txt | 2 +-
+ src/Makefile.am | 4 ++--
+ src/SConscript | 2 +-
+ src/bitset.c | 67 ------------------------------------------------------
+ src/bitset.h | 19 ----------------
+ src/fdevent.h | 1 -
+ 6 files changed, 4 insertions(+), 91 deletions(-)
+ delete mode 100644 src/bitset.c
+ delete mode 100644 src/bitset.h
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index a5471ff..a4ada19 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -66,7 +66,7 @@ common_src=buffer.c log.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
+- data_config.c bitset.c \
++ data_config.c \
+ inet_ntop_cache.c crc32.c \
+ connections-glue.c \
+ configfile-glue.c \
+@@ -273,7 +273,7 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
+ fdevent.h connections.h base.h stat_cache.h \
+ plugin.h mod_auth.h \
+ etag.h joblist.h array.h crc32.h \
+- network_backends.h configfile.h bitset.h \
++ network_backends.h configfile.h \
+ mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
+ configparser.h mod_ssi_exprparser.h \
+ sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
+diff --git a/src/SConscript b/src/SConscript
+index 7565094..bb507a5 100644
+--- a/src/SConscript
++++ b/src/SConscript
+@@ -14,7 +14,7 @@ common_src = Split("buffer.c log.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
+- data_config.c bitset.c \
++ data_config.c \
+ inet_ntop_cache.c crc32.c \
+ connections-glue.c \
+ configfile-glue.c \
+diff --git a/src/bitset.c b/src/bitset.c
+deleted file mode 100644
+index 27c93a8..0000000
+--- a/src/bitset.c
++++ /dev/null
+@@ -1,67 +0,0 @@
+-#include "buffer.h"
+-#include "bitset.h"
+-
+-#include <limits.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <stdio.h>
+-#include <assert.h>
+-
+-#define BITSET_BITS \
+- ( CHAR_BIT * sizeof(size_t) )
+-
+-#define BITSET_MASK(pos) \
+- ( ((size_t)1) << ((pos) % BITSET_BITS) )
+-
+-#define BITSET_WORD(set, pos) \
+- ( (set)->bits[(pos) / BITSET_BITS] )
+-
+-#define BITSET_USED(nbits) \
+- ( ((nbits) + (BITSET_BITS - 1)) / BITSET_BITS )
+-
+-bitset *bitset_init(size_t nbits) {
+- bitset *set;
+-
+- set = malloc(sizeof(*set));
+- force_assert(set);
+-
+- set->bits = calloc(BITSET_USED(nbits), sizeof(*set->bits));
+- set->nbits = nbits;
+-
+- force_assert(set->bits);
+-
+- return set;
+-}
+-
+-void bitset_reset(bitset *set) {
+- memset(set->bits, 0, BITSET_USED(set->nbits) * sizeof(*set->bits));
+-}
+-
+-void bitset_free(bitset *set) {
+- free(set->bits);
+- free(set);
+-}
+-
+-void bitset_clear_bit(bitset *set, size_t pos) {
+- if (pos >= set->nbits) {
+- SEGFAULT();
+- }
+-
+- BITSET_WORD(set, pos) &= ~BITSET_MASK(pos);
+-}
+-
+-void bitset_set_bit(bitset *set, size_t pos) {
+- if (pos >= set->nbits) {
+- SEGFAULT();
+- }
+-
+- BITSET_WORD(set, pos) |= BITSET_MASK(pos);
+-}
+-
+-int bitset_test_bit(bitset *set, size_t pos) {
+- if (pos >= set->nbits) {
+- SEGFAULT();
+- }
+-
+- return (BITSET_WORD(set, pos) & BITSET_MASK(pos)) != 0;
+-}
+diff --git a/src/bitset.h b/src/bitset.h
+deleted file mode 100644
+index 467e13f..0000000
+--- a/src/bitset.h
++++ /dev/null
+@@ -1,19 +0,0 @@
+-#ifndef _BITSET_H_
+-#define _BITSET_H_
+-
+-#include <stddef.h>
+-
+-typedef struct {
+- size_t *bits;
+- size_t nbits;
+-} bitset;
+-
+-bitset *bitset_init(size_t nbits);
+-void bitset_reset(bitset *set);
+-void bitset_free(bitset *set);
+-
+-void bitset_clear_bit(bitset *set, size_t pos);
+-void bitset_set_bit(bitset *set, size_t pos);
+-int bitset_test_bit(bitset *set, size_t pos);
+-
+-#endif
+diff --git a/src/fdevent.h b/src/fdevent.h
+index 5147baa..235d68b 100644
+--- a/src/fdevent.h
++++ b/src/fdevent.h
+@@ -6,7 +6,6 @@
+ #endif
+
+ #include "settings.h"
+-#include "bitset.h"
+
+ #if defined HAVE_STDINT_H
+ # include <stdint.h>
+--
+2.4.5
+
diff --git a/main/lighttpd/0023-remove-unused-stuff-from-server.h.patch b/main/lighttpd/0023-remove-unused-stuff-from-server.h.patch
new file mode 100644
index 0000000000..178cba4c40
--- /dev/null
+++ b/main/lighttpd/0023-remove-unused-stuff-from-server.h.patch
@@ -0,0 +1,38 @@
+From 68add2602b15638f2bb8cb7710a0dd60e95c6ac3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:53 +0000
+Subject: [PATCH 23/29] remove unused stuff from server.h
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2983 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/server.h | 8 --------
+ 1 file changed, 8 deletions(-)
+
+diff --git a/src/server.h b/src/server.h
+index bca2d52..67d4e7c 100644
+--- a/src/server.h
++++ b/src/server.h
+@@ -3,15 +3,7 @@
+
+ #include "base.h"
+
+-typedef struct {
+- char *key;
+- char *value;
+-} two_strings;
+-
+-typedef enum { CONFIG_UNSET, CONFIG_DOCUMENT_ROOT } config_var_t;
+-
+ int config_read(server *srv, const char *fn);
+ int config_set_defaults(server *srv);
+-buffer *config_get_value_buffer(server *srv, connection *con, config_var_t field);
+
+ #endif
+--
+2.4.5
+
diff --git a/main/lighttpd/0024-crc32-fix-method-signature-const-pointer.patch b/main/lighttpd/0024-crc32-fix-method-signature-const-pointer.patch
new file mode 100644
index 0000000000..f53cc5b2cf
--- /dev/null
+++ b/main/lighttpd/0024-crc32-fix-method-signature-const-pointer.patch
@@ -0,0 +1,44 @@
+From deceae78c9584350d17a9b5b9a5d2fef3def5e45 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:56 +0000
+Subject: [PATCH 24/29] [crc32] fix method signature (const pointer)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2984 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ src/crc32.c | 2 +-
+ src/crc32.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/crc32.c b/src/crc32.c
+index cdad7bc..b19bec5 100644
+--- a/src/crc32.c
++++ b/src/crc32.c
+@@ -70,7 +70,7 @@ static const unsigned int crc_c[256] = {
+ };
+
+
+-uint32_t generate_crc32c(char *buffer, size_t length) {
++uint32_t generate_crc32c(const char *buffer, size_t length) {
+ size_t i;
+ uint32_t crc32 = ~0L;
+
+diff --git a/src/crc32.h b/src/crc32.h
+index c5b4245..10e0e90 100644
+--- a/src/crc32.h
++++ b/src/crc32.h
+@@ -13,6 +13,6 @@
+ # include <inttypes.h>
+ #endif
+
+-uint32_t generate_crc32c(char *string, size_t length);
++uint32_t generate_crc32c(const char *string, size_t length);
+
+ #endif
+--
+2.4.5
+
diff --git a/main/lighttpd/0025-tests-fix-undefined-index-warning-in-sendfile.php.patch b/main/lighttpd/0025-tests-fix-undefined-index-warning-in-sendfile.php.patch
new file mode 100644
index 0000000000..f37b98cdba
--- /dev/null
+++ b/main/lighttpd/0025-tests-fix-undefined-index-warning-in-sendfile.php.patch
@@ -0,0 +1,31 @@
+From 673923daf839fda59e4dc1e5f95f5b265a65e802 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Sun, 8 Feb 2015 19:10:58 +0000
+Subject: [PATCH 25/29] [tests] fix undefined index warning in sendfile.php
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2985 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ tests/docroot/www/sendfile.php | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/docroot/www/sendfile.php b/tests/docroot/www/sendfile.php
+index 0aa8786..e460220 100644
+--- a/tests/docroot/www/sendfile.php
++++ b/tests/docroot/www/sendfile.php
+@@ -6,7 +6,7 @@ function pathencode($path) {
+
+ $val = "X-Sendfile2: " . pathencode(getcwd() . "/index.txt") . " " . $_GET["range"];
+
+-if ($_GET["range2"]) $val .= ", " . pathencode(getcwd() . "/index.txt") . " " . $_GET["range2"];
++if (isset($_GET["range2"])) $val .= ", " . pathencode(getcwd() . "/index.txt") . " " . $_GET["range2"];
+
+ header($val);
+
+--
+2.4.5
+
diff --git a/main/lighttpd/0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch b/main/lighttpd/0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch
new file mode 100644
index 0000000000..8fbefeb99e
--- /dev/null
+++ b/main/lighttpd/0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch
@@ -0,0 +1,102 @@
+From c92496720d21ea7888187a8ae305c392d4fe824a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 12 Feb 2015 06:39:39 +0000
+Subject: [PATCH 26/29] [mod_auth] use crypt_r instead of crypt if available
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2986 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ configure.ac | 22 +++++++++++++++-------
+ src/CMakeLists.txt | 12 +++++++++---
+ src/config.h.cmake | 3 ++-
+ src/http_auth.c | 10 +++++++++-
+ 5 files changed, 36 insertions(+), 12 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index ddb370d..59fd4f6 100644
+--- a/NEWS
++++ b/NEWS
+@@ -16,6 +16,7 @@ NEWS
+ * [connections] fix bug in connection state handling
+ * print backtrace in assert logging with libunwind
+ * major refactoring of internal buffer/chunk handling
++ * [mod_auth] use crypt_r instead of crypt if available
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/configure.ac b/configure.ac
+index c846d1a..16e66d6 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -528,19 +528,27 @@ if test "$WITH_LUA" != "no"; then
+ AC_SUBST(LUA_LIBS)
+ fi
+
++dnl search for crypt_r and (fallback) for crypt
+ save_LIBS=$LIBS
+-AC_SEARCH_LIBS(crypt,crypt,[
++LIBS=
++AC_SEARCH_LIBS([crypt_r],[crypt],[
++ AC_DEFINE([HAVE_CRYPT_R], [1], [crypt_r])
+ AC_CHECK_HEADERS([crypt.h],[
+- AC_DEFINE([HAVE_CRYPT_H], [1])
++ AC_DEFINE([HAVE_CRYPT_H], [1], [crypt.h])
+ ])
+
+- AC_DEFINE([HAVE_LIBCRYPT], [1], [libcrypt])
+- if test "$ac_cv_search_crypt" != no; then
+- test "$ac_cv_search_crypt" = "none required" || CRYPT_LIB="$ac_cv_search_crypt"
+- fi
++ CRYPT_LIB=$LIBS
++],[
++ AC_SEARCH_LIBS([crypt],[crypt],[
++ AC_CHECK_HEADERS([crypt.h],[
++ AC_DEFINE([HAVE_CRYPT_H], [1], [crypt.h])
++ ])
++
++ CRYPT_LIB=$LIBS
++ ])
+ ])
+ LIBS=$save_LIBS
+-AC_SUBST(CRYPT_LIB)
++AC_SUBST([CRYPT_LIB])
+
+ save_LIBS=$LIBS
+ AC_SEARCH_LIBS(sendfilev,sendfile,[
+diff --git a/src/http_auth.c b/src/http_auth.c
+index a98ea62..dacf70a 100644
+--- a/src/http_auth.c
++++ b/src/http_auth.c
+@@ -669,15 +669,23 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
+ return (strcmp(sample, password->ptr) == 0) ? 0 : 1;
+ #endif
+ } else {
+-#ifdef HAVE_CRYPT
++#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
+ char *crypted;
++#if defined(HAVE_CRYPT_R)
++ struct crypt_data crypt_tmp_data;
++ crypt_tmp_data.initialized = 0;
++#endif
+
+ /* a simple DES password is 2 + 11 characters. everything else should be longer. */
+ if (buffer_string_length(password) < 13) {
+ return -1;
+ }
+
++#if defined(HAVE_CRYPT_R)
++ if (0 == (crypted = crypt_r(pw, password->ptr, &crypt_tmp_data))) {
++#else
+ if (0 == (crypted = crypt(pw, password->ptr))) {
++#endif
+ /* crypt failed. */
+ return -1;
+ }
+--
+2.4.5
+
diff --git a/main/lighttpd/0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch b/main/lighttpd/0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch
new file mode 100644
index 0000000000..c11a695e72
--- /dev/null
+++ b/main/lighttpd/0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch
@@ -0,0 +1,49 @@
+From df87b3ef98711b6a4ca4cefb1fceec022ddcdc13 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 14 May 2015 09:38:30 +0000
+Subject: [PATCH 27/29] fix error message for T_CONFIG_ARRAY config values if
+ an entry value is not a string
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2987 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/configfile-glue.c | 6 +++---
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 59fd4f6..4d19144 100644
+--- a/NEWS
++++ b/NEWS
+@@ -17,6 +17,7 @@ NEWS
+ * print backtrace in assert logging with libunwind
+ * major refactoring of internal buffer/chunk handling
+ * [mod_auth] use crypt_r instead of crypt if available
++ * fix error message for T_CONFIG_ARRAY config values if an entry value is not a string
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/configfile-glue.c b/src/configfile-glue.c
+index f411d72..807e307 100644
+--- a/src/configfile-glue.c
++++ b/src/configfile-glue.c
+@@ -56,9 +56,9 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
+
+ array_insert_unique(cv[i].destination, (data_unset *)ds);
+ } else {
+- log_error_write(srv, __FILE__, __LINE__, "sssd",
+- "the key of an array can only be a string or a integer, variable:",
+- cv[i].key, "type:", da->value->data[j]->type);
++ log_error_write(srv, __FILE__, __LINE__, "sssbsd",
++ "the value of an array can only be a string, variable:",
++ cv[i].key, "[", da->value->data[j]->key, "], type:", da->value->data[j]->type);
+
+ return -1;
+ }
+--
+2.4.5
+
diff --git a/main/lighttpd/0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch b/main/lighttpd/0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch
new file mode 100644
index 0000000000..d35b478424
--- /dev/null
+++ b/main/lighttpd/0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch
@@ -0,0 +1,447 @@
+From 33cebeb0f778d437e1a6070504f588b2531fa291 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 14 May 2015 09:38:33 +0000
+Subject: [PATCH 28/29] fix segfaults in many plugins if they failed
+ configuration
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2988 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 1 +
+ src/mod_access.c | 2 ++
+ src/mod_accesslog.c | 2 +-
+ src/mod_alias.c | 2 +-
+ src/mod_auth.c | 2 +-
+ src/mod_cgi.c | 2 ++
+ src/mod_cml.c | 2 ++
+ src/mod_compress.c | 2 +-
+ src/mod_evasive.c | 2 ++
+ src/mod_evhost.c | 2 +-
+ src/mod_expire.c | 3 ++-
+ src/mod_extforward.c | 2 +-
+ src/mod_fastcgi.c | 2 +-
+ src/mod_flv_streaming.c | 2 +-
+ src/mod_indexfile.c | 2 +-
+ src/mod_magnet.c | 2 +-
+ src/mod_proxy.c | 7 +++----
+ src/mod_redirect.c | 2 ++
+ src/mod_rewrite.c | 3 +++
+ src/mod_rrdtool.c | 2 ++
+ src/mod_scgi.c | 2 +-
+ src/mod_secure_download.c | 2 ++
+ src/mod_setenv.c | 2 ++
+ src/mod_skeleton.c | 2 +-
+ src/mod_ssi.c | 2 ++
+ src/mod_staticfile.c | 2 ++
+ src/mod_trigger_b4_dl.c | 2 +-
+ src/mod_uploadprogress.c | 2 ++
+ src/mod_userdir.c | 2 ++
+ src/mod_usertrack.c | 2 ++
+ src/mod_webdav.c | 2 +-
+ 31 files changed, 49 insertions(+), 19 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 4d19144..dd2d1b8 100644
+--- a/NEWS
++++ b/NEWS
+@@ -18,6 +18,7 @@ NEWS
+ * major refactoring of internal buffer/chunk handling
+ * [mod_auth] use crypt_r instead of crypt if available
+ * fix error message for T_CONFIG_ARRAY config values if an entry value is not a string
++ * fix segfaults in many plugins if they failed configuration
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+diff --git a/src/mod_access.c b/src/mod_access.c
+index a6c25a4..e6a9a14 100644
+--- a/src/mod_access.c
++++ b/src/mod_access.c
+@@ -40,6 +40,8 @@ FREE_FUNC(mod_access_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ array_free(s->access_deny);
+
+ free(s);
+diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
+index 9bb3fe2..f5be7d2 100644
+--- a/src/mod_accesslog.c
++++ b/src/mod_accesslog.c
+@@ -414,7 +414,7 @@ FREE_FUNC(mod_accesslog_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ if (!buffer_string_is_empty(s->access_logbuffer)) {
+ if (s->log_access_fd != -1) {
+diff --git a/src/mod_alias.c b/src/mod_alias.c
+index 4625973..f9d7b51 100644
+--- a/src/mod_alias.c
++++ b/src/mod_alias.c
+@@ -45,7 +45,7 @@ FREE_FUNC(mod_alias_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if(!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->alias);
+
+diff --git a/src/mod_auth.c b/src/mod_auth.c
+index 1870893..edddaa8 100644
+--- a/src/mod_auth.c
++++ b/src/mod_auth.c
+@@ -60,7 +60,7 @@ FREE_FUNC(mod_auth_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ mod_auth_plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->auth_require);
+ buffer_free(s->auth_plain_groupfile);
+diff --git a/src/mod_cgi.c b/src/mod_cgi.c
+index 8a7cc2b..01b1877 100644
+--- a/src/mod_cgi.c
++++ b/src/mod_cgi.c
+@@ -127,6 +127,8 @@ FREE_FUNC(mod_cgi_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ array_free(s->cgi);
+
+ free(s);
+diff --git a/src/mod_cml.c b/src/mod_cml.c
+index baa23b3..98f8d77 100644
+--- a/src/mod_cml.c
++++ b/src/mod_cml.c
+@@ -43,6 +43,8 @@ FREE_FUNC(mod_cml_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ buffer_free(s->ext);
+
+ buffer_free(s->mc_namespace);
+diff --git a/src/mod_compress.c b/src/mod_compress.c
+index f0ffa1c..29d5ab5 100644
+--- a/src/mod_compress.c
++++ b/src/mod_compress.c
+@@ -90,7 +90,7 @@ FREE_FUNC(mod_compress_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->compress);
+ buffer_free(s->compress_cache_dir);
+diff --git a/src/mod_evasive.c b/src/mod_evasive.c
+index d9b8732..da45c9a 100644
+--- a/src/mod_evasive.c
++++ b/src/mod_evasive.c
+@@ -58,6 +58,8 @@ FREE_FUNC(mod_evasive_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ free(s);
+ }
+ free(p->config_storage);
+diff --git a/src/mod_evhost.c b/src/mod_evhost.c
+index e728551..3c49adf 100644
+--- a/src/mod_evhost.c
++++ b/src/mod_evhost.c
+@@ -46,7 +46,7 @@ FREE_FUNC(mod_evhost_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ if(s->path_pieces) {
+ size_t j;
+diff --git a/src/mod_expire.c b/src/mod_expire.c
+index e26c3c6..0794c15 100644
+--- a/src/mod_expire.c
++++ b/src/mod_expire.c
+@@ -62,7 +62,8 @@ FREE_FUNC(mod_expire_free) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+- if (!s) continue;
++
++ if (NULL == s) continue;
+
+ array_free(s->expire_url);
+ free(s);
+diff --git a/src/mod_extforward.c b/src/mod_extforward.c
+index 7f77982..557c505 100644
+--- a/src/mod_extforward.c
++++ b/src/mod_extforward.c
+@@ -135,7 +135,7 @@ FREE_FUNC(mod_extforward_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->forwarder);
+ array_free(s->headers);
+diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
+index d16306c..5be73df 100644
+--- a/src/mod_fastcgi.c
++++ b/src/mod_fastcgi.c
+@@ -693,7 +693,7 @@ FREE_FUNC(mod_fastcgi_free) {
+ plugin_config *s = p->config_storage[i];
+ fcgi_exts *exts;
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ exts = s->exts;
+
+diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
+index db041e2..6e92c74 100644
+--- a/src/mod_flv_streaming.c
++++ b/src/mod_flv_streaming.c
+@@ -54,7 +54,7 @@ FREE_FUNC(mod_flv_streaming_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->extensions);
+
+diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
+index 13d18e2..3c57256 100644
+--- a/src/mod_indexfile.c
++++ b/src/mod_indexfile.c
+@@ -51,7 +51,7 @@ FREE_FUNC(mod_indexfile_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->indexfiles);
+
+diff --git a/src/mod_magnet.c b/src/mod_magnet.c
+index 8f89d4e..0d99fdf 100644
+--- a/src/mod_magnet.c
++++ b/src/mod_magnet.c
+@@ -71,7 +71,7 @@ FREE_FUNC(mod_magnet_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->url_raw);
+ array_free(s->physical_path);
+diff --git a/src/mod_proxy.c b/src/mod_proxy.c
+index dfdc636..7821072 100644
+--- a/src/mod_proxy.c
++++ b/src/mod_proxy.c
+@@ -167,12 +167,11 @@ FREE_FUNC(mod_proxy_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (s) {
++ if (NULL == s) continue;
+
+- array_free(s->extensions);
++ array_free(s->extensions);
+
+- free(s);
+- }
++ free(s);
+ }
+ free(p->config_storage);
+ }
+diff --git a/src/mod_redirect.c b/src/mod_redirect.c
+index 615c7db..769c8c8 100644
+--- a/src/mod_redirect.c
++++ b/src/mod_redirect.c
+@@ -47,6 +47,8 @@ FREE_FUNC(mod_redirect_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ pcre_keyvalue_buffer_free(s->redirect);
+
+ free(s);
+diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
+index 5191a64..113cc54 100644
+--- a/src/mod_rewrite.c
++++ b/src/mod_rewrite.c
+@@ -146,6 +146,9 @@ FREE_FUNC(mod_rewrite_free) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
++
++ if (NULL == s) continue;
++
+ rewrite_rule_buffer_free(s->rewrite);
+ rewrite_rule_buffer_free(s->rewrite_NF);
+
+diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
+index 0532e4d..6b8cdae 100644
+--- a/src/mod_rrdtool.c
++++ b/src/mod_rrdtool.c
+@@ -65,6 +65,8 @@ FREE_FUNC(mod_rrd_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ buffer_free(s->path_rrdtool_bin);
+ buffer_free(s->path_rrd);
+
+diff --git a/src/mod_scgi.c b/src/mod_scgi.c
+index 9e88de3..733b51c 100644
+--- a/src/mod_scgi.c
++++ b/src/mod_scgi.c
+@@ -554,7 +554,7 @@ FREE_FUNC(mod_scgi_free) {
+ plugin_config *s = p->config_storage[i];
+ scgi_exts *exts;
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ exts = s->exts;
+
+diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
+index da98b61..d85872d 100644
+--- a/src/mod_secure_download.c
++++ b/src/mod_secure_download.c
+@@ -65,6 +65,8 @@ FREE_FUNC(mod_secdownload_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ buffer_free(s->secret);
+ buffer_free(s->doc_root);
+ buffer_free(s->uri_prefix);
+diff --git a/src/mod_setenv.c b/src/mod_setenv.c
+index 60e9b55..34075c1 100644
+--- a/src/mod_setenv.c
++++ b/src/mod_setenv.c
+@@ -67,6 +67,8 @@ FREE_FUNC(mod_setenv_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ array_free(s->request_header);
+ array_free(s->response_header);
+ array_free(s->environment);
+diff --git a/src/mod_skeleton.c b/src/mod_skeleton.c
+index 68d272d..8461279 100644
+--- a/src/mod_skeleton.c
++++ b/src/mod_skeleton.c
+@@ -79,7 +79,7 @@ FREE_FUNC(mod_skeleton_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ array_free(s->match);
+
+diff --git a/src/mod_ssi.c b/src/mod_ssi.c
+index ed3b75c..07b695d 100644
+--- a/src/mod_ssi.c
++++ b/src/mod_ssi.c
+@@ -69,6 +69,8 @@ FREE_FUNC(mod_ssi_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ array_free(s->ssi_extension);
+ buffer_free(s->content_type);
+
+diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
+index d40aa31..22929bb 100644
+--- a/src/mod_staticfile.c
++++ b/src/mod_staticfile.c
+@@ -63,6 +63,8 @@ FREE_FUNC(mod_staticfile_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ array_free(s->exclude_ext);
+
+ free(s);
+diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c
+index e1fa993..4a3eac2 100644
+--- a/src/mod_trigger_b4_dl.c
++++ b/src/mod_trigger_b4_dl.c
+@@ -89,7 +89,7 @@ FREE_FUNC(mod_trigger_b4_dl_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ buffer_free(s->db_filename);
+ buffer_free(s->download_url);
+diff --git a/src/mod_userdir.c b/src/mod_userdir.c
+index 682f950..f6f1d8a 100644
+--- a/src/mod_userdir.c
++++ b/src/mod_userdir.c
+@@ -60,6 +60,8 @@ FREE_FUNC(mod_userdir_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ array_free(s->include_user);
+ array_free(s->exclude_user);
+ buffer_free(s->path);
+diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c
+index 11aad95..3adedcf 100644
+--- a/src/mod_usertrack.c
++++ b/src/mod_usertrack.c
+@@ -48,6 +48,8 @@ FREE_FUNC(mod_usertrack_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
++ if (NULL == s) continue;
++
+ buffer_free(s->cookie_name);
+ buffer_free(s->cookie_domain);
+
+diff --git a/src/mod_webdav.c b/src/mod_webdav.c
+index 654108a..2fff8c3 100644
+--- a/src/mod_webdav.c
++++ b/src/mod_webdav.c
+@@ -120,7 +120,7 @@ FREE_FUNC(mod_webdav_free) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+- if (!s) continue;
++ if (NULL == s) continue;
+
+ buffer_free(s->sqlite_db_name);
+ #ifdef USE_PROPPATCH
+--
+2.4.5
+
diff --git a/main/lighttpd/0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch b/main/lighttpd/0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch
new file mode 100644
index 0000000000..20307fb204
--- /dev/null
+++ b/main/lighttpd/0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch
@@ -0,0 +1,174 @@
+From 427120b41a141626dbb40a752c848f199fc9f7a8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
+Date: Thu, 28 May 2015 15:47:14 +0000
+Subject: [PATCH 29/29] =?UTF-8?q?escape=20all=20strings=20for=20logging=20?=
+ =?UTF-8?q?(fixes=20#2646=20log=20file=20injection,=20reported=20by=20Jaan?=
+ =?UTF-8?q?us=20K=C3=A4=C3=A4p)?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Bühler <stbuehler@web.de>
+
+git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2989 152afb58-edef-0310-8abb-c4023f1b3aa9
+---
+ NEWS | 5 +++--
+ src/buffer.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/buffer.h | 5 ++++-
+ src/log.c | 8 ++++----
+ 4 files changed, 70 insertions(+), 7 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index dd2d1b8..18007fc 100644
+--- a/NEWS
++++ b/NEWS
+@@ -19,6 +19,7 @@ NEWS
+ * [mod_auth] use crypt_r instead of crypt if available
+ * fix error message for T_CONFIG_ARRAY config values if an entry value is not a string
+ * fix segfaults in many plugins if they failed configuration
++ * escape all strings for logging (fixes #2646 log file injection, reported by Jaanus Kääp)
+
+ - 1.4.35 - 2014-03-12
+ * [network/ssl] fix build error if TLSEXT is disabled
+@@ -557,10 +558,10 @@ NEWS
+ * ignore empty packets from STDERR stream. #998
+ * fix a crash for files with an mtime of 0 reported by cubiq on irc [1519]
+ CVE-2007-1870
+- * allow empty passwords with ldap (Jörg Sonnenberger) [1516]
++ * allow empty passwords with ldap (Jörg Sonnenberger) [1516]
+ * mod_scgi.c segfault fix #964 [1501]
+ * Added round-robin support to mod_fastcgi [1500]
+- * Handle DragonFlyBSD the same way as Freebsd (Jörg Sonnenberger) [1492,1676]
++ * Handle DragonFlyBSD the same way as Freebsd (Jörg Sonnenberger) [1492,1676]
+ * added now and weeks support to mod_expire. #943
+ * fix cpu hog in certain requests [1473] CVE-2007-1869
+ * fix for handling hostnames with trailing dot [1406]
+diff --git a/src/buffer.c b/src/buffer.c
+index 57c1613..36995a0 100644
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -731,6 +731,65 @@ void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer
+ }
+ }
+
++void buffer_append_string_c_escaped(buffer *b, const char *s, size_t s_len) {
++ unsigned char *ds, *d;
++ size_t d_len, ndx;
++
++ force_assert(NULL != b);
++ force_assert(NULL != s || 0 == s_len);
++
++ if (0 == s_len) return;
++
++ /* count to-be-encoded-characters */
++ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
++ if ((*ds < 0x20) /* control character */
++ || (*ds >= 0x7f)) { /* DEL + non-ASCII characters */
++ switch (*ds) {
++ case '\t':
++ case '\r':
++ case '\n':
++ d_len += 2;
++ break;
++ default:
++ d_len += 4; /* \xCC */
++ break;
++ }
++ } else {
++ d_len++;
++ }
++ }
++
++ d = (unsigned char*) buffer_string_prepare_append(b, d_len);
++ buffer_commit(b, d_len); /* fill below */
++ force_assert('\0' == *d);
++
++ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
++ if ((*ds < 0x20) /* control character */
++ || (*ds >= 0x7f)) { /* DEL + non-ASCII characters */
++ d[d_len++] = '\\';
++ switch (*ds) {
++ case '\t':
++ d[d_len++] = 't';
++ break;
++ case '\r':
++ d[d_len++] = 'r';
++ break;
++ case '\n':
++ d[d_len++] = 'n';
++ break;
++ default:
++ d[d_len++] = 'x';
++ d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
++ d[d_len++] = hex_chars[(*ds) & 0x0F];
++ break;
++ }
++ } else {
++ d[d_len++] = *ds;
++ }
++ }
++}
++
++
+ void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header) {
+ size_t i, j;
+
+diff --git a/src/buffer.h b/src/buffer.h
+index b6065d4..5f659df 100644
+--- a/src/buffer.h
++++ b/src/buffer.h
+@@ -133,6 +133,9 @@ typedef enum {
+
+ void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
+
++/* escape non-printable characters; simple escapes for \t, \r, \n; fallback to \xCC */
++void buffer_append_string_c_escaped(buffer *b, const char *s, size_t s_len);
++
+ /* to upper case, replace non alpha-numerics with '_'; if is_http_header prefix with "HTTP_" unless s is "content-type" */
+ void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header);
+
+@@ -164,7 +167,7 @@ static inline void buffer_append_slash(buffer *b); /* append '/' no non-empty st
+ buffer_copy_string_len(x, y, sizeof(y) - 1)
+
+ #define CONST_STR_LEN(x) x, (x) ? sizeof(x) - 1 : 0
+-#define CONST_BUF_LEN(x) (x)->ptr, buffer_string_length(x)
++#define CONST_BUF_LEN(x) ((x) ? (x)->ptr : NULL), buffer_string_length(x)
+
+
+ #define UNUSED(x) ( (void)(x) )
+diff --git a/src/log.c b/src/log.c
+index 9322d2c..94f4710 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -267,12 +267,12 @@ static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ switch(*fmt) {
+ case 's': /* string */
+ s = va_arg(ap, char *);
+- buffer_append_string(out, s);
++ buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
+ buffer_append_string_len(out, CONST_STR_LEN(" "));
+ break;
+ case 'b': /* buffer */
+ b = va_arg(ap, buffer *);
+- buffer_append_string_buffer(out, b);
++ buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
+ buffer_append_string_len(out, CONST_STR_LEN(" "));
+ break;
+ case 'd': /* int */
+@@ -293,11 +293,11 @@ static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ break;
+ case 'S': /* string */
+ s = va_arg(ap, char *);
+- buffer_append_string(out, s);
++ buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
+ break;
+ case 'B': /* buffer */
+ b = va_arg(ap, buffer *);
+- buffer_append_string_buffer(out, b);
++ buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
+ break;
+ case 'D': /* int */
+ d = va_arg(ap, int);
+--
+2.4.5
+
diff --git a/main/lighttpd/APKBUILD b/main/lighttpd/APKBUILD
index b959f48f2c..e3a7d7cc12 100644
--- a/main/lighttpd/APKBUILD
+++ b/main/lighttpd/APKBUILD
@@ -2,7 +2,7 @@
pkgname=lighttpd
pkgver=1.4.35
_streamver=2.2.0
-pkgrel=3
+pkgrel=4
pkgdesc="a secure, fast, compliant and very flexible web-server"
url="http://www.lighttpd.net/"
arch="all"
@@ -16,6 +16,36 @@ makedepends="flex pcre-dev openssl-dev zlib-dev bzip2-dev lua-dev
source="http://download.lighttpd.net/lighttpd/releases-1.4.x/$pkgname-$pkgver.tar.bz2
http://h264.code-shop.com/download/lighttpd-1.4.18_mod_h264_streaming-$_streamver.tar.gz
+ 0001-next-is-1.4.36.patch
+ 0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch
+ 0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch
+ 0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch
+ 0005-fix-typo-in-NEWS-entry-for-2579.patch
+ 0006-add-support-for-Free-BSD-extended-attributes.patch
+ 0007-build-use-fortify-flags-with-extra-warnings.patch
+ 0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch
+ 0009-ssl-disable-SSL3.0-by-default.patch
+ 0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch
+ 0011-add-NEWS-entry-for-previous-commit.patch
+ 0012-network-fix-compile-break-in-calculation-of-sockaddr.patch
+ 0013-connections-fix-bug-in-connection-state-handling.patch
+ 0014-print-backtrace-in-assert-logging-with-libunwind.patch
+ 0015-fix-buffer-chunk-and-http_chunk-API.patch
+ 0016-Remove-chunkqueue_get_-append-prepend-API.patch
+ 0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch
+ 0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch
+ 0019-Use-buffer-API-to-read-and-modify-used-member.patch
+ 0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch
+ 0021-buffer-constify-some-parameters.patch
+ 0022-bitset-unused-remove.patch
+ 0023-remove-unused-stuff-from-server.h.patch
+ 0024-crc32-fix-method-signature-const-pointer.patch
+ 0025-tests-fix-undefined-index-warning-in-sendfile.php.patch
+ 0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch
+ 0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch
+ 0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch
+ 0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch
+
$pkgname.initd
$pkgname.confd
$pkgname.logrotate
@@ -134,6 +164,35 @@ mod_webdav() {
md5sums="f7a88130ee9984b421ad8aa80629750a lighttpd-1.4.35.tar.bz2
ac37885c881a058194405232e7737a7a lighttpd-1.4.18_mod_h264_streaming-2.2.0.tar.gz
+00ee47ed4f38b4feede5bc015466966f 0001-next-is-1.4.36.patch
+bd2d1fba09c4ccee295a3c2dcafe8257 0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch
+dd6668db0b13257cbf63e6964e14edc3 0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch
+0fb4734ad0d3a669e29593a3bee8cb19 0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch
+0f3bf205dfa4bc26c27e6d91bae5a77d 0005-fix-typo-in-NEWS-entry-for-2579.patch
+148470359b1c253d926929cbf4a3df6e 0006-add-support-for-Free-BSD-extended-attributes.patch
+7a295bd597977549912a995cac4c16d2 0007-build-use-fortify-flags-with-extra-warnings.patch
+f7eae7225e3bbb176c805c4781c20fdd 0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch
+71745edff2b66f6e3764008f265922cf 0009-ssl-disable-SSL3.0-by-default.patch
+3dfd329eba6cbe2d5561a4a86be41d41 0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch
+d3701826b4d2e62eb915e2add340ab64 0011-add-NEWS-entry-for-previous-commit.patch
+0fb5b2d1047abf714072ac1d5e4d8e9d 0012-network-fix-compile-break-in-calculation-of-sockaddr.patch
+719ea46ccbd435b4e0a5b7679f6e6619 0013-connections-fix-bug-in-connection-state-handling.patch
+ab768bf719f1c80bcfec3921f597e9ce 0014-print-backtrace-in-assert-logging-with-libunwind.patch
+b45c3022b16bac36ed542e7761d1fc8d 0015-fix-buffer-chunk-and-http_chunk-API.patch
+4cae316e303cc74e6ceba6d9bb31b118 0016-Remove-chunkqueue_get_-append-prepend-API.patch
+5fdc9ba9824c47e92e35a87ed77cf673 0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch
+bb6293085a26d2585fd1a9027ee163df 0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch
+1df70c6be883619b1c0e0b225e8a76d9 0019-Use-buffer-API-to-read-and-modify-used-member.patch
+8cbc257ca7cb41933ed19bd096d63953 0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch
+abaa48bc0376b5bc2266159c81b386fd 0021-buffer-constify-some-parameters.patch
+0d2b7108b95bf4a26830e45337da57a9 0022-bitset-unused-remove.patch
+5f7c377944b94ae35e4360296241eab1 0023-remove-unused-stuff-from-server.h.patch
+7ab10c7e1f8ccb260289ab55d3588110 0024-crc32-fix-method-signature-const-pointer.patch
+ef60f4c3935b3b1a70e3ea0159208d7e 0025-tests-fix-undefined-index-warning-in-sendfile.php.patch
+24efc5f5dc32f35b34935cb69f7ff064 0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch
+f4d7686b793434bba88c03cbbc783440 0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch
+d7b916dab3c4440e0f5cee327f6e3993 0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch
+92a0c1b87737ac0f845ac10fefcf724a 0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch
b3f7106fa5dcdadf3b0e1bb98bba5e3a lighttpd.initd
0dede109282bfe685bdec6b35f0e4b6b lighttpd.confd
ad091c9157134890499f26d170352c9f lighttpd.logrotate
@@ -144,6 +203,35 @@ f3363e39832f1b6678468b482d121afb mod_fastcgi.conf
aee5947a1abf380b0685a534ca384b42 mod_fastcgi_fpm.conf"
sha256sums="4a71c1f6d8af41ed894b507720c4c17184dc320590013881d5170ca7f15c5bf7 lighttpd-1.4.35.tar.bz2
732cf98d823f2c7ddc96a3130a3c88d588b02ed20a0e7f8c9be25a265fbea2d6 lighttpd-1.4.18_mod_h264_streaming-2.2.0.tar.gz
+c879dbe0d41e2b5e9d79e94c621bcb6498170a9949aa9944009aebf7266f6574 0001-next-is-1.4.36.patch
+ea90697199e2dafb483942e44558bb73727b3ba2e2afe9017735a92db5a92b9e 0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch
+2de1193ee68715de6f92654a439c09254500c6d371fd979400265af1c31e2f64 0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch
+1708a734bb0bd9a6e5ff4357da82bf5dffc15bbb89e3fb369e4ed21408431081 0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch
+69b6b9986c6dd69ea77b60d61da8c984869a34d2e48928d774678392e9e0b377 0005-fix-typo-in-NEWS-entry-for-2579.patch
+959120d7c256733292aaeb6595c55e9b703968d3de3093ec3c65163f86859058 0006-add-support-for-Free-BSD-extended-attributes.patch
+e6e5984fb33ed89d7961e39ea75467a644a8f70ab931ff886545ee271b3e4079 0007-build-use-fortify-flags-with-extra-warnings.patch
+5a59ef2bf5efd77770a02421451372ec08b00a2e27cd4ce1312301ea94be58af 0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch
+b204c4bf8572f41cd31d4de34529ab65ec42a0d32eb4bcd4b77d42afd3858ff5 0009-ssl-disable-SSL3.0-by-default.patch
+c25c136143f597a557df676bb80dc549d44b4216de2bbec578b02e474532b7f5 0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch
+f0759a4fd37e43abb4901ecc53cfa64bc24ffcc52d425d1057b63d5e696ccddc 0011-add-NEWS-entry-for-previous-commit.patch
+91cc0d32a195178d78923749e0d9f49cba3806e988f3ec30ec1011bb5f10c888 0012-network-fix-compile-break-in-calculation-of-sockaddr.patch
+3c1ec290a581afb0c11d5743ecdffbee4bb2caec790e9c174fce2ce7501dcc96 0013-connections-fix-bug-in-connection-state-handling.patch
+afdfe2f60b91367eecc00b63d6e7f5bad221c9d719f4f827aef2b5fd35fecdaa 0014-print-backtrace-in-assert-logging-with-libunwind.patch
+fff02538e63edb68e4c070f0c5f518a43630addd7b4ce33b321caa9071f05357 0015-fix-buffer-chunk-and-http_chunk-API.patch
+c72d9b344ba4784cb1db1d9fca4fc88c86dca25ec1cfc91688424474da22e5f9 0016-Remove-chunkqueue_get_-append-prepend-API.patch
+600a3698a6d8882bf1f91a0f1e636395736f479d3fa2dda0b0ab099dbe648e73 0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch
+20b759bf8f4c7c79862f919fce2dc1b3348695993ba1033449df9558dbe01a6d 0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch
+4b5538e7428ac2d625655b35f46afcdf794f9cf7fab11d2fb2f626d9c0684dd9 0019-Use-buffer-API-to-read-and-modify-used-member.patch
+17b240483cd3b326e67c6dc38b53a9041623b9aec664e883c81f4ce525a36108 0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch
+58b7afa5a8e98a700c8856174586d4f458019308313864fcddcb974cf94650b2 0021-buffer-constify-some-parameters.patch
+d98d8bc7ddd107bca0b7653a7c9ac7f6874b986864f00c4a359a71892dda9da7 0022-bitset-unused-remove.patch
+3f4524142df2db012c5a8f0ab0dac2bdc53d5a253d18b842e4ba0649e37ac435 0023-remove-unused-stuff-from-server.h.patch
+45ae49ec62907750b5741d726942bc5171397a88cf676ff7750d54a89f94e8a8 0024-crc32-fix-method-signature-const-pointer.patch
+7adefe15856cb965f6ab102d8e655513b229c475951003766ea15d60e0f95536 0025-tests-fix-undefined-index-warning-in-sendfile.php.patch
+e46917c0731eff62ee5d73ecbdd6d4276674893936132a050c855c419d1dc8e6 0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch
+a1c8b496be35065ea72a115462c3a23c78995b953ce15b806d2ef6b6b6758523 0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch
+42192c43bd917a6b196e8b3fb52cfc76b9165f0b3de08bd30d0fab08b3ce2444 0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch
+dca7509a720ce26488685ce7acca041e83e1e1f2eb195adc36338ef4031b90fc 0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch
097a4df1a6470e2e9fd2097c7c1daa7b1ee6341faddc35a65e975af019beaebd lighttpd.initd
94f69a173dc26610a43532474230537b9bc31ec846fb9f94cb72765f125edf87 lighttpd.confd
503ee1cd454e2c0f9a212ef60dc8321893eda06ccf721ecbe94d189a09e0bc6c lighttpd.logrotate
@@ -154,6 +242,35 @@ d1adc1358b5d9e85353caa2e706bfa231d145dd59c075cdcb3f818b3cb5d722e mod_fastcgi.co
e7eb047360e09d1a2b693f08d4a912b99954090c5bdea706f46a33554e867043 mod_fastcgi_fpm.conf"
sha512sums="13f8562fb735964fe7ef1b127a15c43907f34be70b6bd2dd4ba61b59275d7c2a8d9a7947ff1a4d7cc5fd7efd309fc66b7de6d954b59424f814ea2eb98fd876b9 lighttpd-1.4.35.tar.bz2
12e1b7c8146cccfa78678ce56cd2f704423559b23b90996dff00602634f110512146386086ac234293a3c28900a06c2bec1c97e680e7eed5173372f88177b351 lighttpd-1.4.18_mod_h264_streaming-2.2.0.tar.gz
+622314eae65e08866dd55efbbf0a3c9b84818e4f5f5e4c4a602883c0123cf448edbfd1dd1c69a288fae923c730be213a4cf358aa6334caf57c62b54330fa2765 0001-next-is-1.4.36.patch
+23a9f56e402fc24cea33e2d4d84ed7c4c0473b4c28bab9837294756ea27b5f6682393871188ec9b3744591aa01c75804a3373999842f3e44935c87e7b0f214de 0002-use-keep-alive-timeout-while-waiting-for-HTTP-header.patch
+7ebe0117493bcea361e1dc60a394e57fb52b6d83c284af246179af58e41c2b2a95255f257fd8706c31dddf67559c8f807db1c959fd39777f5ec1d31bc48ed1c2 0003-fix-bad-shift-in-conditional-netmask-.-0-handling.patch
+85ad87b3632ad145812a1cf1bcaf321d98a000a0e50fdbbdbacf1b3a3e53e3081044da070ce41e2d2a234a82f4bfb7938ce09d8db289e5c469254d2b6cd6f487 0004-add-more-mime-types-and-a-script-to-generate-mime.co.patch
+64a75d212a8f4388be909d4f6b341f5567a028469b91db49df9ef018248ad78d6468d945c582090f762ea2f778568aedfb572e5493927cab25476966d11ef479 0005-fix-typo-in-NEWS-entry-for-2579.patch
+09d3722fa79423bb0bfc7c1fc5fd1b2a8022127b40b8a1055ac26aec369861b27b8be2394bfcf2dd0f33adc1063e7ba1d3bac3ced9e6d4d74c824c870aede879 0006-add-support-for-Free-BSD-extended-attributes.patch
+1df20ff4c5b48e60fdd8b4c37d47016667b7ad6c74ea8d4d8bb53b84bd0f90e9905fdc500df319a5288e92761500e8ddd6a15e5b946e34c819628bef6c501610 0007-build-use-fortify-flags-with-extra-warnings.patch
+9fb01cec49962a47db026befd73a13026df06b7ee16d4870394ce5c3dd3ff4c671b53425a1066a43482854dca7f4dad234100c0dc71e7647dc70202d61053a61 0008-mod_dirlisting-mod_redirect-mod_rewrite-abort-config.patch
+cb94bfb83ddbe1f2aaccf844ab262139f111dbc8cd522cfe3621e235b5e058fdf960d9245f154c0da17f5c52d1c2f56f37d473fdbb5c71ca584ce408ae9affca 0009-ssl-disable-SSL3.0-by-default.patch
+385db7d9879584e76ddd1e01a1d30bd8488a440ddc9ab014de5db72f001d6370007b0e96dd83f5875b154dd34ad289c7ed4d93b42c8143d81b0598dfbee38674 0010-Fixed-typo-found-by-openSUSE-user-boo-907709.patch
+3409867e77a2a7dfbd429e1ea8b5c45573c75c8574edd71fb206a3fc76a230f98b1232bfc3e7a77c59008c4c32155e360c972dd7ebcb42baf9671af2b388df2a 0011-add-NEWS-entry-for-previous-commit.patch
+cf5fbcc8742757bed684e23a8c2ca3fe66184fd5d5e153f54a24108a8ddde2062f4adb300211c56759a3401ae24c1b1e6313e8bb07e9688cc25a3fe83fae29e5 0012-network-fix-compile-break-in-calculation-of-sockaddr.patch
+836703b795bcb9601b6212c8b7e1be50a681e50697dc564749f1a5cc3795ecc16de4e86be98037b6fca98ba728835f3a5f7261e9b39e4ebe3824e3d58fcd7559 0013-connections-fix-bug-in-connection-state-handling.patch
+aca54c61898d26e6e729be421e96e595929646f4361dd905c22dc4aed6ba795c33c233f76961f2b6401ad60104c0fdfce263c1240aeeed29e3fc7bd7e7ed67a1 0014-print-backtrace-in-assert-logging-with-libunwind.patch
+d97bb6832e85923454ed3ff5c2d739c7f70b0141f08fe6c1326ca86eb55a75f5a4bf7e761b2d73402c0552bb76faefff2b442030d76891fade51197b34719839 0015-fix-buffer-chunk-and-http_chunk-API.patch
+f9a1c772a3a8cdc3d0e5dd6430d3ac5651cda2bb1f6dc156474477c6c9509ff98fcfe76bf89d9761970ccd8ae56c8585d51b81757b46ded356a55f8247efb248 0016-Remove-chunkqueue_get_-append-prepend-API.patch
+500ede5ad01476afe0e65d1cef22f0c89df3b91d330479cd23071aa594276560bf045de9531a61e5a15821ba5389e616fbdf6532caf25882d9ec86ec0c882a53 0017-Remove-buffer_prepare_copy-and-buffer_prepare_append.patch
+c22dad92b15655cb071c0e96f43bd1f6af55f1f4c468279814aa5643ec601d5e0ba5d0829470d6125a7da979fed7c79689af453e5b127310d7c5cfb77e0479ad 0018-tests-improve-valgrind-and-strace-TRACEME-disable-co.patch
+7d3133bd31cd413eef55cff57a4deeeb553db1c23cc17eb1655a0c02b70aa4f11ef069b47979966c1e0e6512a9b74a5bfcc50b4c91c55115b55d4861d3b95581 0019-Use-buffer-API-to-read-and-modify-used-member.patch
+0b37401c1acbf5b7bb633758024c2a09fe22a54731175fe5475217952691059fac1b757bf2a651c2f91ce2b71c010ad05b2015523954062cae5d88103f1eb783 0020-rename-buffer_append_long_hex-to-buffer_append_uint_.patch
+558a8333f509a3cbd7a4c04b745ab407e7d846a01fbd400e873dc9a18e90b8042bb46e34c0475dbfa203fe39ba201145d06384f5c1f42a2dc0894c43cc984dac 0021-buffer-constify-some-parameters.patch
+49c6c3d032b69740e1b9ae9f2c0b09d13a34a4e2aed890c12af78bfd2a2266319d282b0a2a63dab214189bcd9b4596226818dfca44dfed0f44d7494976f98b2c 0022-bitset-unused-remove.patch
+b1299b16f14feaf848344d27dd6b6529543d49b8ec26bf03de3e2fe7551254cc00eec1b3309f73b8e6541b730b047425feabb8f5c6a822757b7934825d79bbbc 0023-remove-unused-stuff-from-server.h.patch
+40f6436720ecf43370a32081da1529a9df1faee15e29056ec8832456beacfff2ea19e73b9c6377f1942d7852eaad2ea88cc1b4e49c0a317768f3b4a7cfb97cc1 0024-crc32-fix-method-signature-const-pointer.patch
+7c9772483e7d32cbc80dd9133661bf8a7542e2c571ecc9745d926de78f6879067cfd0feb7725235f23fa715febb5b810bcb352170cb8e6e09ce861961f937db4 0025-tests-fix-undefined-index-warning-in-sendfile.php.patch
+f01032d73b5a0f7b339fa4ea863767acf39a4ae84ab90eeac702eac029982017e659afc3da21198919c63a739412f12a31756cfa8ad1bcd8cc651cbd70d00b7d 0026-mod_auth-use-crypt_r-instead-of-crypt-if-available.patch
+bedd3fa6a02e315e11109ec0b5dd3ef2c3a8a250d45fdd673254cce20059165b1c96227725e01ac5e9b85fe93da2ac89770d5b2fe414bbf66063b5fe7d3ee38b 0027-fix-error-message-for-T_CONFIG_ARRAY-config-values-i.patch
+974ac318ad22aa164b860bf9273f0ccb10b08f43642bcd90008e31844d65329b89ff7100538971d068a1f42ea451639c5345dd94fe303a936e4ebd6212e431a6 0028-fix-segfaults-in-many-plugins-if-they-failed-configu.patch
+8fb56b604c89129ba84fd2d34dc38ea31eb07b377b69f8551c831d65d0076cfc7f0d9219bda4b0ad122e12102aecf29a84c6111a8bfc232f97652efc5f14e600 0029-escape-all-strings-for-logging-fixes-2646-log-file-i.patch
69b7574a8d4384bcbbca587aa643aeb55c2b237e726093d1443982d8ec1d085b15c3891a273f7901a9554df4d0842a586d59cc6062b8347e72dad8c6c37bc39a lighttpd.initd
93a05dddab14ba6355a0345f1da2fe900c8b55fed8f98506295dc12d96c7cef803c4aca77f016b8acea7bbde485be1e09a57d31fdca6f91023fbeb4db9a90a8b lighttpd.confd
e1284fe9ab4b9a53c21b40a5ac3e77e66343e187321b8a2f7464db64747f3a99f7e17a9e7c0e298db84a24fa1286cfe344dbff182eddd9de5c0605f5397a6972 lighttpd.logrotate