diff options
-rw-r--r-- | src/buffer.c | 23 | ||||
-rw-r--r-- | src/buffer.h | 12 | ||||
-rw-r--r-- | src/chunk.c | 295 | ||||
-rw-r--r-- | src/chunk.h | 39 | ||||
-rw-r--r-- | src/connections.c | 195 | ||||
-rw-r--r-- | src/mod_compress.c | 4 | ||||
-rw-r--r-- | src/mod_dirlisting.c | 4 | ||||
-rw-r--r-- | src/mod_fastcgi.c | 76 | ||||
-rw-r--r-- | src/mod_flv_streaming.c | 6 | ||||
-rw-r--r-- | src/mod_proxy.c | 5 | ||||
-rw-r--r-- | src/mod_scgi.c | 4 | ||||
-rw-r--r-- | src/mod_ssi.c | 63 | ||||
-rw-r--r-- | src/mod_staticfile.c | 13 | ||||
-rw-r--r-- | src/mod_status.c | 42 | ||||
-rw-r--r-- | src/mod_uploadprogress.c | 11 | ||||
-rw-r--r-- | src/mod_webdav.c | 18 | ||||
-rw-r--r-- | src/response.c | 6 |
17 files changed, 465 insertions, 351 deletions
diff --git a/src/buffer.c b/src/buffer.c index caaa5bbc..019abb7f 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 ff57d68d..5d540a4e 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 c991b827..83adc153 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 65590000..33b7e27b 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 bc770bf6..3fab7689 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 ad6e9f2a..b428cd08 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 4b7106ac..e2e0bfac 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 01e72e58..e7b62f6b 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 501f8e85..1c1a3567 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 3bfc78fc..2b5a7408 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 66dce5e9..2fa265da 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 38eeac5d..ecdfb996 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 931bc570..e36c6973 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 e8da0a8b..99b332a1 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_uploadprogress.c b/src/mod_uploadprogress.c index 0076e682..25d08c2c 100644 --- a/src/mod_uploadprogress.c +++ b/src/mod_uploadprogress.c @@ -362,9 +362,7 @@ URIHANDLER_FUNC(mod_uploadprogress_uri_handler) { log_error_write(srv, __FILE__, __LINE__, "sb", "ID no known:", b); - b = chunkqueue_get_append_buffer(con->write_queue); - - buffer_append_string_len(b, CONST_STR_LEN("starting")); + chunkqueue_get_append_mem(con->write_queue, CONST_STR_LEN("starting")); return HANDLER_FINISHED; } @@ -376,7 +374,7 @@ URIHANDLER_FUNC(mod_uploadprogress_uri_handler) { response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT")); response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0")); - b = chunkqueue_get_append_buffer(con->write_queue); + b = buffer_init(); /* prepare XML */ buffer_copy_string_len(b, CONST_STR_LEN( @@ -392,7 +390,12 @@ URIHANDLER_FUNC(mod_uploadprogress_uri_handler) { "</received>" "</upload>")); +#if 0 log_error_write(srv, __FILE__, __LINE__, "sb", "...", b); +#endif + + chunkqueue_append_buffer(con->write_queue, b); + buffer_free(b); return HANDLER_FINISHED; default: diff --git a/src/mod_webdav.c b/src/mod_webdav.c index a3807c0a..433b904f 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 bde381f1..31bcd69e 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; } |