Commit 95fcb261 authored by Deomid "rojer" Ryabkov's avatar Deomid "rojer" Ryabkov Committed by Cesanta Bot

Fix processing of keep-alive requests when chunks are consumed

PUBLISHED_FROM=136ce2ed4f143d7ee246e5fd1078c431e205bb3a
parent 5867c67d
...@@ -29,6 +29,12 @@ signature: | ...@@ -29,6 +29,12 @@ signature: |
/* Headers */ /* Headers */
struct mg_str header_names[MG_MAX_HTTP_HEADERS]; struct mg_str header_names[MG_MAX_HTTP_HEADERS];
struct mg_str header_values[MG_MAX_HTTP_HEADERS]; struct mg_str header_values[MG_MAX_HTTP_HEADERS];
/*
* Value of the Content-Length header if present,
* otherwise MG_HTTP_CONTENT_LENGTH_UNKNOWN.
*/
size_t content_length;
}; };
--- ---
......
...@@ -2913,13 +2913,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) { ...@@ -2913,13 +2913,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
} else { } else {
mbuf_append(&nc->recv_mbuf, buf, n); mbuf_append(&nc->recv_mbuf, buf, n);
} }
mbuf_trim(&lc->recv_mbuf);
lc->last_io_time = nc->last_io_time = (time_t) mg_time(); lc->last_io_time = nc->last_io_time = (time_t) mg_time();
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) { if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
} }
#endif #endif
mbuf_trim(&lc->recv_mbuf);
if (n != 0) { if (n != 0) {
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} }
...@@ -5820,7 +5820,10 @@ struct mg_http_proto_data { ...@@ -5820,7 +5820,10 @@ struct mg_http_proto_data {
struct mg_http_endpoint *endpoints; struct mg_http_endpoint *endpoints;
mg_event_handler_t endpoint_handler; mg_event_handler_t endpoint_handler;
struct mg_reverse_proxy_data reverse_proxy_data; struct mg_reverse_proxy_data reverse_proxy_data;
size_t rcvd; /* How many bytes we have received. */ size_t rcvd; /* How many bytes we have received. */
size_t body_rcvd; /* How many bytes of body we have received. */
size_t body_processed; /* How many bytes of body we have processed. */
int finished;
}; };
static void mg_http_proto_data_destructor(void *proto_data); static void mg_http_proto_data_destructor(void *proto_data);
...@@ -6051,6 +6054,7 @@ static int mg_http_get_request_len(const char *s, int buf_len) { ...@@ -6051,6 +6054,7 @@ static int mg_http_get_request_len(const char *s, int buf_len) {
static const char *mg_http_parse_headers(const char *s, const char *end, static const char *mg_http_parse_headers(const char *s, const char *end,
int len, struct http_message *req) { int len, struct http_message *req) {
int i = 0; int i = 0;
req->content_length = MG_HTTP_CONTENT_LENGTH_UNKNOWN;
while (i < (int) ARRAY_SIZE(req->header_names) - 1) { while (i < (int) ARRAY_SIZE(req->header_names) - 1) {
struct mg_str *k = &req->header_names[i], *v = &req->header_values[i]; struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
...@@ -6076,9 +6080,10 @@ static const char *mg_http_parse_headers(const char *s, const char *end, ...@@ -6076,9 +6080,10 @@ static const char *mg_http_parse_headers(const char *s, const char *end,
break; break;
} }
if (!mg_ncasecmp(k->p, "Content-Length", 14)) { if (mg_ncasecmp(k->p, "Content-Length", 14) == 0) {
req->body.len = (size_t) to64(v->p); req->body.len = (size_t) to64(v->p);
req->message.len = len + req->body.len; req->message.len = len + req->body.len;
req->content_length = req->body.len;
} }
i++; i++;
...@@ -6194,6 +6199,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { ...@@ -6194,6 +6199,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) {
pd->file.keepalive)); pd->file.keepalive));
if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
mg_http_free_proto_data_file(&pd->file); mg_http_free_proto_data_file(&pd->file);
pd->finished = 1;
} }
} else if (pd->file.type == DATA_PUT) { } else if (pd->file.type == DATA_PUT) {
struct mbuf *io = &nc->recv_mbuf; struct mbuf *io = &nc->recv_mbuf;
...@@ -6206,6 +6212,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { ...@@ -6206,6 +6212,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) {
if (n == 0 || pd->file.sent >= pd->file.cl) { if (n == 0 || pd->file.sent >= pd->file.cl) {
if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
mg_http_free_proto_data_file(&pd->file); mg_http_free_proto_data_file(&pd->file);
pd->finished = 1;
} }
} }
#if MG_ENABLE_HTTP_CGI #if MG_ENABLE_HTTP_CGI
...@@ -6361,13 +6368,26 @@ static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, ...@@ -6361,13 +6368,26 @@ static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
struct http_message *hm); struct http_message *hm);
static void deliver_chunk(struct mg_connection *c, struct http_message *hm, static void deliver_chunk(struct mg_connection *c, struct http_message *hm,
int req_len) { struct mg_http_proto_data *pd, int req_len) {
/* Incomplete message received. Send MG_EV_HTTP_CHUNK event */ /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */
hm->body.len = c->recv_mbuf.len - req_len; hm->body.len = c->recv_mbuf.len - req_len;
if (hm->content_length != MG_HTTP_CONTENT_LENGTH_UNKNOWN) {
size_t body_remain = hm->content_length - pd->body_processed;
if (hm->body.len > body_remain) {
hm->body.len = body_remain;
}
}
if (pd != NULL) {
pd->body_rcvd = pd->body_processed + hm->body.len;
}
c->flags &= ~MG_F_DELETE_CHUNK; c->flags &= ~MG_F_DELETE_CHUNK;
mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm); mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm);
/* Delete processed data if user set MG_F_DELETE_CHUNK flag */ /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len; if (c->flags & MG_F_DELETE_CHUNK) {
pd->body_processed += hm->body.len;
c->recv_mbuf.len = req_len;
hm->body.len = 0;
}
} }
/* /*
...@@ -6438,7 +6458,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -6438,7 +6458,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
hm->message.len = io->len; hm->message.len = io->len;
hm->body.len = io->buf + io->len - hm->body.p; hm->body.len = io->buf + io->len - hm->body.p;
deliver_chunk(nc, hm, req_len); deliver_chunk(nc, hm, pd, req_len);
mg_http_call_endpoint_handler(nc, ev2, hm); mg_http_call_endpoint_handler(nc, ev2, hm);
} }
if (pd != NULL && pd->endpoint_handler != NULL && if (pd != NULL && pd->endpoint_handler != NULL &&
...@@ -6450,6 +6470,8 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -6450,6 +6470,8 @@ void mg_http_handler(struct mg_connection *nc, int ev,
#if MG_ENABLE_FILESYSTEM #if MG_ENABLE_FILESYSTEM
if (pd != NULL && pd->file.fp != NULL) { if (pd != NULL && pd->file.fp != NULL) {
mg_http_transfer_file_data(nc); mg_http_transfer_file_data(nc);
if (pd->finished) {
}
} }
#endif #endif
...@@ -6474,8 +6496,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -6474,8 +6496,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
again: again:
req_len = mg_parse_http(io->buf, io->len, hm, is_req); req_len = mg_parse_http(io->buf, io->len, hm, is_req);
if (req_len > 0 && (pd == NULL || pd->finished)) {
if (req_len > 0) {
/* New request - new proto data */ /* New request - new proto data */
pd = mg_http_create_proto_data(nc); pd = mg_http_create_proto_data(nc);
pd->rcvd = io->len; pd->rcvd = io->len;
...@@ -6557,42 +6578,50 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -6557,42 +6578,50 @@ void mg_http_handler(struct mg_connection *nc, int ev,
} }
} }
#endif /* MG_ENABLE_HTTP_WEBSOCKET */ #endif /* MG_ENABLE_HTTP_WEBSOCKET */
else if (hm->message.len > pd->rcvd) { else {
/* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */ deliver_chunk(nc, hm, pd, req_len);
deliver_chunk(nc, hm, req_len); if (hm->message.len > pd->rcvd &&
if (nc->recv_mbuf_limit > 0 && nc->recv_mbuf.len >= nc->recv_mbuf_limit) { (hm->content_length == MG_HTTP_CONTENT_LENGTH_UNKNOWN ||
LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit " pd->body_rcvd < hm->content_length)) {
"%lu bytes, and not drained, closing", /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */
nc, (unsigned long) nc->recv_mbuf.len, if (nc->recv_mbuf_limit > 0 &&
(unsigned long) nc->recv_mbuf_limit)); nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY; LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
} "%lu bytes, and not drained, closing",
} else { nc, (unsigned long) nc->recv_mbuf.len,
/* We did receive all HTTP body. */ (unsigned long) nc->recv_mbuf_limit));
int request_done = 1; nc->flags |= MG_F_CLOSE_IMMEDIATELY;
int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; }
char addr[32]; } else {
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), /* We did receive all HTTP body. */
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); int request_done = 1;
DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p, int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
(int) hm->uri.len, hm->uri.p)); char addr[32];
deliver_chunk(nc, hm, req_len); mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
/* Whole HTTP message is fully buffered, call event handler */ MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
mg_http_call_endpoint_handler(nc, trigger_ev, hm); DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p,
mbuf_remove(io, hm->message.len); (int) hm->uri.len, hm->uri.p));
pd->rcvd -= hm->message.len; /* Whole HTTP message is fully buffered, call event handler */
mg_http_call_endpoint_handler(nc, trigger_ev, hm);
mbuf_remove(io, req_len + hm->body.len);
pd->rcvd -= hm->message.len;
pd->body_rcvd = 0;
#if MG_ENABLE_FILESYSTEM #if MG_ENABLE_FILESYSTEM
/* We don't have a generic mechanism of communicating that we are done /* We don't have a generic mechanism of communicating that we are done
* responding to a request (should probably add one). But if we are * responding to a request (should probably add one). But if we are
* serving * serving
* a file, we are definitely not done. */ * a file, we are definitely not done. */
if (pd->file.fp != NULL) request_done = 0; if (pd->file.fp != NULL) request_done = 0;
#endif #endif
#if MG_ENABLE_HTTP_CGI #if MG_ENABLE_HTTP_CGI
/* If this is a CGI request, we are not done either. */ /* If this is a CGI request, we are not done either. */
if (pd->cgi.cgi_nc != NULL) request_done = 0; if (pd->cgi.cgi_nc != NULL) request_done = 0;
#endif #endif
if (request_done && io->len > 0) goto again; pd->finished = request_done;
DBG(("%p finished %d ml %d bl %d", nc, pd->finished,
(int) hm->message.len, (int) hm->body.len));
if (request_done && io->len > 0) goto again;
}
} }
} }
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#ifndef CS_MONGOOSE_SRC_COMMON_H_ #ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_
#define MG_VERSION "6.17" #define MG_VERSION "6.18"
/* Local tweaks, applied before any of Mongoose's own headers. */ /* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS #ifdef MG_LOCALS
...@@ -4420,8 +4420,16 @@ struct http_message { ...@@ -4420,8 +4420,16 @@ struct http_message {
/* Headers */ /* Headers */
struct mg_str header_names[MG_MAX_HTTP_HEADERS]; struct mg_str header_names[MG_MAX_HTTP_HEADERS];
struct mg_str header_values[MG_MAX_HTTP_HEADERS]; struct mg_str header_values[MG_MAX_HTTP_HEADERS];
/*
* Value of the Content-Length header if present,
* otherwise MG_HTTP_CONTENT_LENGTH_UNKNOWN.
*/
size_t content_length;
}; };
#define MG_HTTP_CONTENT_LENGTH_UNKNOWN ((size_t) -1)
#if MG_ENABLE_HTTP_WEBSOCKET #if MG_ENABLE_HTTP_WEBSOCKET
/* WebSocket message */ /* WebSocket message */
struct websocket_message { struct websocket_message {
......
#ifndef CS_MONGOOSE_SRC_COMMON_H_ #ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_
#define MG_VERSION "6.17" #define MG_VERSION "6.18"
/* Local tweaks, applied before any of Mongoose's own headers. */ /* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS #ifdef MG_LOCALS
......
...@@ -174,7 +174,10 @@ struct mg_http_proto_data { ...@@ -174,7 +174,10 @@ struct mg_http_proto_data {
struct mg_http_endpoint *endpoints; struct mg_http_endpoint *endpoints;
mg_event_handler_t endpoint_handler; mg_event_handler_t endpoint_handler;
struct mg_reverse_proxy_data reverse_proxy_data; struct mg_reverse_proxy_data reverse_proxy_data;
size_t rcvd; /* How many bytes we have received. */ size_t rcvd; /* How many bytes we have received. */
size_t body_rcvd; /* How many bytes of body we have received. */
size_t body_processed; /* How many bytes of body we have processed. */
int finished;
}; };
static void mg_http_proto_data_destructor(void *proto_data); static void mg_http_proto_data_destructor(void *proto_data);
...@@ -405,6 +408,7 @@ static int mg_http_get_request_len(const char *s, int buf_len) { ...@@ -405,6 +408,7 @@ static int mg_http_get_request_len(const char *s, int buf_len) {
static const char *mg_http_parse_headers(const char *s, const char *end, static const char *mg_http_parse_headers(const char *s, const char *end,
int len, struct http_message *req) { int len, struct http_message *req) {
int i = 0; int i = 0;
req->content_length = MG_HTTP_CONTENT_LENGTH_UNKNOWN;
while (i < (int) ARRAY_SIZE(req->header_names) - 1) { while (i < (int) ARRAY_SIZE(req->header_names) - 1) {
struct mg_str *k = &req->header_names[i], *v = &req->header_values[i]; struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
...@@ -430,9 +434,10 @@ static const char *mg_http_parse_headers(const char *s, const char *end, ...@@ -430,9 +434,10 @@ static const char *mg_http_parse_headers(const char *s, const char *end,
break; break;
} }
if (!mg_ncasecmp(k->p, "Content-Length", 14)) { if (mg_ncasecmp(k->p, "Content-Length", 14) == 0) {
req->body.len = (size_t) to64(v->p); req->body.len = (size_t) to64(v->p);
req->message.len = len + req->body.len; req->message.len = len + req->body.len;
req->content_length = req->body.len;
} }
i++; i++;
...@@ -548,6 +553,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { ...@@ -548,6 +553,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) {
pd->file.keepalive)); pd->file.keepalive));
if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
mg_http_free_proto_data_file(&pd->file); mg_http_free_proto_data_file(&pd->file);
pd->finished = 1;
} }
} else if (pd->file.type == DATA_PUT) { } else if (pd->file.type == DATA_PUT) {
struct mbuf *io = &nc->recv_mbuf; struct mbuf *io = &nc->recv_mbuf;
...@@ -560,6 +566,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { ...@@ -560,6 +566,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) {
if (n == 0 || pd->file.sent >= pd->file.cl) { if (n == 0 || pd->file.sent >= pd->file.cl) {
if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
mg_http_free_proto_data_file(&pd->file); mg_http_free_proto_data_file(&pd->file);
pd->finished = 1;
} }
} }
#if MG_ENABLE_HTTP_CGI #if MG_ENABLE_HTTP_CGI
...@@ -715,13 +722,26 @@ static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, ...@@ -715,13 +722,26 @@ static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
struct http_message *hm); struct http_message *hm);
static void deliver_chunk(struct mg_connection *c, struct http_message *hm, static void deliver_chunk(struct mg_connection *c, struct http_message *hm,
int req_len) { struct mg_http_proto_data *pd, int req_len) {
/* Incomplete message received. Send MG_EV_HTTP_CHUNK event */ /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */
hm->body.len = c->recv_mbuf.len - req_len; hm->body.len = c->recv_mbuf.len - req_len;
if (hm->content_length != MG_HTTP_CONTENT_LENGTH_UNKNOWN) {
size_t body_remain = hm->content_length - pd->body_processed;
if (hm->body.len > body_remain) {
hm->body.len = body_remain;
}
}
if (pd != NULL) {
pd->body_rcvd = pd->body_processed + hm->body.len;
}
c->flags &= ~MG_F_DELETE_CHUNK; c->flags &= ~MG_F_DELETE_CHUNK;
mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm); mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm);
/* Delete processed data if user set MG_F_DELETE_CHUNK flag */ /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len; if (c->flags & MG_F_DELETE_CHUNK) {
pd->body_processed += hm->body.len;
c->recv_mbuf.len = req_len;
hm->body.len = 0;
}
} }
/* /*
...@@ -792,7 +812,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -792,7 +812,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
hm->message.len = io->len; hm->message.len = io->len;
hm->body.len = io->buf + io->len - hm->body.p; hm->body.len = io->buf + io->len - hm->body.p;
deliver_chunk(nc, hm, req_len); deliver_chunk(nc, hm, pd, req_len);
mg_http_call_endpoint_handler(nc, ev2, hm); mg_http_call_endpoint_handler(nc, ev2, hm);
} }
if (pd != NULL && pd->endpoint_handler != NULL && if (pd != NULL && pd->endpoint_handler != NULL &&
...@@ -804,6 +824,8 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -804,6 +824,8 @@ void mg_http_handler(struct mg_connection *nc, int ev,
#if MG_ENABLE_FILESYSTEM #if MG_ENABLE_FILESYSTEM
if (pd != NULL && pd->file.fp != NULL) { if (pd != NULL && pd->file.fp != NULL) {
mg_http_transfer_file_data(nc); mg_http_transfer_file_data(nc);
if (pd->finished) {
}
} }
#endif #endif
...@@ -828,8 +850,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -828,8 +850,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
again: again:
req_len = mg_parse_http(io->buf, io->len, hm, is_req); req_len = mg_parse_http(io->buf, io->len, hm, is_req);
if (req_len > 0 && (pd == NULL || pd->finished)) {
if (req_len > 0) {
/* New request - new proto data */ /* New request - new proto data */
pd = mg_http_create_proto_data(nc); pd = mg_http_create_proto_data(nc);
pd->rcvd = io->len; pd->rcvd = io->len;
...@@ -911,42 +932,50 @@ void mg_http_handler(struct mg_connection *nc, int ev, ...@@ -911,42 +932,50 @@ void mg_http_handler(struct mg_connection *nc, int ev,
} }
} }
#endif /* MG_ENABLE_HTTP_WEBSOCKET */ #endif /* MG_ENABLE_HTTP_WEBSOCKET */
else if (hm->message.len > pd->rcvd) { else {
/* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */ deliver_chunk(nc, hm, pd, req_len);
deliver_chunk(nc, hm, req_len); if (hm->message.len > pd->rcvd &&
if (nc->recv_mbuf_limit > 0 && nc->recv_mbuf.len >= nc->recv_mbuf_limit) { (hm->content_length == MG_HTTP_CONTENT_LENGTH_UNKNOWN ||
LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit " pd->body_rcvd < hm->content_length)) {
"%lu bytes, and not drained, closing", /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */
nc, (unsigned long) nc->recv_mbuf.len, if (nc->recv_mbuf_limit > 0 &&
(unsigned long) nc->recv_mbuf_limit)); nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY; LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
} "%lu bytes, and not drained, closing",
} else { nc, (unsigned long) nc->recv_mbuf.len,
/* We did receive all HTTP body. */ (unsigned long) nc->recv_mbuf_limit));
int request_done = 1; nc->flags |= MG_F_CLOSE_IMMEDIATELY;
int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; }
char addr[32]; } else {
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), /* We did receive all HTTP body. */
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); int request_done = 1;
DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p, int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
(int) hm->uri.len, hm->uri.p)); char addr[32];
deliver_chunk(nc, hm, req_len); mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
/* Whole HTTP message is fully buffered, call event handler */ MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
mg_http_call_endpoint_handler(nc, trigger_ev, hm); DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p,
mbuf_remove(io, hm->message.len); (int) hm->uri.len, hm->uri.p));
pd->rcvd -= hm->message.len; /* Whole HTTP message is fully buffered, call event handler */
mg_http_call_endpoint_handler(nc, trigger_ev, hm);
mbuf_remove(io, req_len + hm->body.len);
pd->rcvd -= hm->message.len;
pd->body_rcvd = 0;
#if MG_ENABLE_FILESYSTEM #if MG_ENABLE_FILESYSTEM
/* We don't have a generic mechanism of communicating that we are done /* We don't have a generic mechanism of communicating that we are done
* responding to a request (should probably add one). But if we are * responding to a request (should probably add one). But if we are
* serving * serving
* a file, we are definitely not done. */ * a file, we are definitely not done. */
if (pd->file.fp != NULL) request_done = 0; if (pd->file.fp != NULL) request_done = 0;
#endif #endif
#if MG_ENABLE_HTTP_CGI #if MG_ENABLE_HTTP_CGI
/* If this is a CGI request, we are not done either. */ /* If this is a CGI request, we are not done either. */
if (pd->cgi.cgi_nc != NULL) request_done = 0; if (pd->cgi.cgi_nc != NULL) request_done = 0;
#endif #endif
if (request_done && io->len > 0) goto again; pd->finished = request_done;
DBG(("%p finished %d ml %d bl %d", nc, pd->finished,
(int) hm->message.len, (int) hm->body.len));
if (request_done && io->len > 0) goto again;
}
} }
} }
} }
......
...@@ -62,8 +62,16 @@ struct http_message { ...@@ -62,8 +62,16 @@ struct http_message {
/* Headers */ /* Headers */
struct mg_str header_names[MG_MAX_HTTP_HEADERS]; struct mg_str header_names[MG_MAX_HTTP_HEADERS];
struct mg_str header_values[MG_MAX_HTTP_HEADERS]; struct mg_str header_values[MG_MAX_HTTP_HEADERS];
/*
* Value of the Content-Length header if present,
* otherwise MG_HTTP_CONTENT_LENGTH_UNKNOWN.
*/
size_t content_length;
}; };
#define MG_HTTP_CONTENT_LENGTH_UNKNOWN ((size_t) -1)
#if MG_ENABLE_HTTP_WEBSOCKET #if MG_ENABLE_HTTP_WEBSOCKET
/* WebSocket message */ /* WebSocket message */
struct websocket_message { struct websocket_message {
......
...@@ -707,13 +707,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) { ...@@ -707,13 +707,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
} else { } else {
mbuf_append(&nc->recv_mbuf, buf, n); mbuf_append(&nc->recv_mbuf, buf, n);
} }
mbuf_trim(&lc->recv_mbuf);
lc->last_io_time = nc->last_io_time = (time_t) mg_time(); lc->last_io_time = nc->last_io_time = (time_t) mg_time();
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) { if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
} }
#endif #endif
mbuf_trim(&lc->recv_mbuf);
if (n != 0) { if (n != 0) {
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} }
......
This diff is collapsed.
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