[core] perf: optimize connection_read_header()

personal/stbuehler/fix-fdevent
Glenn Strauss 4 years ago
parent 21afabb8f8
commit 8426b94161

@ -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);
}
/**

Loading…
Cancel
Save