|
|
|
@ -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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|