mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-17 10:49:47 +00:00
Deliver EV_CLOSE to the last endpoint handler
CL: mg: Deliver EV_CLOSE to the last endpoint handler PUBLISHED_FROM=02ee2c6627ed9ee1d35022244f71dfe1877ce2c0
This commit is contained in:
1 parent
c277a1d878
commit
e5910da300
4 files changed
+89
-68
No files matched your search
+38
-30
@@ -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);
|
||||
|
||||
MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
|
||||
struct mg_connection *c) {
|
||||
/* 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
+35
-30
@@ -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);
|
||||
|
||||
MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
|
||||
struct mg_connection *c) {
|
||||
/* 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
+13
-8
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user