diff options
Diffstat (limited to 'main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch')
-rw-r--r-- | main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch | 1537 |
1 files changed, 1537 insertions, 0 deletions
diff --git a/main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch b/main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch new file mode 100644 index 0000000000..6f265d155b --- /dev/null +++ b/main/lighttpd/0016-Remove-chunkqueue_get_-append-prepend-API.patch @@ -0,0 +1,1537 @@ +From 1be163b44a53eebb0a7b0ed562d12e3f252794e1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de> +Date: Sun, 8 Feb 2015 19:10:36 +0000 +Subject: [PATCH 16/29] Remove chunkqueue_get_{append,prepend}* API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Although those were "easy" to use, they violated the abstraction: + content of the chunkqueue should only be modified via the API. + Replace with chunkqueue_get_memory() and chunkqueue_use_memory() for + functions that read data from network (reusing large buffers), + chunkqueue_steal_with_tempfiles() to store request bodies on disk + temporarily. + Modules that were generating content and need a buffer maintain the + buffer manually (have to be careful to free the buffer on errors, as + it isn't part of the chunkqueue yet). + +From: Stefan Bühler <stbuehler@web.de> + +git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2976 152afb58-edef-0310-8abb-c4023f1b3aa9 +--- + src/buffer.c | 23 +++- + src/buffer.h | 12 ++ + src/chunk.c | 295 +++++++++++++++++++++++++++++++++++++++-------- + src/chunk.h | 39 ++++--- + src/connections.c | 195 +++++-------------------------- + src/mod_compress.c | 4 +- + src/mod_dirlisting.c | 4 +- + src/mod_fastcgi.c | 76 +++++------- + src/mod_flv_streaming.c | 6 +- + src/mod_proxy.c | 5 +- + src/mod_scgi.c | 4 +- + src/mod_ssi.c | 63 +++++----- + src/mod_staticfile.c | 13 +-- + src/mod_status.c | 42 ++++--- + src/mod_uploadprogress.c | 11 +- + src/mod_webdav.c | 18 ++- + src/response.c | 6 +- + 17 files changed, 465 insertions(+), 351 deletions(-) + +diff --git a/src/buffer.c b/src/buffer.c +index caaa5bb..019abb7 100644 +--- a/src/buffer.c ++++ b/src/buffer.c +@@ -139,6 +139,27 @@ char* buffer_prepare_append(buffer *b, size_t size) { + return b->ptr + b->used - 1; + } + ++char* buffer_string_prepare_copy(buffer *b, size_t size) { ++ force_assert(NULL != b); ++ ++ buffer_prepare_copy(b, size); ++ b->used = 1; ++ ++ return b->ptr; ++} ++ ++char* buffer_string_prepare_append(buffer *b, size_t size) { ++ force_assert(NULL != b); ++ ++ if (0 == b->used) { ++ return buffer_string_prepare_copy(b, size); ++ } else { ++ force_assert('\0' == b->ptr[b->used - 1]); ++ return buffer_prepare_append(b, size); ++ } ++} ++ ++ + void buffer_commit(buffer *b, size_t size) + { + force_assert(NULL != b); +@@ -231,7 +252,7 @@ void buffer_append_long_hex(buffer *b, unsigned long value) { + } while (0 != copy); + } + +- buf = buffer_prepare_append(b, shift); ++ buf = buffer_string_prepare_append(b, shift); + buffer_commit(b, shift); /* will fill below */ + + shift <<= 2; /* count bits now */ +diff --git a/src/buffer.h b/src/buffer.h +index ff57d68..5d540a4 100644 +--- a/src/buffer.h ++++ b/src/buffer.h +@@ -62,6 +62,11 @@ char* buffer_prepare_copy(buffer *b, size_t size); + */ + char* buffer_prepare_append(buffer *b, size_t size); + ++/* similar to buffer_prepare_copy(b, size), but sets b->used = 1 */ ++char* buffer_string_prepare_copy(buffer *b, size_t size); ++/* similar to buffer_prepare_append(b, size), but sets b->used = 1 if used was b->0 before */ ++char* buffer_string_prepare_append(buffer *b, size_t size); ++ + /* use after prepare_(copy,append) when you have written data to the buffer + * to increase the buffer length by size. also sets the terminating zero. + * requires enough space is present for the terminating zero (prepare with the +@@ -136,6 +141,7 @@ int light_isalpha(int c); + int light_isalnum(int c); + + static inline size_t buffer_string_length(const buffer *b); /* buffer string length without terminating 0 */ ++static inline size_t buffer_string_space(const buffer *b); /* maximum length of string that can be stored without reallocating */ + static inline void buffer_append_slash(buffer *b); /* append '/' no non-empty strings not ending in '/' */ + + #define BUFFER_APPEND_STRING_CONST(x, y) \ +@@ -161,6 +167,12 @@ static inline size_t buffer_string_length(const buffer *b) { + return NULL != b && 0 != b->used ? b->used - 1 : 0; + } + ++static inline size_t buffer_string_space(const buffer *b) { ++ if (NULL == b || b->size == 0) return 0; ++ if (0 == b->used) return b->size - 1; ++ return b->size - b->used; ++} ++ + static inline void buffer_append_slash(buffer *b) { + size_t len = buffer_string_length(b); + if (len > 0 && '/' != b->ptr[len-1]) BUFFER_APPEND_STRING_CONST(b, "/"); +diff --git a/src/chunk.c b/src/chunk.c +index c991b82..83adc15 100644 +--- a/src/chunk.c ++++ b/src/chunk.c +@@ -5,6 +5,8 @@ + */ + + #include "chunk.h" ++#include "base.h" ++#include "log.h" + + #include <sys/types.h> + #include <sys/stat.h> +@@ -233,28 +235,84 @@ void chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) { + chunkqueue_append_chunk(cq, c); + } + +-buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) { ++void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_size, size_t alloc_size) { ++ static const size_t REALLOC_MAX_SIZE = 256; + chunk *c; ++ buffer *b; ++ char *dummy_mem; ++ size_t dummy_len; + +- c = chunkqueue_get_unused_chunk(cq); ++ force_assert(NULL != cq); ++ if (NULL == mem) mem = &dummy_mem; ++ if (NULL == len) len = &dummy_len; + +- c->type = MEM_CHUNK; ++ /* default values: */ ++ if (0 == min_size) min_size = 1024; ++ if (0 == alloc_size) alloc_size = 4096; ++ if (alloc_size < min_size) alloc_size = min_size; + +- chunkqueue_prepend_chunk(cq, c); ++ if (NULL != cq->last && MEM_CHUNK == cq->last->type) { ++ size_t have; + +- return c->mem; +-} ++ b = cq->last->mem; ++ have = buffer_string_space(b); + +-buffer *chunkqueue_get_append_buffer(chunkqueue *cq) { +- chunk *c; ++ /* unused buffer: allocate space */ ++ if (buffer_string_is_empty(b)) { ++ buffer_string_prepare_copy(b, alloc_size); ++ have = buffer_string_space(b); ++ } ++ /* if buffer is really small just make it bigger */ ++ else if (have < min_size && b->size <= REALLOC_MAX_SIZE) { ++ size_t new_size = b->used + min_size, append; ++ if (new_size < alloc_size) new_size = alloc_size; ++ ++ append = new_size - b->used; ++ if (append >= min_size) { ++ buffer_string_prepare_append(b, append); ++ have = buffer_string_space(b); ++ } ++ } + +- c = chunkqueue_get_unused_chunk(cq); ++ /* return pointer into existing buffer if large enough */ ++ if (have >= min_size) { ++ *mem = b->ptr + buffer_string_length(b); ++ *len = have; ++ return; ++ } ++ } + ++ /* allocate new chunk */ ++ c = chunkqueue_get_unused_chunk(cq); + c->type = MEM_CHUNK; +- + chunkqueue_append_chunk(cq, c); + +- return c->mem; ++ b = c->mem; ++ buffer_string_prepare_append(b, alloc_size); ++ ++ *mem = b->ptr + buffer_string_length(b); ++ *len = buffer_string_space(b); ++} ++ ++void chunkqueue_use_memory(chunkqueue *cq, size_t len) { ++ buffer *b; ++ ++ force_assert(NULL != cq); ++ force_assert(NULL != cq->last && MEM_CHUNK == cq->last->type); ++ b = cq->last->mem; ++ ++ force_assert(b->used > 0); ++ force_assert(len <= buffer_string_space(b)); ++ ++ if (len > 0) { ++ b->used += len; ++ b->ptr[b->used - 1] = '\0'; ++ } else if (buffer_string_is_empty(b)) { ++ /* unused buffer: can't remove chunk easily from ++ * end of list, so just reset the buffer ++ */ ++ buffer_reset(b); ++ } + } + + void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) { +@@ -262,13 +320,67 @@ void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) { + cq->tempdirs = tempdirs; + } + +-chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { +- chunk *c; +- buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX"); ++void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) { ++ while (len > 0) { ++ chunk *c = src->first; ++ off_t clen = 0, use; + +- c = chunkqueue_get_unused_chunk(cq); ++ if (NULL == c) break; + +- c->type = FILE_CHUNK; ++ switch (c->type) { ++ case MEM_CHUNK: ++ clen = buffer_string_length(c->mem); ++ break; ++ case FILE_CHUNK: ++ clen = c->file.length; ++ break; ++ } ++ force_assert(clen >= c->offset); ++ clen -= c->offset; ++ use = len >= clen ? clen : len; ++ ++ src->bytes_out += use; ++ dest->bytes_in += use; ++ len -= use; ++ ++ if (0 == clen) { ++ /* drop empty chunk */ ++ src->first = c->next; ++ if (c == src->last) src->last = NULL; ++ chunkqueue_push_unused_chunk(src, c); ++ continue; ++ } ++ ++ if (use == clen) { ++ /* move complete chunk */ ++ src->first = c->next; ++ if (c == src->last) src->last = NULL; ++ ++ chunkqueue_append_chunk(dest, c); ++ continue; ++ } ++ ++ /* partial chunk with length "use" */ ++ ++ switch (c->type) { ++ case MEM_CHUNK: ++ chunkqueue_append_mem(dest, c->mem->ptr + c->offset, use); ++ break; ++ case FILE_CHUNK: ++ /* tempfile flag is in "last" chunk after the split */ ++ chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, use); ++ break; ++ } ++ ++ c->offset += use; ++ force_assert(0 == len); ++ } ++} ++ ++static chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { ++ chunk *c; ++ buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX"); ++ int fd; + + if (cq->tempdirs && cq->tempdirs->used) { + size_t i; +@@ -282,19 +394,21 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { + buffer_append_slash(template); + buffer_append_string_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX")); + +- if (-1 != (c->file.fd = mkstemp(template->ptr))) { +- /* only trigger the unlink if we created the temp-file successfully */ +- c->file.is_temp = 1; +- break; +- } ++ if (-1 != (fd = mkstemp(template->ptr))) break; + } + } else { +- if (-1 != (c->file.fd = mkstemp(template->ptr))) { +- /* only trigger the unlink if we created the temp-file successfully */ +- c->file.is_temp = 1; +- } ++ fd = mkstemp(template->ptr); + } + ++ if (-1 == fd) { ++ buffer_free(template); ++ return NULL; ++ } ++ ++ c = chunkqueue_get_unused_chunk(cq); ++ c->type = FILE_CHUNK; ++ c->file.fd = fd; ++ c->file.is_temp = 1; + buffer_copy_buffer(c->file.name, template); + c->file.length = 0; + +@@ -305,10 +419,76 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { + return c; + } + +-void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) { ++static int chunkqueue_append_to_tempfile(server *srv, chunkqueue *dest, const char *mem, size_t len) { ++ chunk *dst_c = NULL; ++ ssize_t written; ++ /* copy everything to max 1Mb sized tempfiles */ ++ ++ /* ++ * if the last chunk is ++ * - smaller than 1Mb (size < 1Mb) ++ * - not read yet (offset == 0) ++ * -> append to it ++ * otherwise ++ * -> create a new chunk ++ * ++ * */ ++ ++ if (NULL != dest->last ++ && FILE_CHUNK != dest->last->type ++ && dest->last->file.is_temp ++ && -1 != dest->last->file.fd ++ && 0 == dest->last->offset) { ++ /* ok, take the last chunk for our job */ ++ dst_c = dest->last; ++ ++ if (dest->last->file.length >= 1 * 1024 * 1024) { ++ /* the chunk is too large now, close it */ ++ if (-1 != dst_c->file.fd) { ++ close(dst_c->file.fd); ++ dst_c->file.fd = -1; ++ } ++ dst_c = chunkqueue_get_append_tempfile(dest); ++ } ++ } else { ++ dst_c = chunkqueue_get_append_tempfile(dest); ++ } ++ ++ if (NULL == dst_c) { ++ /* we don't have file to write to, ++ * EACCES might be one reason. ++ * ++ * Instead of sending 500 we send 413 and say the request is too large ++ */ ++ ++ log_error_write(srv, __FILE__, __LINE__, "sbs", ++ "denying upload as opening temp-file for upload failed:", ++ dst_c->file.name, strerror(errno)); ++ ++ return -1; ++ } ++ ++ if (0 > (written = write(dst_c->file.fd, mem, len)) || (size_t) written != len) { ++ /* write failed for some reason ... disk full ? */ ++ log_error_write(srv, __FILE__, __LINE__, "sbs", ++ "denying upload as writing to file failed:", ++ dst_c->file.name, strerror(errno)); ++ ++ close(dst_c->file.fd); ++ dst_c->file.fd = -1; ++ ++ return -1; ++ } ++ ++ dst_c->file.length += len; ++ ++ return 0; ++} ++ ++int chunkqueue_steal_with_tempfiles(server *srv, chunkqueue *dest, chunkqueue *src, off_t len) { + while (len > 0) { + chunk *c = src->first; +- off_t clen = 0; ++ off_t clen = 0, use; + + if (NULL == c) break; + +@@ -322,36 +502,57 @@ void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) { + } + force_assert(clen >= c->offset); + clen -= c->offset; ++ use = len >= clen ? clen : len; + +- if (len >= clen) { +- /* move complete chunk */ ++ src->bytes_out += use; ++ dest->bytes_in += use; ++ len -= use; ++ ++ if (0 == clen) { ++ /* drop empty chunk */ + src->first = c->next; + if (c == src->last) src->last = NULL; +- +- chunkqueue_append_chunk(dest, c); +- src->bytes_out += clen; +- dest->bytes_in += clen; +- len -= clen; ++ chunkqueue_push_unused_chunk(src, c); + continue; + } + +- /* partial chunk with length "len" */ ++ if (FILE_CHUNK == c->type) { ++ if (use == clen) { ++ /* move complete chunk */ ++ src->first = c->next; ++ if (c == src->last) src->last = NULL; + +- switch (c->type) { +- case MEM_CHUNK: +- chunkqueue_append_mem(dest, c->mem->ptr + c->offset, len); +- break; +- case FILE_CHUNK: +- /* tempfile flag is in "last" chunk after the split */ +- chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, len); +- break; ++ chunkqueue_append_chunk(dest, c); ++ } else { ++ /* partial chunk with length "use" */ ++ /* tempfile flag is in "last" chunk after the split */ ++ chunkqueue_append_file(dest, c->file.name, c->file.start + c->offset, use); ++ ++ c->offset += use; ++ force_assert(0 == len); ++ } ++ continue; + } + +- c->offset += len; +- src->bytes_out += len; +- dest->bytes_in += len; +- len = 0; ++ /* store "use" bytes from memory chunk in tempfile */ ++ if (0 != chunkqueue_append_to_tempfile(srv, dest, c->mem->ptr + c->offset, use)) { ++ /* undo counters */ ++ src->bytes_out -= use; ++ dest->bytes_in -= use; ++ return -1; ++ } ++ ++ ++ c->offset += use; ++ if (use == clen) { ++ /* finished chunk */ ++ src->first = c->next; ++ if (c == src->last) src->last = NULL; ++ chunkqueue_push_unused_chunk(src, c); ++ } + } ++ ++ return 0; + } + + off_t chunkqueue_length(chunkqueue *cq) { +diff --git a/src/chunk.h b/src/chunk.h +index 6559000..33b7e27 100644 +--- a/src/chunk.h ++++ b/src/chunk.h +@@ -48,24 +48,37 @@ typedef struct { + } chunkqueue; + + chunkqueue *chunkqueue_init(void); +-void chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs); +-void chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len); /* copies "fn" */ +-void chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len); /* copies memory */ +-void chunkqueue_append_buffer(chunkqueue *c, buffer *mem); /* may reset "mem" */ +-void chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem); /* may reset "mem" */ +- +-buffer * chunkqueue_get_append_buffer(chunkqueue *c); +-buffer * chunkqueue_get_prepend_buffer(chunkqueue *c); +-chunk * chunkqueue_get_append_tempfile(chunkqueue *cq); ++void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs); ++void chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len); /* copies "fn" */ ++void chunkqueue_append_mem(chunkqueue *cq, const char *mem, size_t len); /* copies memory */ ++void chunkqueue_append_buffer(chunkqueue *cq, buffer *mem); /* may reset "mem" */ ++void chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem); /* may reset "mem" */ ++ ++/* functions to handle buffers to read into: */ ++/* return a pointer to a buffer in *mem with size *len; ++ * it should be at least min_size big, and use alloc_size if ++ * new memory is allocated. ++ * modifying the chunkqueue invalidates the memory area. ++ * should always be followed by chunkqueue_get_memory(), ++ * even if nothing was read. ++ * pass 0 for min_size/alloc_size for default values ++ */ ++void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_size, size_t alloc_size); ++/* append first len bytes of the memory queried with ++ * chunkqueue_get_memory to the chunkqueue ++ */ ++void chunkqueue_use_memory(chunkqueue *cq, size_t len); + + void chunkqueue_remove_finished_chunks(chunkqueue *cq); + + void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len); ++struct server; ++int chunkqueue_steal_with_tempfiles(struct server *srv, chunkqueue *dest, chunkqueue *src, off_t len); + +-off_t chunkqueue_length(chunkqueue *c); +-void chunkqueue_free(chunkqueue *c); +-void chunkqueue_reset(chunkqueue *c); ++off_t chunkqueue_length(chunkqueue *cq); ++void chunkqueue_free(chunkqueue *cq); ++void chunkqueue_reset(chunkqueue *cq); + +-int chunkqueue_is_empty(chunkqueue *c); ++int chunkqueue_is_empty(chunkqueue *cq); + + #endif +diff --git a/src/connections.c b/src/connections.c +index bc770bf..3fab768 100644 +--- a/src/connections.c ++++ b/src/connections.c +@@ -197,31 +197,22 @@ static void dump_packet(const unsigned char *data, size_t len) { + + static int connection_handle_read_ssl(server *srv, connection *con) { + #ifdef USE_OPENSSL +- int r, ssl_err, len, count = 0, read_offset, toread; +- buffer *b = NULL; ++ int r, ssl_err, len, count = 0; ++ char *mem = NULL; ++ size_t mem_len = 0; + + if (!con->srv_socket->is_ssl) return -1; + + ERR_clear_error(); + do { +- if (NULL != con->read_queue->last) { +- b = con->read_queue->last->mem; +- } +- +- if (NULL == b || b->size - b->used < 1024) { +- b = chunkqueue_get_append_buffer(con->read_queue); +- len = SSL_pending(con->ssl); +- if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */ +- buffer_prepare_copy(b, len); +- +- /* overwrite everything with 0 */ +- memset(b->ptr, 0, b->size); +- } +- +- read_offset = (b->used > 0) ? b->used - 1 : 0; +- toread = b->size - 1 - read_offset; ++ chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl)); ++#if 0 ++ /* overwrite everything with 0 */ ++ memset(mem, 0, mem_len); ++#endif + +- len = SSL_read(con->ssl, b->ptr + read_offset, toread); ++ len = SSL_read(con->ssl, mem, mem_len); ++ chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0); + + if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) { + log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection"); +@@ -230,15 +221,10 @@ static int connection_handle_read_ssl(server *srv, connection *con) { + } + + if (len > 0) { +- if (b->used > 0) b->used--; +- b->used += len; +- b->ptr[b->used++] = '\0'; +- + con->bytes_read += len; +- + count += len; + } +- } while (len == toread && count < MAX_READ_LIMIT); ++ } while (len == (ssize_t) mem_len && count < MAX_READ_LIMIT); + + + if (len < 0) { +@@ -331,44 +317,36 @@ static int connection_handle_read_ssl(server *srv, connection *con) { + /* 0: everything ok, -1: error, -2: con closed */ + static int connection_handle_read(server *srv, connection *con) { + int len; +- buffer *b; +- int toread, read_offset; ++ char *mem = NULL; ++ size_t mem_len = 0; ++ int toread; + + if (con->srv_socket->is_ssl) { + return connection_handle_read_ssl(srv, con); + } + +- b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL; +- + /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells + * us more than 4kb is available + * if FIONREAD doesn't signal a big chunk we fill the previous buffer + * if it has >= 1kb free + */ + #if defined(__WIN32) +- if (NULL == b || b->size - b->used < 1024) { +- b = chunkqueue_get_append_buffer(con->read_queue); +- buffer_prepare_copy(b, 4 * 1024); +- } ++ chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096); + +- read_offset = (b->used == 0) ? 0 : b->used - 1; +- len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0); ++ len = recv(con->fd, mem, mem_len, 0); + #else + if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) { +- if (NULL == b || b->size - b->used < 1024) { +- b = chunkqueue_get_append_buffer(con->read_queue); +- buffer_prepare_copy(b, 4 * 1024); +- } +- } else { + if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT; +- b = chunkqueue_get_append_buffer(con->read_queue); +- buffer_prepare_copy(b, toread); ++ } else { ++ toread = 4096; + } ++ chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread); + +- read_offset = (b->used == 0) ? 0 : b->used - 1; +- len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset); ++ len = read(con->fd, mem, mem_len); + #endif + ++ chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0); ++ + if (len < 0) { + con->is_readable = 0; + +@@ -394,16 +372,12 @@ static int connection_handle_read(server *srv, connection *con) { + /* pipelining */ + + return -2; +- } else if ((size_t)len < b->size - 1) { ++ } else if (len != (ssize_t) mem_len) { + /* we got less then expected, wait for the next fd-event */ + + con->is_readable = 0; + } + +- if (b->used > 0) b->used--; +- b->used += len; +- b->ptr[b->used++] = '\0'; +- + con->bytes_read += len; + #if 0 + dump_packet(b->ptr, len); +@@ -494,7 +468,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) { + buffer_reset(con->physical.path); + + con->file_finished = 1; +- b = chunkqueue_get_append_buffer(con->write_queue); ++ b = buffer_init(); + + /* build default error-page */ + buffer_copy_string_len(b, CONST_STR_LEN( +@@ -522,6 +496,10 @@ static int connection_handle_write_prepare(server *srv, connection *con) { + "</html>\n" + )); + ++ http_chunk_append_buffer(srv, con, b); ++ buffer_free(b); ++ http_chunk_close(srv, con); ++ + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + } + break; +@@ -1029,119 +1007,10 @@ found_header_end: + } + break; + case CON_STATE_READ_POST: +- for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) { +- off_t weWant, weHave, toRead; +- +- weWant = con->request.content_length - dst_cq->bytes_in; +- +- force_assert(c->mem->used); +- +- weHave = c->mem->used - c->offset - 1; +- +- toRead = weHave > weWant ? weWant : weHave; +- +- /* the new way, copy everything into a chunkqueue whcih might use tempfiles */ +- if (con->request.content_length > 64 * 1024) { +- chunk *dst_c = NULL; +- /* copy everything to max 1Mb sized tempfiles */ +- +- /* +- * if the last chunk is +- * - smaller than 1Mb (size < 1Mb) +- * - not read yet (offset == 0) +- * -> append to it +- * otherwise +- * -> create a new chunk +- * +- * */ +- +- if (dst_cq->last && +- dst_cq->last->type == FILE_CHUNK && +- dst_cq->last->file.is_temp && +- dst_cq->last->offset == 0) { +- /* ok, take the last chunk for our job */ +- +- if (dst_cq->last->file.length < 1 * 1024 * 1024) { +- dst_c = dst_cq->last; +- +- if (dst_c->file.fd == -1) { +- /* this should not happen as we cache the fd, but you never know */ +- dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND); +- fd_close_on_exec(dst_c->file.fd); +- } +- } else { +- /* the chunk is too large now, close it */ +- dst_c = dst_cq->last; +- +- if (dst_c->file.fd != -1) { +- close(dst_c->file.fd); +- dst_c->file.fd = -1; +- } +- dst_c = chunkqueue_get_append_tempfile(dst_cq); +- } +- } else { +- dst_c = chunkqueue_get_append_tempfile(dst_cq); +- } +- +- /* we have a chunk, let's write to it */ +- +- if (dst_c->file.fd == -1) { +- /* we don't have file to write to, +- * EACCES might be one reason. +- * +- * Instead of sending 500 we send 413 and say the request is too large +- * */ +- +- log_error_write(srv, __FILE__, __LINE__, "sbs", +- "denying upload as opening to temp-file for upload failed:", +- dst_c->file.name, strerror(errno)); +- +- con->http_status = 413; /* Request-Entity too large */ +- con->keep_alive = 0; +- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); +- +- break; +- } +- +- if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) { +- /* write failed for some reason ... disk full ? */ +- log_error_write(srv, __FILE__, __LINE__, "sbs", +- "denying upload as writing to file failed:", +- dst_c->file.name, strerror(errno)); +- +- con->http_status = 413; /* Request-Entity too large */ +- con->keep_alive = 0; +- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); +- +- close(dst_c->file.fd); +- dst_c->file.fd = -1; +- +- break; +- } +- +- dst_c->file.length += toRead; +- +- if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) { +- /* we read everything, close the chunk */ +- close(dst_c->file.fd); +- dst_c->file.fd = -1; +- } +- } else { +- buffer *b; +- +- if (dst_cq->last && +- dst_cq->last->type == MEM_CHUNK) { +- b = dst_cq->last->mem; +- } else { +- b = chunkqueue_get_append_buffer(dst_cq); +- /* prepare buffer size for remaining POST data; is < 64kb */ +- buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in); +- } +- buffer_append_string_len(b, c->mem->ptr + c->offset, toRead); +- } +- +- c->offset += toRead; +- dst_cq->bytes_in += toRead; ++ if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, con->request.content_length - dst_cq->bytes_in )) { ++ con->http_status = 413; /* Request-Entity too large */ ++ con->keep_alive = 0; ++ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + } + + /* Content is ready */ +diff --git a/src/mod_compress.c b/src/mod_compress.c +index ad6e9f2..b428cd0 100644 +--- a/src/mod_compress.c ++++ b/src/mod_compress.c +@@ -583,7 +583,6 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, + int ifd; + int ret = -1; + void *start; +- buffer *b; + + /* overflow */ + if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1; +@@ -651,8 +650,7 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, + if (ret != 0) return -1; + + chunkqueue_reset(con->write_queue); +- b = chunkqueue_get_append_buffer(con->write_queue); +- buffer_copy_string_len(b, p->b->ptr, p->b->used); ++ chunkqueue_append_mem(con->write_queue, p->b->ptr, p->b->used); + + buffer_reset(con->physical.path); + +diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c +index 4b7106a..e2e0bfa 100644 +--- a/src/mod_dirlisting.c ++++ b/src/mod_dirlisting.c +@@ -784,7 +784,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf + + if (files.used) http_dirls_sort(files.ent, files.used); + +- out = chunkqueue_get_append_buffer(con->write_queue); ++ out = buffer_init(); + buffer_copy_string_len(out, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"")); + if (buffer_string_is_empty(p->conf.encoding)) { + buffer_append_string_len(out, CONST_STR_LEN("iso-8859-1")); +@@ -899,6 +899,8 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf + } + + con->file_finished = 1; ++ chunkqueue_append_buffer(con->write_queue, out); ++ buffer_free(out); + + return 0; + } +diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c +index 01e72e5..e7b62f6 100644 +--- a/src/mod_fastcgi.c ++++ b/src/mod_fastcgi.c +@@ -52,13 +52,6 @@ + + #include "version.h" + +-#define FCGI_ENV_ADD_CHECK(ret, con) \ +- if (ret == -1) { \ +- con->http_status = 400; \ +- con->file_finished = 1; \ +- return -1; \ +- }; +- + /* + * + * TODO: +@@ -1769,6 +1762,12 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h + return CONNECTION_OK; + } + ++#define FCGI_ENV_ADD_CHECK(ret, con) \ ++ if (ret == -1) { \ ++ con->http_status = 400; \ ++ con->file_finished = 1; \ ++ return -1; \ ++ }; + static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) { + size_t i; + +@@ -1834,11 +1833,9 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat + return 0; + } + +- + static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { + FCGI_BeginRequestRecord beginRecord; + FCGI_Header header; +- buffer *b; + + char buf[LI_ITOSTRING_LENGTH]; + const char *s; +@@ -1863,10 +1860,6 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { + beginRecord.body.flags = 0; + memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved)); + +- b = chunkqueue_get_append_buffer(hctx->wb); +- +- buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord)); +- + /* send FCGI_PARAMS */ + buffer_prepare_copy(p->fcgi_env, 1024); + +@@ -2054,14 +2047,22 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { + + FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con); + +- fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0); +- buffer_append_string_len(b, (const char *)&header, sizeof(header)); +- buffer_append_string_len(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used); ++ { ++ buffer *b = buffer_init(); + +- fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0); +- buffer_append_string_len(b, (const char *)&header, sizeof(header)); ++ buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord)); + +- hctx->wb->bytes_in += b->used - 1; ++ fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0); ++ buffer_append_string_len(b, (const char *)&header, sizeof(header)); ++ buffer_append_string_len(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used); ++ ++ fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0); ++ buffer_append_string_len(b, (const char *)&header, sizeof(header)); ++ ++ hctx->wb->bytes_in += b->used - 1; ++ chunkqueue_append_buffer(hctx->wb, b); ++ buffer_free(b); ++ } + + if (con->request.content_length) { + chunkqueue *req_cq = con->request_content_queue; +@@ -2433,38 +2434,21 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { + return -1; + } + +- /* init read-buffer */ +- + if (toread > 0) { +- buffer *b; +- chunk *cq_first = hctx->rb->first; +- chunk *cq_last = hctx->rb->last; +- +- b = chunkqueue_get_append_buffer(hctx->rb); +- buffer_prepare_copy(b, toread + 1); +- +- /* append to read-buffer */ +- if (-1 == (r = read(hctx->fd, b->ptr, toread))) { +- if (errno == EAGAIN) { +- /* roll back the last chunk allocation, +- and continue on next iteration */ +- buffer_free(hctx->rb->last->mem); +- free(hctx->rb->last); +- hctx->rb->first = cq_first; +- hctx->rb->last = cq_last; +- return 0; +- } ++ char *mem; ++ size_t mem_len; ++ ++ chunkqueue_get_memory(hctx->rb, &mem, &mem_len, 0, toread); ++ r = read(hctx->fd, mem, mem_len); ++ chunkqueue_use_memory(hctx->rb, r > 0 ? r : 0); ++ ++ if (-1 == r) { ++ if (errno == EAGAIN) return 0; + log_error_write(srv, __FILE__, __LINE__, "sds", + "unexpected end-of-file (perhaps the fastcgi process died):", + fcgi_fd, strerror(errno)); + return -1; + } +- +- /* this should be catched by the b > 0 above */ +- force_assert(r); +- +- b->used = r + 1; /* one extra for the fake \0 */ +- b->ptr[b->used - 1] = '\0'; + } else { + log_error_write(srv, __FILE__, __LINE__, "ssdsb", + "unexpected end-of-file (perhaps the fastcgi process died):", +@@ -2973,8 +2957,8 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { + "fcgi-request is already in use:", hctx->request_id); + } + +- /* fall through */ + if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR; ++ + fcgi_set_state(srv, hctx, FCGI_STATE_WRITE); + /* fall through */ + case FCGI_STATE_WRITE: +diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c +index 501f8e8..1c1a356 100644 +--- a/src/mod_flv_streaming.c ++++ b/src/mod_flv_streaming.c +@@ -207,7 +207,6 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) { + if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { + data_string *get_param; + stat_cache_entry *sce = NULL; +- buffer *b; + int start; + char *err = NULL; + /* if there is a start=[0-9]+ in the header use it as start, +@@ -242,10 +241,9 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) { + } + + /* we are safe now, let's build a flv header */ +- b = chunkqueue_get_append_buffer(con->write_queue); +- buffer_copy_string_len(b, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9")); +- ++ http_chunk_append_mem(srv, con, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9")); + http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start); ++ http_chunk_close(srv, con); + + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv")); + +diff --git a/src/mod_proxy.c b/src/mod_proxy.c +index 3bfc78f..2b5a740 100644 +--- a/src/mod_proxy.c ++++ b/src/mod_proxy.c +@@ -449,7 +449,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { + + /* build header */ + +- b = chunkqueue_get_append_buffer(hctx->wb); ++ b = buffer_init(); + + /* request line */ + buffer_copy_string(b, get_http_method_name(con->request.http_method)); +@@ -486,6 +486,9 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { + buffer_append_string_len(b, CONST_STR_LEN("\r\n")); + + hctx->wb->bytes_in += b->used - 1; ++ chunkqueue_append_buffer(hctx->wb, b); ++ buffer_free(b); ++ + /* body */ + + if (con->request.content_length) { +diff --git a/src/mod_scgi.c b/src/mod_scgi.c +index 66dce5e..2fa265d 100644 +--- a/src/mod_scgi.c ++++ b/src/mod_scgi.c +@@ -1629,7 +1629,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { + + scgi_env_add_request_headers(srv, con, p); + +- b = chunkqueue_get_append_buffer(hctx->wb); ++ b = buffer_init(); + + buffer_append_int(b, p->scgi_env->used); + buffer_append_string_len(b, CONST_STR_LEN(":")); +@@ -1637,6 +1637,8 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { + buffer_append_string_len(b, CONST_STR_LEN(",")); + + hctx->wb->bytes_in += b->used - 1; ++ chunkqueue_append_buffer(hctx->wb, b); ++ buffer_free(b); + + if (con->request.content_length) { + chunkqueue *req_cq = con->request_content_queue; +diff --git a/src/mod_ssi.c b/src/mod_ssi.c +index 38eeac5..ecdfb99 100644 +--- a/src/mod_ssi.c ++++ b/src/mod_ssi.c +@@ -430,7 +430,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + case SSI_ECHO_USER_NAME: { + struct passwd *pw; + +- b = chunkqueue_get_append_buffer(con->write_queue); ++ b = buffer_init(); + #ifdef HAVE_PWD_H + if (NULL == (pw = getpwuid(sce->st.st_uid))) { + buffer_copy_int(b, sce->st.st_uid); +@@ -440,67 +440,62 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + #else + buffer_copy_int(b, sce->st.st_uid); + #endif ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); + break; + } + case SSI_ECHO_LAST_MODIFIED: { + time_t t = sce->st.st_mtime; + +- b = chunkqueue_get_append_buffer(con->write_queue); + if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) { +- buffer_copy_string_len(b, CONST_STR_LEN("(none)")); ++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)")); + } else { +- buffer_copy_string(b, buf); ++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf)); + } + break; + } + case SSI_ECHO_DATE_LOCAL: { + time_t t = time(NULL); + +- b = chunkqueue_get_append_buffer(con->write_queue); + if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) { +- buffer_copy_string_len(b, CONST_STR_LEN("(none)")); ++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)")); + } else { +- buffer_copy_string(b, buf); ++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf)); + } + break; + } + case SSI_ECHO_DATE_GMT: { + time_t t = time(NULL); + +- b = chunkqueue_get_append_buffer(con->write_queue); + if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) { +- buffer_copy_string_len(b, CONST_STR_LEN("(none)")); ++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)")); + } else { +- buffer_copy_string(b, buf); ++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf)); + } + break; + } + case SSI_ECHO_DOCUMENT_NAME: { + char *sl; + +- b = chunkqueue_get_append_buffer(con->write_queue); + if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) { +- buffer_copy_buffer(b, con->physical.path); ++ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->physical.path)); + } else { +- buffer_copy_string(b, sl + 1); ++ chunkqueue_append_mem(con->write_queue, sl + 1, strlen(sl + 1)); + } + break; + } + case SSI_ECHO_DOCUMENT_URI: { +- b = chunkqueue_get_append_buffer(con->write_queue); +- buffer_copy_buffer(b, con->uri.path); ++ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.path)); + break; + } + default: { + data_string *ds; + /* check if it is a cgi-var */ + +- b = chunkqueue_get_append_buffer(con->write_queue); +- + if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) { +- buffer_copy_buffer(b, ds->value); ++ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(ds->value)); + } else { +- buffer_copy_string_len(b, CONST_STR_LEN("(none)")); ++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)")); + } + + break; +@@ -583,7 +578,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + + switch (ssicmd) { + case SSI_FSIZE: +- b = chunkqueue_get_append_buffer(con->write_queue); ++ b = buffer_init(); + if (p->sizefmt) { + int j = 0; + const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL }; +@@ -597,13 +592,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + } else { + buffer_copy_int(b, st.st_size); + } ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); + break; + case SSI_FLASTMOD: +- b = chunkqueue_get_append_buffer(con->write_queue); + if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) { +- buffer_copy_string_len(b, CONST_STR_LEN("(none)")); ++ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)")); + } else { +- buffer_copy_string(b, buf); ++ chunkqueue_append_mem(con->write_queue, buf, strlen(buf)); + } + break; + case SSI_INCLUDE: +@@ -611,7 +607,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + + /* Keep the newest mtime of included files */ + if (st.st_mtime > include_file_last_mtime) +- include_file_last_mtime = st.st_mtime; ++ include_file_last_mtime = st.st_mtime; + + break; + } +@@ -683,7 +679,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + case SSI_PRINTENV: + if (p->if_is_false) break; + +- b = chunkqueue_get_append_buffer(con->write_queue); ++ b = buffer_init(); + for (i = 0; i < p->ssi_vars->used; i++) { + data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]]; + +@@ -700,6 +696,8 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML); + buffer_append_string_len(b, CONST_STR_LEN("\n")); + } ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); + + break; + case SSI_EXEC: { +@@ -791,17 +789,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const + } + + if (toread > 0) { +- b = chunkqueue_get_append_buffer(con->write_queue); ++ char *mem; ++ size_t mem_len; + +- buffer_prepare_copy(b, toread); ++ chunkqueue_get_memory(con->write_queue, &mem, &mem_len, 0, toread); ++ r = read(from_exec_fds[0], mem, mem_len); ++ chunkqueue_use_memory(con->write_queue, r > 0 ? r : 0); + +- if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) { +- /* read failed */ +- break; +- } else { +- b->used = r; +- b->ptr[b->used++] = '\0'; +- } ++ if (r < 0) break; /* read failed */ + } else { + break; + } +diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c +index 931bc57..e36c697 100644 +--- a/src/mod_staticfile.c ++++ b/src/mod_staticfile.c +@@ -285,9 +285,7 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data * + if (!error) { + if (multipart) { + /* write boundary-header */ +- buffer *b; +- +- b = chunkqueue_get_append_buffer(con->write_queue); ++ buffer *b = buffer_init(); + + buffer_copy_string_len(b, CONST_STR_LEN("\r\n--")); + buffer_append_string(b, boundary); +@@ -307,7 +305,8 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data * + buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); + + con->response.content_length += b->used - 1; +- ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); + } + + chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1); +@@ -320,15 +319,15 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data * + + if (multipart) { + /* add boundary end */ +- buffer *b; +- +- b = chunkqueue_get_append_buffer(con->write_queue); ++ buffer *b = buffer_init(); + + buffer_copy_string_len(b, "\r\n--", 4); + buffer_append_string(b, boundary); + buffer_append_string_len(b, "--\r\n", 4); + + con->response.content_length += b->used - 1; ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); + + /* set header-fields */ + +diff --git a/src/mod_status.c b/src/mod_status.c +index e8da0a8..99b332a 100644 +--- a/src/mod_status.c ++++ b/src/mod_status.c +@@ -199,7 +199,7 @@ static int mod_status_get_multiplier(double *avg, char *multiplier, int size) { + + static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) { + plugin_data *p = p_d; +- buffer *b; ++ buffer *b = buffer_init(); + size_t j; + double avg; + char multiplier = '\0'; +@@ -208,8 +208,6 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c + + int days, hours, mins, seconds; + +- b = chunkqueue_get_append_buffer(con->write_queue); +- + buffer_copy_string_len(b, CONST_STR_LEN( + "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" +@@ -555,6 +553,9 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c + "</html>\n" + )); + ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); ++ + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + + return 0; +@@ -563,15 +564,13 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c + + static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) { + plugin_data *p = p_d; +- buffer *b; ++ buffer *b = buffer_init(); + double avg; + time_t ts; + char buf[32]; + unsigned int k; + unsigned int l; + +- b = chunkqueue_get_append_buffer(con->write_queue); +- + /* output total number of requests */ + buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: ")); + avg = p->abs_requests; +@@ -598,13 +597,13 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c + buffer_append_string_len(b, CONST_STR_LEN("\n")); + + buffer_append_string_len(b, CONST_STR_LEN("IdleServers: ")); +- buffer_append_int(b, srv->conns->size - srv->conns->used); +- buffer_append_string_len(b, CONST_STR_LEN("\n")); ++ buffer_append_int(b, srv->conns->size - srv->conns->used); ++ buffer_append_string_len(b, CONST_STR_LEN("\n")); + +- /* output scoreboard */ +- buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: ")); +- for (k = 0; k < srv->conns->used; k++) { +- connection *c = srv->conns->ptr[k]; ++ /* output scoreboard */ ++ buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: ")); ++ for (k = 0; k < srv->conns->used; k++) { ++ connection *c = srv->conns->ptr[k]; + const char *state = connection_get_short_state(c->state); + buffer_append_string_len(b, state, 1); + } +@@ -613,15 +612,17 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c + } + buffer_append_string_len(b, CONST_STR_LEN("\n")); + +- /* set text/plain output */ ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); + ++ /* set text/plain output */ + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); + + return 0; + } + + static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) { +- buffer *b; ++ buffer *b = buffer_init(); + size_t i; + array *st = srv->status; + UNUSED(p_d); +@@ -634,8 +635,6 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co + return HANDLER_FINISHED; + } + +- b = chunkqueue_get_append_buffer(con->write_queue); +- + for (i = 0; i < st->used; i++) { + size_t ndx = st->sorted[i]; + +@@ -645,6 +644,9 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co + buffer_append_string_len(b, CONST_STR_LEN("\n")); + } + ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); ++ + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); + + con->http_status = 200; +@@ -671,7 +673,8 @@ static handler_t mod_status_handle_server_status(server *srv, connection *con, v + + static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) { + plugin_data *p = p_d; +- buffer *b, *m = p->module_list; ++ buffer *b = buffer_init(); ++ buffer *m = p->module_list; + size_t i; + + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = +@@ -703,8 +706,6 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v + { FDEVENT_HANDLER_UNSET, NULL } + }; + +- b = chunkqueue_get_append_buffer(con->write_queue); +- + buffer_copy_string_len(b, CONST_STR_LEN( + "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" +@@ -756,6 +757,9 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v + "</html>\n" + )); + ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); ++ + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + + con->http_status = 200; +diff --git a/src/mod_webdav.c b/src/mod_webdav.c +index a3807c0..433b904 100644 +--- a/src/mod_webdav.c ++++ b/src/mod_webdav.c +@@ -1094,7 +1094,7 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p, + static int webdav_lockdiscovery(server *srv, connection *con, + buffer *locktoken, const char *lockscope, const char *locktype, int depth) { + +- buffer *b; ++ buffer *b = buffer_init(); + + response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken)); + +@@ -1102,8 +1102,6 @@ static int webdav_lockdiscovery(server *srv, connection *con, + CONST_STR_LEN("Content-Type"), + CONST_STR_LEN("text/xml; charset=\"utf-8\"")); + +- b = chunkqueue_get_append_buffer(con->write_queue); +- + buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")); + + buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n")); +@@ -1143,6 +1141,9 @@ static int webdav_lockdiscovery(server *srv, connection *con, + buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n")); + buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n")); + ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); ++ + return 0; + } + #endif +@@ -1341,7 +1342,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { + + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\"")); + +- b = chunkqueue_get_append_buffer(con->write_queue); ++ b = buffer_init(); + + buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")); + +@@ -1487,6 +1488,10 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { + if (p->conf.log_xml) { + log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b); + } ++ ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); ++ + con->file_finished = 1; + + return HANDLER_FINISHED; +@@ -1555,7 +1560,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { + /* we got an error somewhere in between, build a 207 */ + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\"")); + +- b = chunkqueue_get_append_buffer(con->write_queue); ++ b = buffer_init(); + + buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")); + +@@ -1569,6 +1574,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { + log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b); + } + ++ chunkqueue_append_buffer(con->write_queue, b); ++ buffer_free(b); ++ + con->http_status = 207; + con->file_finished = 1; + } else { +diff --git a/src/response.c b/src/response.c +index bde381f..31bcd69 100644 +--- a/src/response.c ++++ b/src/response.c +@@ -33,7 +33,7 @@ int http_response_write_header(server *srv, connection *con) { + int have_date = 0; + int have_server = 0; + +- b = chunkqueue_get_prepend_buffer(con->write_queue); ++ b = buffer_init(); + + if (con->request.http_version == HTTP_VERSION_1_1) { + buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 ")); +@@ -121,13 +121,15 @@ int http_response_write_header(server *srv, connection *con) { + + buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); + +- + con->bytes_header = b->used - 1; + + if (con->conf.log_response_header) { + log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b); + } + ++ chunkqueue_prepend_buffer(con->write_queue, b); ++ buffer_free(b); ++ + return 0; + } + +-- +2.4.5 + |