aboutsummaryrefslogtreecommitdiffstats
path: root/main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2015-07-07 14:20:33 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2015-07-07 14:20:33 +0000
commitc1ee7a6e6d21447788c7512e7197d49ebfbc3096 (patch)
treef6dbf52c47e29ab57edc25ed499f7c6f4745ef75 /main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch
parent77345a923c72d9e8d0a4202d893239ba43b903a3 (diff)
downloadaports-c1ee7a6e6d21447788c7512e7197d49ebfbc3096.tar.bz2
aports-c1ee7a6e6d21447788c7512e7197d49ebfbc3096.tar.xz
main/lighttpd: security fix for CVE-2015-3200
The upstream patch does not apply without applying lot other stuff so we simply apply all since 1.4.35 release. ref #4329
Diffstat (limited to 'main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch')
-rw-r--r--main/lighttpd/0019-Use-buffer-API-to-read-and-modify-used-member.patch4346
1 files changed, 4346 insertions, 0 deletions
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
+