Browse Source

[core] header parsing: use goto for error handling

- disable keep-alive for all failures
- default to 400 for status
personal/stbuehler/fix-fdevent
Stefan Bühler 4 years ago
parent
commit
a2cc330fb4
  1. 182
      src/request.c

182
src/request.c

@ -413,10 +413,6 @@ static void http_request_missing_CR_before_LF(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "s", "missing CR before LF in header -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request);
}
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
}
enum keep_alive_set {
@ -611,9 +607,7 @@ int http_request_parse(server *srv, connection *con) {
#ifdef __COVERITY__
if (buffer_string_length(con->request.request) < 2) {
con->keep_alive = 0;
con->http_status = 400;
return 0;
goto failure;
}
#endif
/* coverity[overflow_sink : FALSE] */
@ -623,13 +617,11 @@ int http_request_parse(server *srv, connection *con) {
/* we are in keep-alive and might get \n after a previous POST request.*/
if (http_header_strict) {
http_request_missing_CR_before_LF(srv, con);
return 0;
goto failure;
}
#ifdef __COVERITY__
if (buffer_string_length(con->request.request) < 1) {
con->keep_alive = 0;
con->http_status = 400;
return 0;
goto failure;
}
#endif
/* coverity[overflow_sink : FALSE] */
@ -665,22 +657,18 @@ int http_request_parse(server *srv, connection *con) {
++i;
} else if (http_header_strict) { /* '\n' */
http_request_missing_CR_before_LF(srv, con);
return 0;
goto failure;
}
con->parse_request->ptr[i] = '\0';
if (request_line_stage != 2) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
proto = con->parse_request->ptr + first;
@ -691,8 +679,6 @@ int http_request_parse(server *srv, connection *con) {
/* we got the first one :) */
if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
con->http_status = 501;
con->response.keep_alive = 0;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
@ -701,7 +687,7 @@ int http_request_parse(server *srv, connection *con) {
con->request.request);
}
return 0;
goto failure;
}
con->request.http_method = r;
@ -737,16 +723,13 @@ int http_request_parse(server *srv, connection *con) {
}
if (invalid_version) {
con->http_status = 400;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
if (major_num == 1 && minor_num == 1) {
@ -762,19 +745,16 @@ int http_request_parse(server *srv, connection *con) {
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
} else {
con->http_status = 400;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
if (*uri == '/') {
@ -798,10 +778,8 @@ int http_request_parse(server *srv, connection *con) {
/* everything looks good so far */
buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
} else {
con->http_status = 400;
con->keep_alive = 0;
log_error_write(srv, __FILE__, __LINE__, "ss", "request-URI parse error -> 400 for:", uri);
return 0;
goto failure;
}
/* check uri for invalid characters */
@ -815,33 +793,30 @@ int http_request_parse(server *srv, connection *con) {
j = (NULL == z) ? jlen : (size_t)(z - con->request.uri->ptr);
}
if (j < jlen) {
con->http_status = 400;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
unsigned char buf[2];
buf[0] = con->request.uri->ptr[j];
buf[1] = '\0';
if (con->request.uri->ptr[j] > 32 &&
con->request.uri->ptr[j] != 127) {
/* the character is printable -> print it */
log_error_write(srv, __FILE__, __LINE__, "ss",
"invalid character in URI -> 400",
buf);
} else {
/* a control-character, print ascii-code */
log_error_write(srv, __FILE__, __LINE__, "sd",
"invalid character in URI -> 400",
con->request.uri->ptr[j]);
}
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
if (srv->srvconf.log_request_header_on_error) {
unsigned char buf[2];
buf[0] = con->request.uri->ptr[j];
buf[1] = '\0';
if (con->request.uri->ptr[j] > 32 &&
con->request.uri->ptr[j] != 127) {
/* the character is printable -> print it */
log_error_write(srv, __FILE__, __LINE__, "ss",
"invalid character in URI -> 400",
buf);
} else {
/* a control-character, print ascii-code */
log_error_write(srv, __FILE__, __LINE__, "sd",
"invalid character in URI -> 400",
con->request.uri->ptr[j]);
}
return 0;
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
goto failure;
}
buffer_copy_buffer(con->request.orig_uri, con->request.uri);
@ -866,17 +841,13 @@ int http_request_parse(server *srv, connection *con) {
break;
default:
/* ERROR, one space to much */
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
request_line_stage++;
@ -887,17 +858,13 @@ int http_request_parse(server *srv, connection *con) {
in_folding = 0;
if (buffer_string_is_empty(con->request.uri)) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
if (state.reqline_host) {
@ -954,10 +921,6 @@ int http_request_parse(server *srv, connection *con) {
case '=':
case '{':
case '}':
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "sbsds",
"invalid character in key", con->request.request, cur, *cur, "-> 400");
@ -966,7 +929,7 @@ int http_request_parse(server *srv, connection *con) {
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
case ' ':
case '\t':
if (i == first) {
@ -1005,11 +968,7 @@ int http_request_parse(server *srv, connection *con) {
con->request.request);
}
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
return 0;
goto failure;
}
}
@ -1031,16 +990,13 @@ int http_request_parse(server *srv, connection *con) {
con->request.request);
}
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
return 0;
goto failure;
}
break;
case '\n':
if (http_header_strict) {
http_request_missing_CR_before_LF(srv, con);
return 0;
goto failure;
} else if (i == first) {
con->parse_request->ptr[i] = '\0';
done = 1;
@ -1049,10 +1005,6 @@ int http_request_parse(server *srv, connection *con) {
/* fall through */
default:
if (http_header_strict ? (*cur < 32 || ((unsigned char)*cur) >= 127) : *cur == '\0') {
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "sbsds",
"invalid character in key", con->request.request, cur, *cur, "-> 400");
@ -1062,7 +1014,7 @@ int http_request_parse(server *srv, connection *con) {
con->request.request);
}
return 0;
goto failure;
}
/* ok */
break;
@ -1076,7 +1028,7 @@ int http_request_parse(server *srv, connection *con) {
if (*cur == '\n') {
if (http_header_strict) {
http_request_missing_CR_before_LF(srv, con);
return 0;
goto failure;
}
} else { /* (con->parse_request->ptr[i+1] == '\n') */
con->parse_request->ptr[i] = '\0';
@ -1107,11 +1059,7 @@ int http_request_parse(server *srv, connection *con) {
con->request.request);
}
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
return 0;
goto failure;
}
if (NULL != (ds = (data_string *)array_get_element_klen(con->request.headers, key, key_len))) {
@ -1139,10 +1087,7 @@ int http_request_parse(server *srv, connection *con) {
if (!parse_single_header(srv, con, &state, ds)) {
/* parse_single_header should already have logged it */
con->http_status = 400;
con->keep_alive = 0;
return 0;
goto failure;
}
} else {
/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
@ -1165,10 +1110,7 @@ int http_request_parse(server *srv, connection *con) {
"CR without LF", con->request.request, "-> 400");
}
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
return 0;
goto failure;
}
break;
case ' ':
@ -1183,10 +1125,7 @@ int http_request_parse(server *srv, connection *con) {
"invalid char in header", (int)*cur, "-> 400");
}
con->http_status = 400;
con->keep_alive = 0;
return 0;
goto failure;
}
break;
}
@ -1210,9 +1149,6 @@ int http_request_parse(server *srv, connection *con) {
/* RFC 2616, 14.23 */
if (con->request.http_host == NULL ||
buffer_string_is_empty(con->request.http_host)) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
if (srv->srvconf.log_request_header_on_error) {
log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
@ -1220,7 +1156,7 @@ int http_request_parse(server *srv, connection *con) {
"request-header:\n",
con->request.request);
}
return 0;
goto failure;
}
} else {
if (state.keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
@ -1245,11 +1181,7 @@ int http_request_parse(server *srv, connection *con) {
con->request.request);
}
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
return 0;
goto failure;
}
{
@ -1258,17 +1190,14 @@ int http_request_parse(server *srv, connection *con) {
if (con->request.http_version == HTTP_VERSION_1_0) {
log_error_write(srv, __FILE__, __LINE__, "s",
"HTTP/1.0 with Transfer-Encoding (bad HTTP/1.0 proxy?) -> 400");
con->keep_alive = 0;
con->http_status = 400; /* Bad Request */
return 0;
goto failure;
}
if (0 != strcasecmp(ds->value->ptr, "chunked")) {
/* Transfer-Encoding might contain additional encodings,
* which are not currently supported by lighttpd */
con->keep_alive = 0;
con->http_status = 501; /* Not Implemented */
return 0;
goto failure;
}
/* reset value for Transfer-Encoding, a hop-by-hop header,
@ -1293,9 +1222,7 @@ int http_request_parse(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "s",
"GET/HEAD with content-length -> 400");
con->keep_alive = 0;
con->http_status = 400;
return 0;
goto failure;
}
break;
case HTTP_METHOD_POST:
@ -1305,10 +1232,8 @@ int http_request_parse(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "s",
"POST-request, but content-length missing -> 411");
con->keep_alive = 0;
con->http_status = 411;
return 0;
goto failure;
}
break;
default:
@ -1324,5 +1249,12 @@ int http_request_parse(server *srv, connection *con) {
}
}
return 0;
failure:
con->keep_alive = 0;
con->response.keep_alive = 0;
if (!con->http_status) con->http_status = 400;
return 0;
}

Loading…
Cancel
Save