Browse Source

[core] permit LF to end lines if !header-strict

permit LF to end header lines if
  server.http-parseopt-header-strict = "disable"
(instead of requiring CR LF)

(makes it easy to use 'openssl s_client -connect <IP:port>' on unix)

(Note: care taken to minimize diff in this commit,
 but header parsing code should be revisited and overhauled)
personal/stbuehler/cleanup-build
Glenn Strauss 4 years ago
parent
commit
fa1eef0071
  1. 22
      src/connections.c
  2. 62
      src/request.c

22
src/connections.c

@ -790,6 +790,28 @@ static int connection_handle_read_state(server *srv, connection *con) {
}
}
}
} 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: ;
}

62
src/request.c

@ -406,6 +406,18 @@ static int request_uri_is_valid_char(unsigned char c) {
return 1;
}
static int http_request_missing_CR_before_LF(server *srv, connection *con) {
if (srv->srvconf.log_request_header_on_error) {
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;
return 0;
}
int http_request_parse(server *srv, connection *con) {
char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
@ -450,6 +462,19 @@ int http_request_parse(server *srv, connection *con) {
#endif
/* coverity[overflow_sink : FALSE] */
buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, buffer_string_length(con->request.request) - 2);
} else if (con->request_count > 0 &&
con->request.request->ptr[1] == '\n') {
/* we are in keep-alive and might get \n after a previous POST request.*/
if (http_header_strict) return http_request_missing_CR_before_LF(srv, con);
#ifdef __COVERITY__
if (buffer_string_length(con->request.request) < 1) {
con->keep_alive = 0;
con->http_status = 400;
return 0;
}
#endif
/* coverity[overflow_sink : FALSE] */
buffer_copy_string_len(con->parse_request, con->request.request->ptr + 1, buffer_string_length(con->request.request) - 1);
} else {
/* fill the local request buffer */
buffer_copy_buffer(con->parse_request, con->request.request);
@ -468,16 +493,24 @@ int http_request_parse(server *srv, connection *con) {
for (i = 0, first = 0; i < ilen && line == 0; i++) {
switch(con->parse_request->ptr[i]) {
case '\r':
if (con->parse_request->ptr[i+1] == '\n') {
if (con->parse_request->ptr[i+1] != '\n') break;
/* fall through */
case '\n':
{
http_method_t r;
char *nuri = NULL;
size_t j, jlen;
buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
/* \r\n -> \0\0 */
if (con->parse_request->ptr[i] == '\r') {
con->parse_request->ptr[i] = '\0';
++i;
} else if (http_header_strict) { /* '\n' */
return http_request_missing_CR_before_LF(srv, con);
}
con->parse_request->ptr[i] = '\0';
con->parse_request->ptr[i+1] = '\0';
buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
if (request_line_stage != 2) {
con->http_status = 400;
@ -649,7 +682,6 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 0;
i++;
line++;
first = i+1;
}
@ -839,6 +871,15 @@ int http_request_parse(server *srv, connection *con) {
return 0;
}
break;
case '\n':
if (http_header_strict) {
return http_request_missing_CR_before_LF(srv, con);
} else if (i == first) {
con->parse_request->ptr[i] = '\0';
done = 1;
break;
}
/* fall through */
default:
if (http_header_strict ? (*cur < 32 || ((unsigned char)*cur) >= 127) : *cur == '\0') {
con->http_status = 400;
@ -862,12 +903,18 @@ int http_request_parse(server *srv, connection *con) {
} else {
switch(*cur) {
case '\r':
if (con->parse_request->ptr[i+1] == '\n') {
case '\n':
if (*cur == '\n' || con->parse_request->ptr[i+1] == '\n') {
data_string *ds = NULL;
if (*cur == '\n') {
if (http_header_strict) return http_request_missing_CR_before_LF(srv, con);
} else { /* (con->parse_request->ptr[i+1] == '\n') */
con->parse_request->ptr[i] = '\0';
++i;
}
/* End of Headerline */
con->parse_request->ptr[i] = '\0';
con->parse_request->ptr[i+1] = '\0';
if (in_folding) {
/**
@ -1092,7 +1139,6 @@ int http_request_parse(server *srv, connection *con) {
}
}
i++;
first = i+1;
is_key = 1;
value = NULL;

Loading…
Cancel
Save