Commit e5910da3 authored by Deomid Ryabkov's avatar Deomid Ryabkov Committed by Cesanta Bot

Deliver EV_CLOSE to the last endpoint handler

CL: mg: Deliver EV_CLOSE to the last endpoint handler

PUBLISHED_FROM=02ee2c6627ed9ee1d35022244f71dfe1877ce2c0
parent c277a1d8
......@@ -88,6 +88,9 @@ extern void *(*test_calloc)(size_t count, size_t size);
#if MG_ENABLE_HTTP
struct mg_serve_http_opts;
MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
struct mg_connection *c);
/*
* Reassemble the content of the buffer (buf, blen) which should be
* in the HTTP chunked encoding, by collapsing data chunks to the
......@@ -6008,20 +6011,29 @@ struct mg_http_proto_data {
size_t rcvd; /* How many bytes we have received. */
};
static void mg_http_conn_destructor(void *proto_data);
static void mg_http_proto_data_destructor(void *proto_data);
struct mg_connection *mg_connect_http_base(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
struct mg_str *path, struct mg_str *user_info, struct mg_str *host);
static struct mg_http_proto_data *mg_http_get_proto_data(
MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
struct mg_connection *c) {
if (c->proto_data == NULL) {
c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
c->proto_data_destructor = mg_http_conn_destructor;
}
/* If we have proto data from previous connection, flush it. */
if (c->proto_data != NULL) {
void *pd = c->proto_data;
c->proto_data = NULL;
mg_http_proto_data_destructor(pd);
}
c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
c->proto_data_destructor = mg_http_proto_data_destructor;
return (struct mg_http_proto_data *) c->proto_data;
}
static struct mg_http_proto_data *mg_http_get_proto_data(
struct mg_connection *c) {
return (struct mg_http_proto_data *) c->proto_data;
}
......@@ -6077,7 +6089,7 @@ static void mg_http_free_reverse_proxy_data(struct mg_reverse_proxy_data *rpd) {
}
}
static void mg_http_conn_destructor(void *proto_data) {
static void mg_http_proto_data_destructor(void *proto_data) {
struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
#if MG_ENABLE_FILESYSTEM
mg_http_free_proto_data_file(&pd->file);
......@@ -6350,7 +6362,8 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) {
/* Rate-limited */
}
if (pd->file.sent >= pd->file.cl) {
LOG(LL_DEBUG, ("%p done, %d bytes", nc, (int) pd->file.sent));
LOG(LL_DEBUG, ("%p done, %d bytes, ka %d", nc, (int) pd->file.sent,
pd->file.keepalive));
if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
mg_http_free_proto_data_file(&pd->file);
}
......@@ -6486,12 +6499,12 @@ struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc,
int matched, matched_max = 0;
struct mg_http_endpoint *ep;
if (nc == NULL) {
return NULL;
}
if (nc == NULL) return NULL;
pd = mg_http_get_proto_data(nc);
if (pd == NULL) return NULL;
ep = pd->endpoints;
while (ep != NULL) {
if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) > 0) {
......@@ -6563,13 +6576,13 @@ void mg_http_handler(struct mg_connection *nc, int ev,
if (ev == MG_EV_CLOSE) {
#if MG_ENABLE_HTTP_CGI
/* Close associated CGI forwarder connection */
if (pd->cgi.cgi_nc != NULL) {
if (pd != NULL && pd->cgi.cgi_nc != NULL) {
pd->cgi.cgi_nc->user_data = NULL;
pd->cgi.cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
#endif
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
if (pd->mp_stream.boundary != NULL) {
if (pd != NULL && pd->mp_stream.boundary != NULL) {
/*
* Multipart message is in progress, but connection is closed.
* Finish part and request with an error flag.
......@@ -6599,14 +6612,14 @@ void mg_http_handler(struct mg_connection *nc, int ev,
deliver_chunk(nc, hm, req_len);
mg_http_call_endpoint_handler(nc, ev2, hm);
}
pd->rcvd = 0;
if (pd->endpoint_handler != NULL && pd->endpoint_handler != nc->handler) {
if (pd != NULL && pd->endpoint_handler != NULL &&
pd->endpoint_handler != nc->handler) {
mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
}
}
#if MG_ENABLE_FILESYSTEM
if (pd->file.fp != NULL) {
if (pd != NULL && pd->file.fp != NULL) {
mg_http_transfer_file_data(nc);
}
#endif
......@@ -6614,7 +6627,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
if (pd->mp_stream.boundary != NULL &&
if (pd != NULL && pd->mp_stream.boundary != NULL &&
(ev == MG_EV_RECV || ev == MG_EV_POLL)) {
if (ev == MG_EV_RECV) {
pd->rcvd += *(int *) ev_data;
......@@ -6629,11 +6642,16 @@ void mg_http_handler(struct mg_connection *nc, int ev,
if (ev == MG_EV_RECV) {
struct mg_str *s;
pd->rcvd += *(int *) ev_data;
again:
req_len = mg_parse_http(io->buf, io->len, hm, is_req);
if (req_len > 0) {
/* New request - new proto data */
pd = mg_http_create_proto_data(nc);
pd->rcvd = io->len;
}
if (req_len > 0 &&
(s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
mg_vcasecmp(s, "chunked") == 0) {
......@@ -6745,18 +6763,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
/* If this is a CGI request, we are not done either. */
if (pd->cgi.cgi_nc != NULL) request_done = 0;
#endif
if (request_done) {
/* This request is done but we may receive another on this connection.
*/
mg_http_conn_destructor(pd);
nc->proto_data = NULL;
if (io->len > 0) {
/* We already have data for the next one, restart parsing. */
pd = mg_http_get_proto_data(nc);
pd->rcvd = io->len;
goto again;
}
}
if (request_done && io->len > 0) goto again;
}
}
}
......@@ -8896,6 +8903,7 @@ void mg_register_http_endpoint_opt(struct mg_connection *nc,
if (new_ep == NULL) return;
pd = mg_http_get_proto_data(nc);
if (pd == NULL) pd = mg_http_create_proto_data(nc);
new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path));
if (opts.auth_domain != NULL && opts.auth_file != NULL) {
new_ep->auth_domain = strdup(opts.auth_domain);
......
......@@ -177,20 +177,29 @@ struct mg_http_proto_data {
size_t rcvd; /* How many bytes we have received. */
};
static void mg_http_conn_destructor(void *proto_data);
static void mg_http_proto_data_destructor(void *proto_data);
struct mg_connection *mg_connect_http_base(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
struct mg_str *path, struct mg_str *user_info, struct mg_str *host);
static struct mg_http_proto_data *mg_http_get_proto_data(
MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
struct mg_connection *c) {
if (c->proto_data == NULL) {
c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
c->proto_data_destructor = mg_http_conn_destructor;
}
/* If we have proto data from previous connection, flush it. */
if (c->proto_data != NULL) {
void *pd = c->proto_data;
c->proto_data = NULL;
mg_http_proto_data_destructor(pd);
}
c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
c->proto_data_destructor = mg_http_proto_data_destructor;
return (struct mg_http_proto_data *) c->proto_data;
}
static struct mg_http_proto_data *mg_http_get_proto_data(
struct mg_connection *c) {
return (struct mg_http_proto_data *) c->proto_data;
}
......@@ -246,7 +255,7 @@ static void mg_http_free_reverse_proxy_data(struct mg_reverse_proxy_data *rpd) {
}
}
static void mg_http_conn_destructor(void *proto_data) {
static void mg_http_proto_data_destructor(void *proto_data) {
struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
#if MG_ENABLE_FILESYSTEM
mg_http_free_proto_data_file(&pd->file);
......@@ -519,7 +528,8 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) {
/* Rate-limited */
}
if (pd->file.sent >= pd->file.cl) {
LOG(LL_DEBUG, ("%p done, %d bytes", nc, (int) pd->file.sent));
LOG(LL_DEBUG, ("%p done, %d bytes, ka %d", nc, (int) pd->file.sent,
pd->file.keepalive));
if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
mg_http_free_proto_data_file(&pd->file);
}
......@@ -655,12 +665,12 @@ struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc,
int matched, matched_max = 0;
struct mg_http_endpoint *ep;
if (nc == NULL) {
return NULL;
}
if (nc == NULL) return NULL;
pd = mg_http_get_proto_data(nc);
if (pd == NULL) return NULL;
ep = pd->endpoints;
while (ep != NULL) {
if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) > 0) {
......@@ -732,13 +742,13 @@ void mg_http_handler(struct mg_connection *nc, int ev,
if (ev == MG_EV_CLOSE) {
#if MG_ENABLE_HTTP_CGI
/* Close associated CGI forwarder connection */
if (pd->cgi.cgi_nc != NULL) {
if (pd != NULL && pd->cgi.cgi_nc != NULL) {
pd->cgi.cgi_nc->user_data = NULL;
pd->cgi.cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
#endif
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
if (pd->mp_stream.boundary != NULL) {
if (pd != NULL && pd->mp_stream.boundary != NULL) {
/*
* Multipart message is in progress, but connection is closed.
* Finish part and request with an error flag.
......@@ -768,14 +778,14 @@ void mg_http_handler(struct mg_connection *nc, int ev,
deliver_chunk(nc, hm, req_len);
mg_http_call_endpoint_handler(nc, ev2, hm);
}
pd->rcvd = 0;
if (pd->endpoint_handler != NULL && pd->endpoint_handler != nc->handler) {
if (pd != NULL && pd->endpoint_handler != NULL &&
pd->endpoint_handler != nc->handler) {
mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
}
}
#if MG_ENABLE_FILESYSTEM
if (pd->file.fp != NULL) {
if (pd != NULL && pd->file.fp != NULL) {
mg_http_transfer_file_data(nc);
}
#endif
......@@ -783,7 +793,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
if (pd->mp_stream.boundary != NULL &&
if (pd != NULL && pd->mp_stream.boundary != NULL &&
(ev == MG_EV_RECV || ev == MG_EV_POLL)) {
if (ev == MG_EV_RECV) {
pd->rcvd += *(int *) ev_data;
......@@ -798,11 +808,16 @@ void mg_http_handler(struct mg_connection *nc, int ev,
if (ev == MG_EV_RECV) {
struct mg_str *s;
pd->rcvd += *(int *) ev_data;
again:
req_len = mg_parse_http(io->buf, io->len, hm, is_req);
if (req_len > 0) {
/* New request - new proto data */
pd = mg_http_create_proto_data(nc);
pd->rcvd = io->len;
}
if (req_len > 0 &&
(s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
mg_vcasecmp(s, "chunked") == 0) {
......@@ -914,18 +929,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
/* If this is a CGI request, we are not done either. */
if (pd->cgi.cgi_nc != NULL) request_done = 0;
#endif
if (request_done) {
/* This request is done but we may receive another on this connection.
*/
mg_http_conn_destructor(pd);
nc->proto_data = NULL;
if (io->len > 0) {
/* We already have data for the next one, restart parsing. */
pd = mg_http_get_proto_data(nc);
pd->rcvd = io->len;
goto again;
}
}
if (request_done && io->len > 0) goto again;
}
}
}
......@@ -3065,6 +3069,7 @@ void mg_register_http_endpoint_opt(struct mg_connection *nc,
if (new_ep == NULL) return;
pd = mg_http_get_proto_data(nc);
if (pd == NULL) pd = mg_http_create_proto_data(nc);
new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path));
if (opts.auth_domain != NULL && opts.auth_file != NULL) {
new_ep->auth_domain = strdup(opts.auth_domain);
......
......@@ -84,6 +84,9 @@ extern void *(*test_calloc)(size_t count, size_t size);
#if MG_ENABLE_HTTP
struct mg_serve_http_opts;
MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
struct mg_connection *c);
/*
* Reassemble the content of the buffer (buf, blen) which should be
* in the HTTP chunked encoding, by collapsing data chunks to the
......
......@@ -1700,7 +1700,7 @@ static void cb10(struct mg_connection *nc, int ev, void *ev_data) {
}
}
static void endpoint_handler(struct mg_connection *nc, int ev, void *ev_data) {
static void default_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
(void) ev_data;
......@@ -1714,7 +1714,8 @@ static void endpoint_handler(struct mg_connection *nc, int ev, void *ev_data) {
}
} else if (ev == MG_EV_CLOSE) {
if (nc->listener != NULL) {
(*(int *) nc->listener->user_data) += 100;
(*(int *) nc->listener->user_data) += 1;
DBG(("%p == default close", nc));
}
}
}
......@@ -1727,7 +1728,8 @@ static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
case MG_EV_CLOSE:
(*(int *) nc->listener->user_data)++;
DBG(("%p == hello1 close", nc));
(*(int *) nc->listener->user_data) += 10;
break;
}
}
......@@ -1740,7 +1742,8 @@ static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) {
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
case MG_EV_CLOSE:
(*(int *) nc->listener->user_data)++;
DBG(("%p == hello2 close", nc));
(*(int *) nc->listener->user_data) += 100;
break;
}
}
......@@ -1753,7 +1756,8 @@ static void handle_hello5(struct mg_connection *nc, int ev, void *ev_data) {
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
case MG_EV_CLOSE:
(*(int *) nc->listener->user_data)++;
DBG(("%p == hello5 close", nc));
(*(int *) nc->listener->user_data) += 1000;
break;
}
}
......@@ -1813,7 +1817,7 @@ static const char *test_http_endpoints(void) {
mg_mgr_init(&mgr, NULL);
/* mgr.hexdump_file = "-"; */
ASSERT((nc = mg_bind(&mgr, local_addr, endpoint_handler)) != NULL);
ASSERT((nc = mg_bind(&mgr, local_addr, default_handler)) != NULL);
mg_register_http_endpoint(nc, "/hello1", handle_hello1 MG_UD_ARG(NULL));
mg_register_http_endpoint(nc, "/hello1/hello2",
handle_hello2 MG_UD_ARG(NULL));
......@@ -1878,7 +1882,7 @@ static const char *test_http_endpoints(void) {
poll_until(&mgr, 1, c_str_ne, buf, (void *) "");
ASSERT_STREQ(buf, "[I am Hello again] 37");
ASSERT_EQ(close_count, 700);
ASSERT_EQ(close_count, 1117);
mg_mgr_free(&mgr);
......@@ -1987,7 +1991,7 @@ static const char *test_http_serve_file_streaming(void) {
ASSERT((nc = mg_connect(&mgr, local_addr, srv2)) != NULL);
mg_set_protocol_http_websocket(nc);
nc->user_data = &status;
mg_printf(nc, "GET / HTTP/1.1\r\n\r\n");
mg_printf(nc, "GET / HTTP/1.0\r\n\r\n");
poll_until(&mgr, 30, c_int_ne, &status, (void *) 0);
ASSERT_EQ(status, 1);
mg_mgr_free(&mgr);
......@@ -3993,6 +3997,7 @@ static const char *test_http_chunk2(void) {
nc.mgr = &mgr;
nc.sock = INVALID_SOCKET;
nc.handler = eh_chunk2;
mg_http_create_proto_data(&nc);
hm.message.len = hm.body.len = ~0;
s_handle_chunk_event = 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