Browse Source

[core] lift code out of request line parse loop

personal/stbuehler/fix-fdevent
Glenn Strauss 3 years ago
parent
commit
b9a37291cb
  1. 80
      src/request.c

80
src/request.c

@ -566,13 +566,16 @@ static int parse_single_header(server *srv, connection *con, parse_header_state
static size_t http_request_parse_reqline(server *srv, connection *con, buffer *hdrs, parse_header_state *state) {
char * const ptr = hdrs->ptr;
char *uri = NULL, *proto = NULL, *method = NULL;
int line = 0;
char *uri = NULL, *proto = NULL;
int request_line_stage = 0;
size_t i, first, ilen;
size_t i;
const unsigned int http_header_strict = (con->conf.http_parseopts & HTTP_PARSEOPT_HEADER_STRICT);
/* hdrs must end with '\n' (already checked before parsing headers) */
#ifdef __COVERITY__
if (NULL == strchr(ptr, '\n')) return 400;
#endif
/*
* Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
* Option : "^([-a-zA-Z]+): (.+)$"
@ -585,40 +588,42 @@ static size_t http_request_parse_reqline(server *srv, connection *con, buffer *h
*
* <method> <uri> <protocol>\r\n
* */
ilen = buffer_string_length(hdrs);
for (i = 0, first = 0; i < ilen && line == 0; i++) {
switch(ptr[i]) {
case '\r':
if (ptr[i+1] != '\n') break;
/* fall through */
case '\n':
for (i = 0; ptr[i] != '\n'; ++i) {
if (ptr[i] == ' ') {
if (NULL == uri) uri = ptr + i + 1;
else if (NULL == proto) proto = ptr + i + 1;
else return http_request_header_line_invalid(srv, 400, "overlong request line; extra space -> 400"); /* ERROR, one space to much */
}
}
ptr[i] = '\0';
state->reqline_len = i+1;
{
http_method_t r;
char *nuri = NULL;
size_t j, jlen;
buffer_copy_string_len(con->request.request_line, ptr, i);
/* \r\n -> \0\0 */
if (ptr[i] == '\r') {
ptr[i] = '\0';
++i;
#ifdef __COVERITY__
if (0 == i) return 400;
#endif
if (ptr[i-1] == '\r') {
ptr[i-1] = '\0';
} else if (http_header_strict) { /* '\n' */
return http_request_header_line_invalid(srv, 400, "missing CR before LF in header -> 400");
}
ptr[i] = '\0';
if (request_line_stage != 2) {
buffer_copy_string_len(con->request.request_line, ptr, i);
if (NULL == proto) {
return http_request_header_line_invalid(srv, 400, "incomplete request line -> 400");
}
proto = ptr + first;
*(uri - 1) = '\0';
*(proto - 1) = '\0';
/* we got the first one :) */
if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
if (HTTP_METHOD_UNSET == (r = get_http_method_key(ptr))) {
return http_request_header_line_invalid(srv, 501, "unknown http-method -> 501");
}
@ -695,6 +700,7 @@ static size_t http_request_parse_reqline(server *srv, connection *con, buffer *h
/* check uri for invalid characters */
jlen = buffer_string_length(con->request.uri);
if (0 == jlen) return http_request_header_line_invalid(srv, 400, "no uri specified -> 400");
if ((con->conf.http_parseopts & HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT)) {
j = jlen; /* URI will be checked in http_response_prepare() */
} else if (http_header_strict) {
@ -708,39 +714,8 @@ static size_t http_request_parse_reqline(server *srv, connection *con, buffer *h
}
buffer_copy_buffer(con->request.orig_uri, con->request.uri);
con->http_status = 0;
line++;
first = i+1;
}
break;
case ' ':
switch(request_line_stage) {
case 0:
/* GET|POST|... */
method = ptr + first;
first = i + 1;
break;
case 1:
/* /foobar/... */
uri = ptr + first;
first = i + 1;
break;
default:
/* ERROR, one space to much */
return http_request_header_line_invalid(srv, 400, "overlong request line -> 400");
}
request_line_stage++;
break;
}
}
if (buffer_string_is_empty(con->request.uri)) {
return http_request_header_line_invalid(srv, 400, "no uri specified -> 400");
}
if (state->reqline_host) {
/* Insert as host header */
if (state->reqline_hostlen >= 1024) { /*(expecting < 256)*/
@ -750,7 +725,6 @@ static size_t http_request_parse_reqline(server *srv, connection *con, buffer *h
con->request.http_host = http_header_request_get(con, HTTP_HEADER_HOST, CONST_STR_LEN("Host"));
}
state->reqline_len = i;
return 0;
}

Loading…
Cancel
Save