|
@@ -2320,6 +2320,9 @@ struct mg_handler_info {
|
|
|
|
|
|
/* Handler for http/https or authorization requests. */
|
|
/* Handler for http/https or authorization requests. */
|
|
mg_request_handler handler;
|
|
mg_request_handler handler;
|
|
|
|
+ unsigned int refcount;
|
|
|
|
+ pthread_mutex_t refcount_mutex; /* Protects refcount */
|
|
|
|
+ pthread_cond_t refcount_cond; /* Signaled when handler refcount is decremented */
|
|
|
|
|
|
/* Handler for ws/wss (websocket) requests. */
|
|
/* Handler for ws/wss (websocket) requests. */
|
|
mg_websocket_connect_handler connect_handler;
|
|
mg_websocket_connect_handler connect_handler;
|
|
@@ -12424,6 +12427,30 @@ redirect_to_https_port(struct mg_connection *conn, int ssl_index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void handler_info_acquire(struct mg_handler_info *handler_info)
|
|
|
|
+{
|
|
|
|
+ pthread_mutex_lock(&handler_info->refcount_mutex);
|
|
|
|
+ handler_info->refcount++;
|
|
|
|
+ pthread_mutex_unlock(&handler_info->refcount_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void handler_info_release(struct mg_handler_info *handler_info)
|
|
|
|
+{
|
|
|
|
+ pthread_mutex_lock(&handler_info->refcount_mutex);
|
|
|
|
+ handler_info->refcount--;
|
|
|
|
+ pthread_cond_signal(&handler_info->refcount_cond);
|
|
|
|
+ pthread_mutex_unlock(&handler_info->refcount_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void handler_info_wait_unused(struct mg_handler_info *handler_info)
|
|
|
|
+{
|
|
|
|
+ pthread_mutex_lock(&handler_info->refcount_mutex);
|
|
|
|
+ while (handler_info->refcount) {
|
|
|
|
+ pthread_cond_wait(&handler_info->refcount_cond,&handler_info->refcount_mutex);
|
|
|
|
+ }
|
|
|
|
+ pthread_mutex_unlock(&handler_info->refcount_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
static void
|
|
static void
|
|
mg_set_handler_type(struct mg_context *phys_ctx,
|
|
mg_set_handler_type(struct mg_context *phys_ctx,
|
|
@@ -12511,6 +12538,10 @@ mg_set_handler_type(struct mg_context *phys_ctx,
|
|
if (!is_delete_request) {
|
|
if (!is_delete_request) {
|
|
/* update existing handler */
|
|
/* update existing handler */
|
|
if (handler_type == REQUEST_HANDLER) {
|
|
if (handler_type == REQUEST_HANDLER) {
|
|
|
|
+ /* Wait for end of use before updating */
|
|
|
|
+ handler_info_wait_unused(tmp_rh);
|
|
|
|
+
|
|
|
|
+ /* Ok, the handler is no more use -> Update it */
|
|
tmp_rh->handler = handler;
|
|
tmp_rh->handler = handler;
|
|
} else if (handler_type == WEBSOCKET_HANDLER) {
|
|
} else if (handler_type == WEBSOCKET_HANDLER) {
|
|
tmp_rh->subprotocols = subprotocols;
|
|
tmp_rh->subprotocols = subprotocols;
|
|
@@ -12524,6 +12555,14 @@ mg_set_handler_type(struct mg_context *phys_ctx,
|
|
tmp_rh->cbdata = cbdata;
|
|
tmp_rh->cbdata = cbdata;
|
|
} else {
|
|
} else {
|
|
/* remove existing handler */
|
|
/* remove existing handler */
|
|
|
|
+ if (handler_type == REQUEST_HANDLER) {
|
|
|
|
+ /* Wait for end of use before removing */
|
|
|
|
+ handler_info_wait_unused(tmp_rh);
|
|
|
|
+
|
|
|
|
+ /* Ok, the handler is no more used -> Destroy resources */
|
|
|
|
+ pthread_cond_destroy(&tmp_rh->refcount_cond);
|
|
|
|
+ pthread_mutex_destroy(&tmp_rh->refcount_mutex);
|
|
|
|
+ }
|
|
*lastref = tmp_rh->next;
|
|
*lastref = tmp_rh->next;
|
|
mg_free(tmp_rh->uri);
|
|
mg_free(tmp_rh->uri);
|
|
mg_free(tmp_rh);
|
|
mg_free(tmp_rh);
|
|
@@ -12564,6 +12603,25 @@ mg_set_handler_type(struct mg_context *phys_ctx,
|
|
}
|
|
}
|
|
tmp_rh->uri_len = urilen;
|
|
tmp_rh->uri_len = urilen;
|
|
if (handler_type == REQUEST_HANDLER) {
|
|
if (handler_type == REQUEST_HANDLER) {
|
|
|
|
+ /* Init refcount mutex and condition */
|
|
|
|
+ if (0 != pthread_mutex_init(&tmp_rh->refcount_mutex, NULL)) {
|
|
|
|
+ mg_unlock_context(phys_ctx);
|
|
|
|
+ mg_free(tmp_rh);
|
|
|
|
+ mg_cry_internal(fc(phys_ctx),
|
|
|
|
+ "%s",
|
|
|
|
+ "Cannot init refcount mutex");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
|
|
|
|
+ mg_unlock_context(phys_ctx);
|
|
|
|
+ pthread_mutex_destroy(&tmp_rh->refcount_mutex);
|
|
|
|
+ mg_free(tmp_rh);
|
|
|
|
+ mg_cry_internal(fc(phys_ctx),
|
|
|
|
+ "%s",
|
|
|
|
+ "Cannot init refcount cond");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ tmp_rh->refcount = 0;
|
|
tmp_rh->handler = handler;
|
|
tmp_rh->handler = handler;
|
|
} else if (handler_type == WEBSOCKET_HANDLER) {
|
|
} else if (handler_type == WEBSOCKET_HANDLER) {
|
|
tmp_rh->subprotocols = subprotocols;
|
|
tmp_rh->subprotocols = subprotocols;
|
|
@@ -12687,7 +12745,8 @@ get_request_handler(struct mg_connection *conn,
|
|
mg_websocket_data_handler *data_handler,
|
|
mg_websocket_data_handler *data_handler,
|
|
mg_websocket_close_handler *close_handler,
|
|
mg_websocket_close_handler *close_handler,
|
|
mg_authorization_handler *auth_handler,
|
|
mg_authorization_handler *auth_handler,
|
|
- void **cbdata)
|
|
|
|
|
|
+ void **cbdata,
|
|
|
|
+ struct mg_handler_info **handler_info)
|
|
{
|
|
{
|
|
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
|
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
|
if (request_info) {
|
|
if (request_info) {
|
|
@@ -12714,6 +12773,9 @@ get_request_handler(struct mg_connection *conn,
|
|
*close_handler = tmp_rh->close_handler;
|
|
*close_handler = tmp_rh->close_handler;
|
|
} else if (handler_type == REQUEST_HANDLER) {
|
|
} else if (handler_type == REQUEST_HANDLER) {
|
|
*handler = tmp_rh->handler;
|
|
*handler = tmp_rh->handler;
|
|
|
|
+ /* Acquire handler and give it back */
|
|
|
|
+ handler_info_acquire(tmp_rh);
|
|
|
|
+ *handler_info = tmp_rh;
|
|
} else { /* AUTH_HANDLER */
|
|
} else { /* AUTH_HANDLER */
|
|
*auth_handler = tmp_rh->auth_handler;
|
|
*auth_handler = tmp_rh->auth_handler;
|
|
}
|
|
}
|
|
@@ -12738,6 +12800,9 @@ get_request_handler(struct mg_connection *conn,
|
|
*close_handler = tmp_rh->close_handler;
|
|
*close_handler = tmp_rh->close_handler;
|
|
} else if (handler_type == REQUEST_HANDLER) {
|
|
} else if (handler_type == REQUEST_HANDLER) {
|
|
*handler = tmp_rh->handler;
|
|
*handler = tmp_rh->handler;
|
|
|
|
+ /* Acquire handler and give it back */
|
|
|
|
+ handler_info_acquire(tmp_rh);
|
|
|
|
+ *handler_info = tmp_rh;
|
|
} else { /* AUTH_HANDLER */
|
|
} else { /* AUTH_HANDLER */
|
|
*auth_handler = tmp_rh->auth_handler;
|
|
*auth_handler = tmp_rh->auth_handler;
|
|
}
|
|
}
|
|
@@ -12761,6 +12826,9 @@ get_request_handler(struct mg_connection *conn,
|
|
*close_handler = tmp_rh->close_handler;
|
|
*close_handler = tmp_rh->close_handler;
|
|
} else if (handler_type == REQUEST_HANDLER) {
|
|
} else if (handler_type == REQUEST_HANDLER) {
|
|
*handler = tmp_rh->handler;
|
|
*handler = tmp_rh->handler;
|
|
|
|
+ /* Acquire handler and give it back */
|
|
|
|
+ handler_info_acquire(tmp_rh);
|
|
|
|
+ *handler_info = tmp_rh;
|
|
} else { /* AUTH_HANDLER */
|
|
} else { /* AUTH_HANDLER */
|
|
*auth_handler = tmp_rh->auth_handler;
|
|
*auth_handler = tmp_rh->auth_handler;
|
|
}
|
|
}
|
|
@@ -12848,6 +12916,7 @@ handle_request(struct mg_connection *conn)
|
|
int i;
|
|
int i;
|
|
struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
mg_request_handler callback_handler = NULL;
|
|
mg_request_handler callback_handler = NULL;
|
|
|
|
+ struct mg_handler_info *handler_info = NULL;
|
|
struct mg_websocket_subprotocols *subprotocols;
|
|
struct mg_websocket_subprotocols *subprotocols;
|
|
mg_websocket_connect_handler ws_connect_handler = NULL;
|
|
mg_websocket_connect_handler ws_connect_handler = NULL;
|
|
mg_websocket_ready_handler ws_ready_handler = NULL;
|
|
mg_websocket_ready_handler ws_ready_handler = NULL;
|
|
@@ -13020,7 +13089,8 @@ handle_request(struct mg_connection *conn)
|
|
&ws_data_handler,
|
|
&ws_data_handler,
|
|
&ws_close_handler,
|
|
&ws_close_handler,
|
|
NULL,
|
|
NULL,
|
|
- &callback_data)) {
|
|
|
|
|
|
+ &callback_data,
|
|
|
|
+ &handler_info)) {
|
|
/* 5.2.1. A callback will handle this request. All requests
|
|
/* 5.2.1. A callback will handle this request. All requests
|
|
* handled
|
|
* handled
|
|
* by a callback have to be considered as requests to a script
|
|
* by a callback have to be considered as requests to a script
|
|
@@ -13056,7 +13126,8 @@ handle_request(struct mg_connection *conn)
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&auth_handler,
|
|
&auth_handler,
|
|
- &auth_callback_data)) {
|
|
|
|
|
|
+ &auth_callback_data,
|
|
|
|
+ NULL)) {
|
|
if (!auth_handler(conn, auth_callback_data)) {
|
|
if (!auth_handler(conn, auth_callback_data)) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -13104,6 +13175,10 @@ handle_request(struct mg_connection *conn)
|
|
if (is_callback_resource) {
|
|
if (is_callback_resource) {
|
|
if (!is_websocket_request) {
|
|
if (!is_websocket_request) {
|
|
i = callback_handler(conn, callback_data);
|
|
i = callback_handler(conn, callback_data);
|
|
|
|
+
|
|
|
|
+ /* Callback handler will not be used anymore. Release it */
|
|
|
|
+ handler_info_release(handler_info);
|
|
|
|
+
|
|
if (i > 0) {
|
|
if (i > 0) {
|
|
/* Do nothing, callback has served the request. Store
|
|
/* Do nothing, callback has served the request. Store
|
|
* then return value as status code for the log and discard
|
|
* then return value as status code for the log and discard
|
|
@@ -17252,6 +17327,10 @@ free_context(struct mg_context *ctx)
|
|
while (ctx->dd.handlers) {
|
|
while (ctx->dd.handlers) {
|
|
tmp_rh = ctx->dd.handlers;
|
|
tmp_rh = ctx->dd.handlers;
|
|
ctx->dd.handlers = tmp_rh->next;
|
|
ctx->dd.handlers = tmp_rh->next;
|
|
|
|
+ if (tmp_rh->handler_type == REQUEST_HANDLER) {
|
|
|
|
+ pthread_cond_destroy(&tmp_rh->refcount_cond);
|
|
|
|
+ pthread_mutex_destroy(&tmp_rh->refcount_mutex);
|
|
|
|
+ }
|
|
mg_free(tmp_rh->uri);
|
|
mg_free(tmp_rh->uri);
|
|
mg_free(tmp_rh);
|
|
mg_free(tmp_rh);
|
|
}
|
|
}
|