diff --git a/src/chunk.c b/src/chunk.c index 4fce20bd..1476e851 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -758,27 +758,40 @@ static void chunkqueue_remove_empty_chunks(chunkqueue *cq) { } } +void chunkqueue_compact_mem_offset(chunkqueue * const cq) { + chunk * const restrict c = cq->first; + if (0 == c->offset) return; + if (c->type != MEM_CHUNK) return; /*(should not happen)*/ + + buffer * const restrict b = c->mem; + size_t len = chunk_buffer_string_length(b) - c->offset; + memmove(b->ptr, b->ptr+c->offset, len); + c->offset = 0; + buffer_string_set_length(b, len); +} + void chunkqueue_compact_mem(chunkqueue *cq, size_t clen) { + /* caller must guarantee that chunks in chunkqueue are MEM_CHUNK, + * which is currently always true when reading input from client */ chunk *c = cq->first; buffer *b = c->mem; - size_t len = buffer_string_length(b) - c->offset; + size_t len = chunk_buffer_string_length(b) - c->offset; + if (len <= clen) return; if (b->size > clen) { - if (0 != c->offset) { - memmove(b->ptr, b->ptr+c->offset, len); - buffer_string_set_length(b, len); - c->offset = 0; - } + if (chunk_buffer_string_space(b) < clen - len) + chunkqueue_compact_mem_offset(cq); } else { - b = chunkqueue_prepend_buffer_open_sz(cq, clen + 8192); + b = chunkqueue_prepend_buffer_open_sz(cq, clen+1); buffer_append_string_len(b, c->mem->ptr + c->offset, len); cq->first->next = c->next; if (NULL == c->next) cq->last = cq->first; chunk_release(c); c = cq->first; } + for (chunk *fc = c; ((clen -= len) && (c = fc->next)); ) { - len = buffer_string_length(c->mem) - c->offset; + len = chunk_buffer_string_length(c->mem) - c->offset; if (len > clen) { buffer_append_string_len(b, c->mem->ptr + c->offset, clen); c->offset += clen; @@ -893,7 +906,8 @@ chunkqueue_peek_data (chunkqueue * const cq, switch (c->type) { case MEM_CHUNK: { - uint32_t have = buffer_string_length(c->mem) - (uint32_t)c->offset; + uint32_t have = + chunk_buffer_string_length(c->mem) - (uint32_t)c->offset; if (have > space) have = space; if (*dlen) diff --git a/src/chunk.h b/src/chunk.h index 841c451d..24a2ddbe 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -119,6 +119,7 @@ int chunkqueue_steal_with_tempfiles(chunkqueue * restrict dest, chunkqueue * res int chunkqueue_open_file_chunk(chunkqueue * restrict cq, struct log_error_st * const restrict errh); +void chunkqueue_compact_mem_offset(chunkqueue *cq); void chunkqueue_compact_mem(chunkqueue *cq, size_t clen); void chunkqueue_small_resp_optim (chunkqueue * restrict cq); diff --git a/src/connections.c b/src/connections.c index efef0bb1..60e2062e 100644 --- a/src/connections.c +++ b/src/connections.c @@ -704,10 +704,8 @@ static int connection_handle_read_state(connection * const con) { if (NULL == c) continue; clen = buffer_string_length(c->mem) - c->offset; if (0 == clen) continue; - if (c->offset > USHRT_MAX) { /*(highly unlikely)*/ - chunkqueue_compact_mem(cq, clen); - c = cq->first; /*(reload c after chunkqueue_compact_mem())*/ - } + if (c->offset > USHRT_MAX) /*(highly unlikely)*/ + chunkqueue_compact_mem_offset(cq); hoff[0] = 1; /* number of lines */ hoff[1] = (unsigned short)c->offset; /* base offset for all lines */ @@ -1659,20 +1657,14 @@ connection_handle_read_post_cq_compact (chunkqueue * const cq) { /* combine first mem chunk with next non-empty mem chunk * (loop if next chunk is empty) */ - chunk *c; - while (NULL != (c = cq->first) && NULL != c->next) { - buffer *mem = c->next->mem; - off_t offset = c->next->offset; - size_t blen = buffer_string_length(mem) - (size_t)offset; - force_assert(c->type == MEM_CHUNK); - force_assert(c->next->type == MEM_CHUNK); - buffer_append_string_len(c->mem, mem->ptr+offset, blen); - c->next->offset = c->offset; - c->next->mem = c->mem; - c->mem = mem; - c->offset = offset + (off_t)blen; - chunkqueue_remove_finished_chunks(cq); - if (0 != blen) return 1; + chunk *c = cq->first; + if (NULL == c) return 0; + const uint32_t mlen = buffer_string_length(c->mem) - (size_t)c->offset; + while ((c = c->next)) { + const uint32_t blen = buffer_string_length(c->mem) - (size_t)c->offset; + if (0 == blen) continue; + chunkqueue_compact_mem(cq, mlen + blen); + return 1; } return 0; } diff --git a/src/h2.c b/src/h2.c index b344a926..a7dd0ac3 100644 --- a/src/h2.c +++ b/src/h2.c @@ -896,42 +896,8 @@ h2_frame_cq_compact (chunkqueue * const cq, uint32_t len) /*assert(cq->first != cq->last);*//*(multiple chunks)*/ /* caller must guarantee that chunks in chunkqueue are all MEM_CHUNK */ - /* move data to beginning of buffer if offset is large or data is short */ - chunk *c = cq->first; - uint32_t mlen = buffer_string_length(c->mem); - if (mlen < c->offset) { - memmove(c->mem->ptr, c->mem->ptr + c->offset, mlen); - buffer_string_set_length(c->mem, mlen); - c->offset = 0; - } - - /* combine first mem chunk with next non-empty mem chunks up to len - * (loop if next chunk is empty) */ - /* (modified from connection_handle_read_post_cq_compact()) */ - uint32_t clen = mlen; - do { - buffer * const mem = c->next->mem; - const off_t offset = c->next->offset; - mlen = buffer_string_length(mem) - (uint32_t)offset; - force_assert(c->type == MEM_CHUNK); - force_assert(c->next->type == MEM_CHUNK); - if (mlen > clen - len) { - mlen = clen - len; - buffer_append_string_len(c->mem, mem->ptr+offset, mlen); - c->next->offset += mlen; - return len; - } - - buffer_append_string_len(c->mem, mem->ptr+offset, mlen); - clen += mlen; - /*(swap first and second chunk, then remove first chunk)*/ - c->next->offset = c->offset; - c->next->mem = c->mem; - c->mem = mem; - c->offset = offset + (off_t)mlen; - chunkqueue_remove_finished_chunks(cq); - } while ((c = cq->first)); /*(need to re-read cq->first)*/ - return clen; + chunkqueue_compact_mem(cq, len); + return buffer_string_length(cq->first->mem) - (uint32_t)cq->first->offset; }