[core] connection_chunkqueue_compact()
@@ -699,6 +699,30 @@ static int connection_reset(server *srv, connection *con) {
return 0;
}
+__attribute_noinline__
+static void connection_chunkqueue_compact(chunkqueue *cq, size_t clen) {
+ if (0 == clen) {
+ chunk *c = cq->first;
+ if (c == cq->last) {
+ if (0 != c->offset && buffer_string_space(c->mem) < 1024) {
+ buffer *b = c->mem;
+ size_t len = buffer_string_length(b) - c->offset;
+ memmove(b->ptr, b->ptr+c->offset, len);
+ buffer_string_set_length(b, len);
+ c->offset = 0;
+ }
+ return;
+ }
+ clen = chunkqueue_length(cq);
+ if (0 == clen) return; /*(not expected)*/
+ }
+
+ /* caller should have checked if data already in first chunk if 0 != clen */
+ /*if (len >= clen) return;*/ /*(not expected)*/
+
+ chunkqueue_compact_mem(cq, clen);
+}
+
static int connection_read_header(connection *con) {
server *srv = con->srv;
chunkqueue * const cq = con->read_queue;
@@ -740,6 +764,10 @@ static int connection_read_header(connection *con) {
con->header_len = hlen;
buffer_clear(con->request.request);
+ if (c != cq->first) {
+ connection_chunkqueue_compact(cq, hlen);
+ c = cq->first;
+ } /*(else common case: headers in single chunk)*/
for (c = cq->first; c; c = c->next) {
size_t len = buffer_string_length(c->mem) - c->offset;
@@ -831,7 +859,17 @@ static int connection_handle_read_state(server *srv, connection *con) {
connection_set_state(srv, con, CON_STATE_REQUEST_END);
return 1;
}
- if (!con->is_readable) return 0;
+ else {
+ /*if (!con->is_readable) return 0;*/
+ /* partial header of next request has already been read,
+ * so optimistically check for more data received on
+ * socket while processing the previous request */
+ con->is_readable = 1;
+ /* adjust last chunk offset for better reuse on keep-alive */
+ /* (caller already checked that cq is not empty) */
+ if (con->read_queue->last->offset > 6*1024)
+ connection_chunkqueue_compact(con->read_queue, 0);
+ }
}
}
@@ -860,6 +898,10 @@ static int connection_handle_read_state(server *srv, connection *con) {
connection_set_state(srv, con, CON_STATE_ERROR);
}
+ if (con->read_queue->first != con->read_queue->last) {
+ connection_chunkqueue_compact(con->read_queue, 0);
+ }
+
return 0;
}
