diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2015-07-07 14:20:33 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2015-07-07 14:20:33 +0000 |
commit | c1ee7a6e6d21447788c7512e7197d49ebfbc3096 (patch) | |
tree | f6dbf52c47e29ab57edc25ed499f7c6f4745ef75 | |
parent | 77345a923c72d9e8d0a4202d893239ba43b903a3 (diff) | |
download | aports-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
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 & 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 |