Commit ebf9ee08 authored by Sergey Lyubka's avatar Sergey Lyubka

Do not send 500 when timing out getreq()

parent 88cf3294
...@@ -78,17 +78,17 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl, ...@@ -78,17 +78,17 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
char *ebuf, size_t ebuf_len, char *ebuf, size_t ebuf_len,
const char *fmt, ...) { const char *fmt, ...) {
struct mg_connection *conn; struct mg_connection *conn;
const char *msg = NULL;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
ebuf[0] = '\0';
if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) { if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
} else if (mg_vprintf(conn, fmt, ap) <= 0) { } else if (mg_vprintf(conn, fmt, ap) <= 0) {
snprintf(ebuf, ebuf_len, "%s", "Error sending request"); snprintf(ebuf, ebuf_len, "%s", "Error sending request");
} else { } else {
getreq(conn, ebuf, ebuf_len); msg = getreq(conn);
} }
if (ebuf[0] != '\0' && conn != NULL) { if (msg != NULL && conn != NULL) {
mg_close_connection(conn); mg_close_connection(conn);
conn = NULL; conn = NULL;
} }
......
...@@ -449,7 +449,7 @@ static void send_http_error(struct mg_connection *, int, const char *, ...@@ -449,7 +449,7 @@ static void send_http_error(struct mg_connection *, int, const char *,
PRINTF_ARGS(4, 5); PRINTF_ARGS(4, 5);
static void cry(struct mg_connection *conn, static void cry(struct mg_connection *conn,
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len); static const char *getreq(struct mg_connection *conn);
#ifdef USE_LUA #ifdef USE_LUA
#include "lua_5.2.1.h" #include "lua_5.2.1.h"
......
...@@ -1023,22 +1023,24 @@ static int is_valid_uri(const char *uri) { ...@@ -1023,22 +1023,24 @@ static int is_valid_uri(const char *uri) {
return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0'); return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
} }
static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) { static const char *getreq(struct mg_connection *conn) {
const char *cl; const char *cl, *ret = NULL;
ebuf[0] = '\0';
reset_per_request_attributes(conn); reset_per_request_attributes(conn);
conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size, conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
&conn->data_len); &conn->data_len);
assert(conn->request_len < 0 || conn->data_len >= conn->request_len); assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
if (conn->request_len == 0 && conn->data_len == conn->buf_size) { if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
snprintf(ebuf, ebuf_len, "%s", "Request Too Large"); conn->status_code = 413;
ret = "Request Entity Too Large";
} else if (conn->request_len <= 0) { } else if (conn->request_len <= 0) {
snprintf(ebuf, ebuf_len, "%s", "Client closed connection"); conn->status_code = 0;
ret = "Client closed connection";
} else if (parse_http_message(conn->buf, conn->buf_size, } else if (parse_http_message(conn->buf, conn->buf_size,
&conn->request_info) <= 0) { &conn->request_info) <= 0) {
snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf); conn->status_code = 400;
ret = "Bad Request";
} else { } else {
// Request is valid. Set content_len attribute by parsing Content-Length // Request is valid. Set content_len attribute by parsing Content-Length
// If Content-Length is absent, set content_len to 0 if request is GET, // If Content-Length is absent, set content_len to 0 if request is GET,
...@@ -1057,13 +1059,14 @@ static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) { ...@@ -1057,13 +1059,14 @@ static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) {
} }
conn->birth_time = time(NULL); conn->birth_time = time(NULL);
} }
return ebuf[0] == '\0';
return ret;
} }
static void process_new_connection(struct mg_connection *conn) { static void process_new_connection(struct mg_connection *conn) {
struct mg_request_info *ri = &conn->request_info; struct mg_request_info *ri = &conn->request_info;
int keep_alive_enabled, keep_alive, discard_len; int keep_alive_enabled, keep_alive, discard_len;
char ebuf[100]; const char *msg = NULL;
keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes"); keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
keep_alive = 0; keep_alive = 0;
...@@ -1072,19 +1075,24 @@ static void process_new_connection(struct mg_connection *conn) { ...@@ -1072,19 +1075,24 @@ static void process_new_connection(struct mg_connection *conn) {
// to crule42. // to crule42.
conn->data_len = 0; conn->data_len = 0;
do { do {
if (!getreq(conn, ebuf, sizeof(ebuf))) { if ((msg = getreq(conn)) != NULL) {
send_http_error(conn, 500, "Server Error", "%s", ebuf);
conn->must_close = 1; conn->must_close = 1;
} else if (!is_valid_uri(conn->request_info.uri)) { } else if (!is_valid_uri(conn->request_info.uri)) {
snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri); msg = "Bad Request";
send_http_error(conn, 400, "Bad Request", "%s", ebuf); conn->status_code = 400;
} else if (strcmp(ri->http_version, "1.0") && } else if (strcmp(ri->http_version, "1.0") &&
strcmp(ri->http_version, "1.1")) { strcmp(ri->http_version, "1.1")) {
snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version); msg = "Bad HTTP Version";
send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf); conn->status_code = 505;
} }
if (ebuf[0] == '\0') { if (msg != NULL) {
// Do not send anything to the client on timeout
// see https://github.com/cesanta/mongoose/issues/261
if (conn->status_code > 0) {
send_http_error(conn, conn->status_code, msg, "%s", "");
}
} else {
handle_request(conn); handle_request(conn);
call_user(MG_REQUEST_END, conn, (void *) (long) conn->status_code); call_user(MG_REQUEST_END, conn, (void *) (long) conn->status_code);
log_access(conn); log_access(conn);
......
...@@ -449,7 +449,7 @@ static void send_http_error(struct mg_connection *, int, const char *, ...@@ -449,7 +449,7 @@ static void send_http_error(struct mg_connection *, int, const char *,
PRINTF_ARGS(4, 5); PRINTF_ARGS(4, 5);
static void cry(struct mg_connection *conn, static void cry(struct mg_connection *conn,
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len); static const char *getreq(struct mg_connection *conn);
#ifdef USE_LUA #ifdef USE_LUA
#include "lua_5.2.1.h" #include "lua_5.2.1.h"
...@@ -2304,17 +2304,17 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl, ...@@ -2304,17 +2304,17 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
char *ebuf, size_t ebuf_len, char *ebuf, size_t ebuf_len,
const char *fmt, ...) { const char *fmt, ...) {
struct mg_connection *conn; struct mg_connection *conn;
const char *msg = NULL;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
ebuf[0] = '\0';
if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) { if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
} else if (mg_vprintf(conn, fmt, ap) <= 0) { } else if (mg_vprintf(conn, fmt, ap) <= 0) {
snprintf(ebuf, ebuf_len, "%s", "Error sending request"); snprintf(ebuf, ebuf_len, "%s", "Error sending request");
} else { } else {
getreq(conn, ebuf, ebuf_len); msg = getreq(conn);
} }
if (ebuf[0] != '\0' && conn != NULL) { if (msg != NULL && conn != NULL) {
mg_close_connection(conn); mg_close_connection(conn);
conn = NULL; conn = NULL;
} }
...@@ -4894,22 +4894,24 @@ static int is_valid_uri(const char *uri) { ...@@ -4894,22 +4894,24 @@ static int is_valid_uri(const char *uri) {
return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0'); return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
} }
static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) { static const char *getreq(struct mg_connection *conn) {
const char *cl; const char *cl, *ret = NULL;
ebuf[0] = '\0';
reset_per_request_attributes(conn); reset_per_request_attributes(conn);
conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size, conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
&conn->data_len); &conn->data_len);
assert(conn->request_len < 0 || conn->data_len >= conn->request_len); assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
if (conn->request_len == 0 && conn->data_len == conn->buf_size) { if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
snprintf(ebuf, ebuf_len, "%s", "Request Too Large"); conn->status_code = 413;
ret = "Request Entity Too Large";
} else if (conn->request_len <= 0) { } else if (conn->request_len <= 0) {
snprintf(ebuf, ebuf_len, "%s", "Client closed connection"); conn->status_code = 0;
ret = "Client closed connection";
} else if (parse_http_message(conn->buf, conn->buf_size, } else if (parse_http_message(conn->buf, conn->buf_size,
&conn->request_info) <= 0) { &conn->request_info) <= 0) {
snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf); conn->status_code = 400;
ret = "Bad Request";
} else { } else {
// Request is valid. Set content_len attribute by parsing Content-Length // Request is valid. Set content_len attribute by parsing Content-Length
// If Content-Length is absent, set content_len to 0 if request is GET, // If Content-Length is absent, set content_len to 0 if request is GET,
...@@ -4928,13 +4930,14 @@ static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) { ...@@ -4928,13 +4930,14 @@ static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) {
} }
conn->birth_time = time(NULL); conn->birth_time = time(NULL);
} }
return ebuf[0] == '\0';
return ret;
} }
static void process_new_connection(struct mg_connection *conn) { static void process_new_connection(struct mg_connection *conn) {
struct mg_request_info *ri = &conn->request_info; struct mg_request_info *ri = &conn->request_info;
int keep_alive_enabled, keep_alive, discard_len; int keep_alive_enabled, keep_alive, discard_len;
char ebuf[100]; const char *msg = NULL;
keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes"); keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
keep_alive = 0; keep_alive = 0;
...@@ -4943,19 +4946,24 @@ static void process_new_connection(struct mg_connection *conn) { ...@@ -4943,19 +4946,24 @@ static void process_new_connection(struct mg_connection *conn) {
// to crule42. // to crule42.
conn->data_len = 0; conn->data_len = 0;
do { do {
if (!getreq(conn, ebuf, sizeof(ebuf))) { if ((msg = getreq(conn)) != NULL) {
send_http_error(conn, 500, "Server Error", "%s", ebuf);
conn->must_close = 1; conn->must_close = 1;
} else if (!is_valid_uri(conn->request_info.uri)) { } else if (!is_valid_uri(conn->request_info.uri)) {
snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri); msg = "Bad Request";
send_http_error(conn, 400, "Bad Request", "%s", ebuf); conn->status_code = 400;
} else if (strcmp(ri->http_version, "1.0") && } else if (strcmp(ri->http_version, "1.0") &&
strcmp(ri->http_version, "1.1")) { strcmp(ri->http_version, "1.1")) {
snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version); msg = "Bad HTTP Version";
send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf); conn->status_code = 505;
} }
if (ebuf[0] == '\0') { if (msg != NULL) {
// Do not send anything to the client on timeout
// see https://github.com/cesanta/mongoose/issues/261
if (conn->status_code > 0) {
send_http_error(conn, conn->status_code, msg, "%s", "");
}
} else {
handle_request(conn); handle_request(conn);
call_user(MG_REQUEST_END, conn, (void *) (long) conn->status_code); call_user(MG_REQUEST_END, conn, (void *) (long) conn->status_code);
log_access(conn); log_access(conn);
......
...@@ -217,7 +217,7 @@ write_file("$root/a+.txt", ''); ...@@ -217,7 +217,7 @@ write_file("$root/a+.txt", '');
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI'); o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI');
# Test HTTP version parsing # Test HTTP version parsing
o("GET / HTTPX/1.0\r\n\r\n", '^HTTP/1.1 500', 'Bad HTTP Version', 0); o("GET / HTTPX/1.0\r\n\r\n", '^HTTP/1.1 400', 'Bad HTTP Version', 0);
o("GET / HTTP/x.1\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP maj Version', 0); o("GET / HTTP/x.1\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP maj Version', 0);
o("GET / HTTP/1.1z\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP min Version', 0); o("GET / HTTP/1.1z\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP min Version', 0);
o("GET / HTTP/02.0\r\n\r\n", '^HTTP/1.1 505', 'HTTP Version >1.1', 0); o("GET / HTTP/02.0\r\n\r\n", '^HTTP/1.1 505', 'HTTP Version >1.1', 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment