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