summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2019-02-05 23:37:10 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2019-02-07 01:17:47 -0500
commit8426b94161e6b4ab10d48b5c97ff66fe8587446c (patch)
treecd8601f51651ace39493d0a0b7f1fed3bd9b7371
parent21afabb8f8f16eddf9e660513b072122ca0616e9 (diff)
downloadlighttpd1.4-8426b94161e6b4ab10d48b5c97ff66fe8587446c.tar.gz
lighttpd1.4-8426b94161e6b4ab10d48b5c97ff66fe8587446c.zip
[core] perf: optimize connection_read_header()
-rw-r--r--src/connections.c162
1 files changed, 50 insertions, 112 deletions
diff --git a/src/connections.c b/src/connections.c
index 821f77c0..ce0f0c15 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -713,118 +713,56 @@ static int connection_reset(server *srv, connection *con) {
}
static void connection_read_header(server *srv, connection *con) {
- chunk *c, *last_chunk;
- off_t last_offset;
- chunkqueue *cq = con->read_queue;
-
- chunkqueue_remove_finished_chunks(cq);
-
- /* we might have got several packets at once
- */
-
- /* if there is a \r\n\r\n in the chunkqueue
- *
- * scan the chunk-queue twice
- * 1. to find the \r\n\r\n
- * 2. to copy the header-packet
- *
- */
-
- last_chunk = NULL;
- last_offset = 0;
-
- for (c = cq->first; c; c = c->next) {
- size_t i;
- size_t len = buffer_string_length(c->mem) - c->offset;
- const char *b = c->mem->ptr + c->offset;
-
- for (i = 0; i < len; ++i) {
- char ch = b[i];
-
- if ('\r' == ch) {
- /* chec if \n\r\n follows */
- size_t j = i+1;
- chunk *cc = c;
- const char header_end[] = "\r\n\r\n";
- int header_end_match_pos = 1;
-
- for ( ; cc; cc = cc->next, j = 0 ) {
- size_t bblen = buffer_string_length(cc->mem) - cc->offset;
- const char *bb = cc->mem->ptr + cc->offset;
-
- for ( ; j < bblen; j++) {
- ch = bb[j];
-
- if (ch == header_end[header_end_match_pos]) {
- header_end_match_pos++;
- if (4 == header_end_match_pos) {
- last_chunk = cc;
- last_offset = j+1;
- goto found_header_end;
- }
- } else {
- goto reset_search;
- }
- }
- }
- } else if ('\n' == ch) {
- /* check if \n follows */
- if (i+1 < len) {
- if (b[i+1] == '\n') {
- last_chunk = c;
- last_offset = i+2;
- break;
- } /* else goto reset_search; */
- } else {
- for (chunk *cc = c->next; cc; cc = cc->next) {
- size_t bblen = buffer_string_length(cc->mem) - cc->offset;
- const char *bb = cc->mem->ptr + cc->offset;
- if (0 == bblen) continue;
- if (bb[0] == '\n') {
- last_chunk = cc;
- last_offset = 1;
- goto found_header_end;
- } else {
- goto reset_search;
- }
- }
- }
- }
-reset_search: ;
- }
- }
-found_header_end:
-
- /* found */
- if (last_chunk) {
- buffer_clear(con->request.request);
-
- for (c = cq->first; c; c = c->next) {
- size_t len = buffer_string_length(c->mem) - c->offset;
-
- if (c == last_chunk) {
- len = last_offset;
- }
-
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, len);
- c->offset += len;
- cq->bytes_out += len;
-
- if (c == last_chunk) break;
- }
-
- connection_set_state(srv, con, CON_STATE_REQUEST_END);
- }
-
- if ((last_chunk ? buffer_string_length(con->request.request) : (size_t)chunkqueue_length(cq))
- > srv->srvconf.max_request_field_size) {
- log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 431");
- con->http_status = 431; /* Request Header Fields Too Large */
- con->keep_alive = 0;
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
- }
-
- chunkqueue_remove_finished_chunks(cq);
+ chunkqueue * const cq = con->read_queue;
+ chunk *c;
+ size_t hlen = 0;
+ int le = 0;
+
+ for (c = cq->first; c; c = c->next) {
+ size_t clen = buffer_string_length(c->mem) - c->offset;
+ const char * const b = c->mem->ptr + c->offset;
+ const char *n = b;
+ if (0 == clen) continue;
+ if (le) { /*(line end sequence cross chunk boundary)*/
+ if (n[0] == '\r') ++n;
+ if (n[0] == '\n') { ++n; hlen += n - b; break; }
+ if (n[0] == '\0') { hlen += n - b; continue; }
+ le = 0;
+ }
+ for (; (n = strchr(n, '\n')); ++n) {
+ if (n[1] == '\r') ++n;
+ if (n[1] == '\n') { hlen += n - b + 2; break; }
+ if (n[1] == '\0') { n = NULL; le = 1; break; }
+ }
+ if (n) break;
+ hlen += clen;
+ }
+
+ if (hlen > srv->srvconf.max_request_field_size) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "oversized request-header -> sending Status 431");
+ con->http_status = 431; /* Request Header Fields Too Large */
+ con->keep_alive = 0;
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+ }
+
+ if (NULL == c) return; /* incomplete request headers */
+
+ buffer_clear(con->request.request);
+
+ for (c = cq->first; c; c = c->next) {
+ size_t len = buffer_string_length(c->mem) - c->offset;
+ if (len > hlen) len = hlen;
+ buffer_append_string_len(con->request.request,
+ c->mem->ptr + c->offset, len);
+ c->offset += len;
+ cq->bytes_out += len;
+ if (0 == (hlen -= len)) break;
+ }
+
+ chunkqueue_remove_finished_chunks(cq);
+
+ connection_set_state(srv, con, CON_STATE_REQUEST_END);
}
/**