[asterisk-commits] ari: Implement 'debug all' and request/response logging (asterisk[14])

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jan 26 18:46:20 CST 2017


Anonymous Coward #1000019 has submitted this change and it was merged. ( https://gerrit.asterisk.org/4748 )

Change subject: ari: Implement 'debug all' and request/response logging
......................................................................


ari: Implement 'debug all' and request/response logging

The 'ari set debug' command has been enhanced to accept 'all' as an
application name.  This allows dumping of all apps even if an app
hasn't registered yet.  To accomplish this, a new global_debug global
variable was added to res/stasis/app.c and new APIs were added to
set and query the value.

'ari set debug' now displays requests and responses as well as events.
This required refactoring the existing debug code.

* The implementation for 'ari set debug' was moved from stasis/cli.{c,h}
  to ari/cli.{c,h}, and stasis/cli.{c,h} were deleted.
* In order to print the body of incoming requests even if a request
  failed, the consumption of the body was moved from the ari stubs
  to ast_ari_callback in res_ari.c and the moustache templates were
  then regenerated.  The body is now passed to ast_ari_invoke and then
  on to the handlers.  This results in code savings since that template
  was inserted multiple times into all the stubs.

An additional change was made to the ao2_str_container implementation
to add partial key searching and a sort function.  The existing cli
code assumed it was already there when it wasn't so the tab completion
was never working.

Change-Id: Ief936f747ce47f1fb14035fbe61152cf766406bf
---
M CHANGES
M include/asterisk/ari.h
M include/asterisk/stasis_app.h
M main/strings.c
M res/ari/ari_websockets.c
M res/ari/cli.c
M res/ari/resource_events.c
M res/res_ari.c
M res/res_ari_applications.c
M res/res_ari_asterisk.c
M res/res_ari_bridges.c
M res/res_ari_channels.c
M res/res_ari_device_states.c
M res/res_ari_endpoints.c
M res/res_ari_events.c
M res/res_ari_mailboxes.c
M res/res_ari_playbacks.c
M res/res_ari_recordings.c
M res/res_ari_sounds.c
M res/res_stasis.c
M res/stasis/app.c
M res/stasis/app.h
D res/stasis/cli.c
D res/stasis/cli.h
M res/stasis/stasis_bridge.c
M rest-api-templates/param_parsing.mustache
M rest-api-templates/res_ari_resource.c.mustache
M tests/test_ari.c
28 files changed, 527 insertions(+), 1,159 deletions(-)

Approvals:
  Mark Michelson: Looks good to me, but someone else must approve
  Anonymous Coward #1000019: Verified
  Joshua Colp: Looks good to me, approved



diff --git a/CHANGES b/CHANGES
index 04861c2..be58488 100644
--- a/CHANGES
+++ b/CHANGES
@@ -50,6 +50,14 @@
    source IP addresses for requests. This is configurable using the
    "srv_lookups" option on the identify and defaults to "yes".
 
+ARI
+------------------
+ * The 'ari set debug' command has been enhanced to accept 'all' as an
+   application name.  This allows dumping of all apps even if an app
+   hasn't registered yet.
+
+ * 'ari set debug' now displays requests and responses as well as events.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------
 ------------------------------------------------------------------------------
diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h
index 4019e94..865b4b0 100644
--- a/include/asterisk/ari.h
+++ b/include/asterisk/ari.h
@@ -59,7 +59,8 @@
 typedef void (*stasis_rest_callback)(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response);
+	struct ast_variable *headers, struct ast_json *body,
+	struct ast_ari_response *response);
 
 /*!
  * \brief Handler for a single RESTful path segment.
@@ -136,7 +137,7 @@
 void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
 	const char *uri, enum ast_http_method method,
 	struct ast_variable *get_params, struct ast_variable *headers,
-	struct ast_ari_response *response);
+	struct ast_json *body, struct ast_ari_response *response);
 
 /*!
  * \internal
@@ -201,6 +202,15 @@
 	const struct ast_ari_websocket_session *session);
 
 /*!
+ * \brief Get the remote address from an ARI WebSocket.
+ *
+ * \param session Session to write to.
+ * \return ast_sockaddr (does not have to be freed)
+ */
+struct ast_sockaddr *ast_ari_websocket_session_get_remote_addr(
+	struct ast_ari_websocket_session *session);
+
+/*!
  * \brief The stock message to return when out of memory.
  *
  * The refcount is NOT bumped on this object, so ast_json_ref() if you want to
diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h
index 137cbb9..e131833 100644
--- a/include/asterisk/stasis_app.h
+++ b/include/asterisk/stasis_app.h
@@ -903,6 +903,56 @@
  * allocated during the time that res_stasis was loaded.
  */
 void stasis_app_control_shutdown(void);
+
+/*!
+ * \brief Enable/disable request/response and event logging on an application
+ *
+ * \param app The app to debug
+ * \param debug If non-zero, enable debugging. If zero, disable.
+ */
+void stasis_app_set_debug(struct stasis_app *app, int debug);
+
+/*!
+ * \brief Enable/disable request/response and event logging on an application
+ *
+ * \param app_name The app name to debug
+ * \param debug If non-zero, enable debugging. If zero, disable.
+ */
+void stasis_app_set_debug_by_name(const char *app_name, int debug);
+
+/*!
+ * \brief Get debug status of an application
+ *
+ * \param app The app to check
+ * \return The debug flag for the app || the global debug flag
+ */
+int stasis_app_get_debug(struct stasis_app *app);
+
+/*!
+ * \brief Get debug status of an application
+ *
+ * \param app_name The app_name to check
+ * \return The debug flag for the app || the global debug flag
+ */
+int stasis_app_get_debug_by_name(const char *app_name);
+
+/*!
+ * \brief Enable/disable request/response and event logging on all applications
+ *
+ * \param debug If non-zero, enable debugging. If zero, disable.
+ */
+void stasis_app_set_global_debug(int debug);
+
+struct ast_cli_args;
+
+/*!
+ * \brief Dump properties of a \c stasis_app to the CLI
+ *
+ * \param app The application
+ * \param a The CLI arguments
+ */
+void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a);
+
 /*! @} */
 
 #endif /* _ASTERISK_STASIS_APP_H */
diff --git a/main/strings.c b/main/strings.c
index e62eb9a..feb67ec 100644
--- a/main/strings.c
+++ b/main/strings.c
@@ -186,15 +186,32 @@
 	return ast_str_hash(obj);
 }
 
+static int str_sort(const void *lhs, const void *rhs, int flags)
+{
+	if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) {
+		return strncmp(lhs, rhs, strlen(rhs));
+	} else {
+		return strcmp(lhs, rhs);
+	}
+}
+
 static int str_cmp(void *lhs, void *rhs, int flags)
 {
-	return strcmp(lhs, rhs) ? 0 : CMP_MATCH;
+	int cmp = 0;
+
+	if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) {
+		cmp = strncmp(lhs, rhs, strlen(rhs));
+	} else {
+		cmp = strcmp(lhs, rhs);
+	}
+
+	return cmp ? 0 : CMP_MATCH;
 }
 
 //struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets)
 struct ao2_container *ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
 {
-	return ao2_container_alloc_options(opts, buckets, str_hash, str_cmp);
+	return ao2_container_alloc_hash(opts, 0, buckets, str_hash, str_sort, str_cmp);
 }
 
 int ast_str_container_add(struct ao2_container *str_container, const char *add)
diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c
index 72e5273..7407bd8 100644
--- a/res/ari/ari_websockets.c
+++ b/res/ari/ari_websockets.c
@@ -23,6 +23,7 @@
 #include "asterisk/ari.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/http_websocket.h"
+#include "asterisk/stasis_app.h"
 #include "internal.h"
 
 /*! \file
@@ -139,6 +140,7 @@
 				ast_log(LOG_WARNING,
 					"WebSocket input failed to parse\n");
 			}
+
 			break;
 		default:
 			/* Ignore all other message types */
@@ -174,16 +176,20 @@
 		return -1;
 	}
 
-#ifdef AST_DEVMODE
-	ast_debug(3, "Examining ARI event (length %u): \n%s\n", (unsigned int) strlen(str), str);
-#endif
 	if (ast_websocket_write_string(session->ws_session, str)) {
-		ast_log(LOG_NOTICE, "Problem occurred during websocket write, websocket closed\n");
+		ast_log(LOG_NOTICE, "Problem occurred during websocket write to %s, websocket closed\n",
+			ast_sockaddr_stringify(ast_ari_websocket_session_get_remote_addr(session)));
 		return -1;
 	}
 	return 0;
 }
 
+struct ast_sockaddr *ast_ari_websocket_session_get_remote_addr(
+	struct ast_ari_websocket_session *session)
+{
+	return ast_websocket_remote_address(session->ws_session);
+}
+
 void ari_handle_websocket(struct ast_websocket_server *ws_server,
 	struct ast_tcptls_session_instance *ser, const char *uri,
 	enum ast_http_method method, struct ast_variable *get_params,
diff --git a/res/ari/cli.c b/res/ari/cli.c
index 4468e44..10a6538 100644
--- a/res/ari/cli.c
+++ b/res/ari/cli.c
@@ -28,6 +28,7 @@
 
 #include "asterisk/astobj2.h"
 #include "asterisk/cli.h"
+#include "asterisk/stasis_app.h"
 #include "internal.h"
 
 static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -251,11 +252,185 @@
 	return CLI_SUCCESS;
 }
 
+static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ao2_container *apps;
+	struct ao2_iterator it_apps;
+	char *app;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "ari show apps";
+		e->usage =
+			"Usage: ari show apps\n"
+			"       Lists all registered applications.\n"
+			;
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	default:
+		break;
+	}
+
+	if (a->argc != 3) {
+		return CLI_SHOWUSAGE;
+	}
+
+	apps = stasis_app_get_all();
+	if (!apps) {
+		ast_cli(a->fd, "Unable to retrieve registered applications!\n");
+		return CLI_FAILURE;
+	}
+
+	ast_cli(a->fd, "Application Name         \n");
+	ast_cli(a->fd, "=========================\n");
+	it_apps = ao2_iterator_init(apps, 0);
+	while ((app = ao2_iterator_next(&it_apps))) {
+		ast_cli(a->fd, "%-25.25s\n", app);
+		ao2_ref(app, -1);
+	}
+
+	ao2_iterator_destroy(&it_apps);
+	ao2_ref(apps, -1);
+
+	return CLI_SUCCESS;
+}
+
+struct app_complete {
+	/*! Nth app to search for */
+	int state;
+	/*! Which app currently on */
+	int which;
+};
+
+static int complete_ari_app_search(void *obj, void *arg, void *data, int flags)
+{
+	struct app_complete *search = data;
+
+	if (++search->which > search->state) {
+		return CMP_MATCH;
+	}
+	return 0;
+}
+
+static char *complete_ari_app(struct ast_cli_args *a, int include_all)
+{
+	RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup);
+	RAII_VAR(char *, app, NULL, ao2_cleanup);
+
+	struct app_complete search = {
+		.state = a->n,
+	};
+
+	if (a->pos != 3) {
+		return NULL;
+	}
+
+	if (!apps) {
+		ast_cli(a->fd, "Error getting ARI applications\n");
+		return CLI_FAILURE;
+	}
+
+	if (include_all && ast_strlen_zero(a->word)) {
+		ast_str_container_add(apps, " all");
+	}
+
+	app = ao2_callback_data(apps,
+		ast_strlen_zero(a->word) ? 0 : OBJ_SEARCH_PARTIAL_KEY,
+		complete_ari_app_search, (char*)a->word, &search);
+
+	return app ? ast_strdup(app) : NULL;
+}
+
+static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	void *app;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "ari show app";
+		e->usage =
+			"Usage: ari show app <application>\n"
+			"       Provide detailed information about a registered application.\n"
+			;
+		return NULL;
+	case CLI_GENERATE:
+		return complete_ari_app(a, 0);
+	default:
+		break;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	app = stasis_app_get_by_name(a->argv[3]);
+	if (!app) {
+		return CLI_FAILURE;
+	}
+
+	stasis_app_to_cli(app, a);
+
+	ao2_ref(app, -1);
+
+	return CLI_SUCCESS;
+}
+
+static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	void *app;
+	int debug;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "ari set debug";
+		e->usage =
+			"Usage: ari set debug <application|all> <on|off>\n"
+			"       Enable or disable debugging on a specific application.\n"
+			;
+		return NULL;
+	case CLI_GENERATE:
+		return complete_ari_app(a, 1);
+	default:
+		break;
+	}
+
+	if (a->argc != 5) {
+		return CLI_SHOWUSAGE;
+	}
+
+	debug = !strcmp(a->argv[4], "on");
+
+	if (!strcmp(a->argv[3], "all")) {
+		stasis_app_set_global_debug(debug);
+		ast_cli(a->fd, "Debugging on all applications %s\n",
+			debug ? "enabled" : "disabled");
+		return CLI_SUCCESS;
+	}
+
+	app = stasis_app_get_by_name(a->argv[3]);
+	if (!app) {
+		return CLI_FAILURE;
+	}
+
+	stasis_app_set_debug(app, debug);
+	ast_cli(a->fd, "Debugging on '%s' %s\n",
+		stasis_app_name(app),
+		debug ? "enabled" : "disabled");
+
+	ao2_ref(app, -1);
+
+	return CLI_SUCCESS;
+}
+
 static struct ast_cli_entry cli_ari[] = {
 	AST_CLI_DEFINE(ari_show, "Show ARI settings"),
 	AST_CLI_DEFINE(ari_show_users, "List ARI users"),
 	AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
 	AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"),
+	AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"),
+	AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"),
+	AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"),
 };
 
 int ast_ari_cli_register(void) {
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c
index 8fa15f5..3c65582 100644
--- a/res/ari/resource_events.c
+++ b/res/ari/resource_events.c
@@ -29,6 +29,7 @@
 
 #include "resource_events.h"
 #include "asterisk/astobj2.h"
+#include "asterisk/http_websocket.h"
 #include "asterisk/stasis_app.h"
 #include "asterisk/vector.h"
 
@@ -110,6 +111,15 @@
 				msg_type,
 				msg_application);
 	} else {
+		if (stasis_app_get_debug_by_name(app_name)) {
+			char *str = ast_json_dump_string_format(message, ast_ari_json_format());
+
+			ast_verbose("<--- Sending ARI event to %s --->\n%s\n",
+				ast_sockaddr_stringify(ast_ari_websocket_session_get_remote_addr(session->ws_session)),
+				str);
+			ast_json_free(str);
+		}
+
 		/* We are ready to publish the message */
 		ast_ari_websocket_session_write(session->ws_session, message);
 	}
diff --git a/res/res_ari.c b/res/res_ari.c
index f976723..56b0a44 100644
--- a/res/res_ari.c
+++ b/res/res_ari.c
@@ -150,6 +150,7 @@
 #include "asterisk/astobj2.h"
 #include "asterisk/module.h"
 #include "asterisk/paths.h"
+#include "asterisk/stasis_app.h"
 
 #include <string.h>
 #include <sys/stat.h>
@@ -493,7 +494,7 @@
 void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
 	const char *uri, enum ast_http_method method,
 	struct ast_variable *get_params, struct ast_variable *headers,
-	struct ast_ari_response *response)
+	struct ast_json *body, struct ast_ari_response *response)
 {
 	RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
 	struct stasis_rest_handlers *handler;
@@ -508,8 +509,10 @@
 	while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
 		struct stasis_rest_handlers *found_handler = NULL;
 		int i;
+
 		ast_uri_decode(path_segment, ast_uri_http_legacy);
 		ast_debug(3, "Finding handler for %s\n", path_segment);
+
 		for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
 			struct stasis_rest_handlers *child = handler->children[i];
 
@@ -571,7 +574,7 @@
 		return;
 	}
 
-	callback(ser, get_params, path_vars, headers, response);
+	callback(ser, get_params, path_vars, headers, body, response);
 	if (response->message == NULL && response->response_code == 0) {
 		/* Really should not happen */
 		ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
@@ -881,6 +884,10 @@
 	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
 	struct ast_ari_response response = { .fd = -1, 0 };
 	RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
+	struct ast_variable *var;
+	const char *app_name = NULL;
+	RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_free);
+	int debug_app = 0;
 
 	if (!response_body) {
 		ast_http_request_close_on_completion(ser);
@@ -928,6 +935,25 @@
 				"Bad Request", "Error parsing request body");
 			goto request_failed;
 		}
+
+		/* Look for a JSON request entity only if there were no post_vars.
+		 * If there were post_vars, then the request body would already have
+		 * been consumed and can not be read again.
+		 */
+		body = ast_http_get_json(ser, headers);
+		if (!body) {
+			switch (errno) {
+			case EFBIG:
+				ast_ari_response_error(&response, 413, "Request Entity Too Large", "Request body too large");
+				goto request_failed;
+			case ENOMEM:
+				ast_ari_response_error(&response, 500, "Internal Server Error", "Error processing request");
+				goto request_failed;
+			case EIO:
+				ast_ari_response_error(&response, 400, "Bad Request", "Error parsing request body");
+				goto request_failed;
+			}
+		}
 	}
 	if (get_params == NULL) {
 		get_params = post_vars;
@@ -942,6 +968,41 @@
 		 */
 		last_var->next = ast_variables_dup(get_params);
 		get_params = post_vars;
+	}
+
+	/* At this point, get_params will contain post_vars (if any) */
+	app_name = ast_variable_find_in_list(get_params, "app");
+	if (!app_name) {
+		struct ast_json *app = ast_json_object_get(body, "app");
+
+		app_name = (app ? ast_json_string_get(app) : NULL);
+	}
+
+	/* stasis_app_get_debug_by_name returns an "||" of the app's debug flag
+	 * and the global debug flag.
+	 */
+	debug_app = stasis_app_get_debug_by_name(app_name);
+	if (debug_app) {
+		struct ast_str *buf = ast_str_create(512);
+		char *str = ast_json_dump_string_format(body, ast_ari_json_format());
+
+		if (!buf) {
+			ast_http_request_close_on_completion(ser);
+			ast_http_error(ser, 500, "Server Error", "Out of memory");
+			goto request_failed;
+		}
+
+		ast_str_append(&buf, 0, "<--- ARI request received from: %s --->\n",
+			ast_sockaddr_stringify(&ser->remote_address));
+		for (var = headers; var; var = var->next) {
+			ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
+		}
+		for (var = get_params; var; var = var->next) {
+			ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
+		}
+		ast_verbose("%sbody:\n%s\n\n", ast_str_buffer(buf), str);
+		ast_json_free(str);
+		ast_free(buf);
 	}
 
 	user = authenticate_user(get_params, headers);
@@ -982,7 +1043,7 @@
 		}
 	} else {
 		/* Other RESTful resources */
-		ast_ari_invoke(ser, uri, method, get_params, headers,
+		ast_ari_invoke(ser, uri, method, get_params, headers, body,
 			&response);
 	}
 
@@ -994,6 +1055,7 @@
 	}
 
 request_failed:
+
 	/* If you explicitly want to have no content, set message to
 	 * ast_json_null().
 	 */
@@ -1016,8 +1078,13 @@
 		}
 	}
 
-	ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code,
-		response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body));
+	if (debug_app) {
+		ast_verbose("<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n",
+			ast_sockaddr_stringify(&ser->remote_address), response.response_code,
+			response.response_text, ast_str_buffer(response.headers),
+			ast_str_buffer(response_body));
+	}
+
 	ast_http_send(ser, method, response.response_code,
 		      response.response_text, response.headers, response_body,
 		      response.fd != -1 ? response.fd : 0, 0);
diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c
index 7ce9722..f2b5b8e 100644
--- a/res/res_ari_applications.c
+++ b/res/res_ari_applications.c
@@ -62,10 +62,9 @@
 static void ast_ari_applications_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_applications_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -113,11 +112,10 @@
 static void ast_ari_applications_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_applications_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -210,11 +208,10 @@
 static void ast_ari_applications_subscribe_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_applications_subscribe_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -271,21 +268,6 @@
 			args.application_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_applications_subscribe_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -376,11 +358,10 @@
 static void ast_ari_applications_unsubscribe_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_applications_unsubscribe_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -437,21 +418,6 @@
 			args.application_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_applications_unsubscribe_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c
index 71f72ee..ae3f10f 100644
--- a/res/res_ari_asterisk.c
+++ b/res/res_ari_asterisk.c
@@ -62,11 +62,10 @@
 static void ast_ari_asterisk_get_object_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_get_object_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -135,11 +134,10 @@
 static void ast_ari_asterisk_update_object_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_update_object_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -156,21 +154,6 @@
 			args.id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	args.fields = body;
 	ast_ari_asterisk_update_object(headers, &args, response);
@@ -218,11 +201,10 @@
 static void ast_ari_asterisk_delete_object_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_delete_object_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -322,11 +304,10 @@
 static void ast_ari_asterisk_get_info_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_get_info_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -378,21 +359,6 @@
 		} else
 		{}
 	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
 	if (ast_ari_asterisk_get_info_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
 		goto fin;
@@ -441,10 +407,9 @@
 static void ast_ari_asterisk_list_modules_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_list_modules_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -492,11 +457,10 @@
 static void ast_ari_asterisk_get_module_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_get_module_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -552,11 +516,10 @@
 static void ast_ari_asterisk_load_module_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_load_module_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -611,11 +574,10 @@
 static void ast_ari_asterisk_unload_module_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_unload_module_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -671,11 +633,10 @@
 static void ast_ari_asterisk_reload_module_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_reload_module_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -731,10 +692,9 @@
 static void ast_ari_asterisk_list_log_channels_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_list_log_channels_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -795,11 +755,10 @@
 static void ast_ari_asterisk_add_log_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_add_log_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -816,21 +775,6 @@
 			args.log_channel_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_asterisk_add_log_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -880,11 +824,10 @@
 static void ast_ari_asterisk_delete_log_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_delete_log_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -939,11 +882,10 @@
 static void ast_ari_asterisk_rotate_log_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_rotate_log_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1011,11 +953,10 @@
 static void ast_ari_asterisk_get_global_var_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_get_global_var_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1026,21 +967,6 @@
 			args.variable = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1106,11 +1032,10 @@
 static void ast_ari_asterisk_set_global_var_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_asterisk_set_global_var_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1124,21 +1049,6 @@
 			args.value = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c
index 79610cd..96aa951 100644
--- a/res/res_ari_bridges.c
+++ b/res/res_ari_bridges.c
@@ -62,10 +62,9 @@
 static void ast_ari_bridges_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -134,11 +133,10 @@
 static void ast_ari_bridges_create_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_create_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -155,21 +153,6 @@
 			args.name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_create_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -234,11 +217,10 @@
 static void ast_ari_bridges_create_with_id_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_create_with_id_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -258,21 +240,6 @@
 			args.bridge_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_create_with_id_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -320,11 +287,10 @@
 static void ast_ari_bridges_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -379,11 +345,10 @@
 static void ast_ari_bridges_destroy_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_destroy_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -480,11 +445,10 @@
 static void ast_ari_bridges_add_channel_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_add_channel_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -544,21 +508,6 @@
 			args.bridge_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_add_channel_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -650,11 +599,10 @@
 static void ast_ari_bridges_remove_channel_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_remove_channel_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -712,21 +660,6 @@
 		} else
 		{}
 	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
 	if (ast_ari_bridges_remove_channel_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
 		goto fin;
@@ -779,11 +712,10 @@
 static void ast_ari_bridges_set_video_source_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_set_video_source_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -843,11 +775,10 @@
 static void ast_ari_bridges_clear_video_source_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_clear_video_source_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -915,11 +846,10 @@
 static void ast_ari_bridges_start_moh_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_start_moh_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -936,21 +866,6 @@
 			args.bridge_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_start_moh_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1000,11 +915,10 @@
 static void ast_ari_bridges_stop_moh_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_stop_moh_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1114,11 +1028,10 @@
 static void ast_ari_bridges_play_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_play_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1187,21 +1100,6 @@
 			args.bridge_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_play_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1303,11 +1201,10 @@
 static void ast_ari_bridges_play_with_id_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_play_with_id_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1376,21 +1273,6 @@
 			args.playback_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_play_with_id_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1479,11 +1361,10 @@
 static void ast_ari_bridges_record_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_bridges_record_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1518,21 +1399,6 @@
 			args.bridge_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_bridges_record_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 9e8eeb4..6a64552 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -62,10 +62,9 @@
 static void ast_ari_channels_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -174,11 +173,10 @@
 static void ast_ari_channels_originate_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_originate_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -225,21 +223,6 @@
 			args.formats = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	args.variables = body;
 	ast_ari_channels_originate(headers, &args, response);
@@ -323,11 +306,10 @@
 static void ast_ari_channels_create_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_create_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -356,21 +338,6 @@
 			args.formats = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_create_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -419,11 +386,10 @@
 static void ast_ari_channels_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -535,11 +501,10 @@
 static void ast_ari_channels_originate_with_id_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_originate_with_id_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -589,21 +554,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	args.variables = body;
 	ast_ari_channels_originate_with_id(headers, &args, response);
@@ -663,11 +613,10 @@
 static void ast_ari_channels_hangup_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_hangup_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -684,21 +633,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_hangup_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -773,11 +707,10 @@
 static void ast_ari_channels_continue_in_dialplan_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_continue_in_dialplan_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -803,21 +736,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_continue_in_dialplan_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -881,11 +799,10 @@
 static void ast_ari_channels_redirect_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_redirect_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -902,21 +819,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_redirect_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -969,11 +871,10 @@
 static void ast_ari_channels_answer_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_answer_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1030,11 +931,10 @@
 static void ast_ari_channels_ring_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_ring_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1091,11 +991,10 @@
 static void ast_ari_channels_ring_stop_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_ring_stop_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1181,11 +1080,10 @@
 static void ast_ari_channels_send_dtmf_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_send_dtmf_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1214,21 +1112,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_send_dtmf_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1293,11 +1176,10 @@
 static void ast_ari_channels_mute_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_mute_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1314,21 +1196,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_mute_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1392,11 +1259,10 @@
 static void ast_ari_channels_unmute_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_unmute_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1413,21 +1279,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_unmute_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1478,11 +1329,10 @@
 static void ast_ari_channels_hold_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_hold_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1539,11 +1389,10 @@
 static void ast_ari_channels_unhold_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_unhold_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1613,11 +1462,10 @@
 static void ast_ari_channels_start_moh_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_start_moh_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1634,21 +1482,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_start_moh_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -1699,11 +1532,10 @@
 static void ast_ari_channels_stop_moh_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_stop_moh_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1760,11 +1592,10 @@
 static void ast_ari_channels_start_silence_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_start_silence_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1821,11 +1652,10 @@
 static void ast_ari_channels_stop_silence_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_stop_silence_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -1936,11 +1766,10 @@
 static void ast_ari_channels_play_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_play_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2009,21 +1838,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_play_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2126,11 +1940,10 @@
 static void ast_ari_channels_play_with_id_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_play_with_id_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2199,21 +2012,6 @@
 			args.playback_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_play_with_id_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2303,11 +2101,10 @@
 static void ast_ari_channels_record_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_record_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2342,21 +2139,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_record_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2421,11 +2203,10 @@
 static void ast_ari_channels_get_channel_var_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_get_channel_var_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2442,21 +2223,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_get_channel_var_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2524,11 +2290,10 @@
 static void ast_ari_channels_set_channel_var_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_set_channel_var_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2548,21 +2313,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_set_channel_var_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2642,11 +2392,10 @@
 static void ast_ari_channels_snoop_channel_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_snoop_channel_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2675,21 +2424,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_snoop_channel_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2764,11 +2498,10 @@
 static void ast_ari_channels_snoop_channel_with_id_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_snoop_channel_with_id_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2797,21 +2530,6 @@
 			args.snoop_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_snoop_channel_with_id_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -2878,11 +2596,10 @@
 static void ast_ari_channels_dial_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_channels_dial_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -2902,21 +2619,6 @@
 			args.channel_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_channels_dial_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c
index c3876af..3e8dc0f 100644
--- a/res/res_ari_device_states.c
+++ b/res/res_ari_device_states.c
@@ -62,10 +62,9 @@
 static void ast_ari_device_states_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_device_states_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -113,11 +112,10 @@
 static void ast_ari_device_states_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_device_states_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -184,11 +182,10 @@
 static void ast_ari_device_states_update_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_device_states_update_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -205,21 +202,6 @@
 			args.device_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_device_states_update_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -269,11 +251,10 @@
 static void ast_ari_device_states_delete_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_device_states_delete_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c
index fd38531..1843b6d 100644
--- a/res/res_ari_endpoints.c
+++ b/res/res_ari_endpoints.c
@@ -62,10 +62,9 @@
 static void ast_ari_endpoints_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_endpoints_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -134,11 +133,10 @@
 static void ast_ari_endpoints_send_message_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_endpoints_send_message_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -155,21 +153,6 @@
 			args.body = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	args.variables = body;
 	ast_ari_endpoints_send_message(headers, &args, response);
@@ -216,11 +199,10 @@
 static void ast_ari_endpoints_list_by_tech_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_endpoints_list_by_tech_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -275,11 +257,10 @@
 static void ast_ari_endpoints_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_endpoints_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -355,11 +336,10 @@
 static void ast_ari_endpoints_send_message_to_endpoint_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_endpoints_send_message_to_endpoint_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -382,21 +362,6 @@
 			args.resource = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	args.variables = body;
 	ast_ari_endpoints_send_message_to_endpoint(headers, &args, response);
diff --git a/res/res_ari_events.c b/res/res_ari_events.c
index 40a18b8..19b6fad 100644
--- a/res/res_ari_events.c
+++ b/res/res_ari_events.c
@@ -289,11 +289,10 @@
 static void ast_ari_events_user_event_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_events_user_event_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -353,21 +352,6 @@
 			args.event_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	args.variables = body;
 	ast_ari_events_user_event(headers, &args, response);
diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c
index 5b05323..7b384ce 100644
--- a/res/res_ari_mailboxes.c
+++ b/res/res_ari_mailboxes.c
@@ -62,10 +62,9 @@
 static void ast_ari_mailboxes_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_mailboxes_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -113,11 +112,10 @@
 static void ast_ari_mailboxes_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_mailboxes_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -189,11 +187,10 @@
 static void ast_ari_mailboxes_update_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_mailboxes_update_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -213,21 +210,6 @@
 			args.mailbox_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_mailboxes_update_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -276,11 +258,10 @@
 static void ast_ari_mailboxes_delete_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_mailboxes_delete_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c
index b4dfd1c..1cbd3e3 100644
--- a/res/res_ari_playbacks.c
+++ b/res/res_ari_playbacks.c
@@ -62,11 +62,10 @@
 static void ast_ari_playbacks_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_playbacks_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -121,11 +120,10 @@
 static void ast_ari_playbacks_stop_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_playbacks_stop_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -193,11 +191,10 @@
 static void ast_ari_playbacks_control_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_playbacks_control_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -214,21 +211,6 @@
 			args.playback_id = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_playbacks_control_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c
index aee3d3d..a6e9a09 100644
--- a/res/res_ari_recordings.c
+++ b/res/res_ari_recordings.c
@@ -62,10 +62,9 @@
 static void ast_ari_recordings_list_stored_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_list_stored_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -113,11 +112,10 @@
 static void ast_ari_recordings_get_stored_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_get_stored_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -172,11 +170,10 @@
 static void ast_ari_recordings_delete_stored_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_delete_stored_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -231,11 +228,10 @@
 static void ast_ari_recordings_get_stored_file_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_get_stored_file_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -304,11 +300,10 @@
 static void ast_ari_recordings_copy_stored_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_copy_stored_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -325,21 +320,6 @@
 			args.recording_name = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_recordings_copy_stored_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -389,11 +369,10 @@
 static void ast_ari_recordings_get_live_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_get_live_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -448,11 +427,10 @@
 static void ast_ari_recordings_cancel_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_cancel_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -507,11 +485,10 @@
 static void ast_ari_recordings_stop_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_stop_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -566,11 +543,10 @@
 static void ast_ari_recordings_pause_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_pause_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -626,11 +602,10 @@
 static void ast_ari_recordings_unpause_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_unpause_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -686,11 +661,10 @@
 static void ast_ari_recordings_mute_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_mute_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -746,11 +720,10 @@
 static void ast_ari_recordings_unmute_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_recordings_unmute_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c
index f5a1d41..b7f2e35 100644
--- a/res/res_ari_sounds.c
+++ b/res/res_ari_sounds.c
@@ -79,11 +79,10 @@
 static void ast_ari_sounds_list_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_sounds_list_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -97,21 +96,6 @@
 			args.format = (i->value);
 		} else
 		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
 	}
 	if (ast_ari_sounds_list_parse_body(body, &args)) {
 		ast_ari_response_alloc_failed(response);
@@ -159,11 +143,10 @@
 static void ast_ari_sounds_get_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_sounds_get_args args = {};
 	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
diff --git a/res/res_stasis.c b/res/res_stasis.c
index fac564f..72a85e3 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -67,7 +67,6 @@
 #include "stasis/app.h"
 #include "stasis/control.h"
 #include "stasis/messaging.h"
-#include "stasis/cli.h"
 #include "stasis/stasis_bridge.h"
 #include "asterisk/core_unreal.h"
 #include "asterisk/musiconhold.h"
@@ -177,11 +176,6 @@
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL(start_message_type,
 	.to_json = stasis_start_to_json);
-
-const char *stasis_app_name(const struct stasis_app *app)
-{
-	return app_name(app);
-}
 
 /*! AO2 hash function for \ref app */
 static int app_hash(const void *obj, const int flags)
@@ -958,7 +952,7 @@
 
 	if (app_subscribe_channel(app, chan)) {
 		ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
-			app_name(app), ast_channel_name(chan));
+			stasis_app_name(app), ast_channel_name(chan));
 		return -1;
 	}
 
@@ -972,7 +966,7 @@
 	payload->replace_channel = ao2_bump(replace_channel_snapshot);
 
 	json_blob = ast_json_pack("{s: s, s: o, s: []}",
-		"app", app_name(app),
+		"app", stasis_app_name(app),
 		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
 		"args");
 	if (!json_blob) {
@@ -1042,7 +1036,7 @@
 		return 0;
 	}
 
-	blob = ast_json_pack("{s: s}", "app", app_name(app));
+	blob = ast_json_pack("{s: s}", "app", stasis_app_name(app));
 	if (!blob) {
 		ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
 		return -1;
@@ -1488,10 +1482,6 @@
 		res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
 	}
 
-	if (!res) {
-		ast_log(LOG_WARNING, "Could not find app '%s'\n",
-			app_name ? : "(null)");
-	}
 	return res;
 }
 
@@ -1972,8 +1962,6 @@
 {
 	stasis_app_unregister_event_sources();
 
-	cli_cleanup();
-
 	messaging_cleanup();
 
 	cleanup();
@@ -2129,11 +2117,6 @@
 	}
 
 	if (messaging_init()) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (cli_init()) {
 		unload_module();
 		return AST_MODULE_LOAD_FAILURE;
 	}
diff --git a/res/stasis/app.c b/res/stasis/app.c
index 7fa5cae..12d21bc 100644
--- a/res/stasis/app.c
+++ b/res/stasis/app.c
@@ -43,6 +43,9 @@
 #define CHANNEL_ALL "__AST_CHANNEL_ALL_TOPIC"
 #define ENDPOINT_ALL "__AST_ENDPOINT_ALL_TOPIC"
 
+/*! Global debug flag.  No need for locking */
+int global_debug;
+
 static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, int terminate);
 
 struct stasis_app {
@@ -842,15 +845,64 @@
 	}
 }
 
-void app_set_debug(struct stasis_app *app, int debug)
+void stasis_app_set_debug(struct stasis_app *app, int debug)
 {
 	if (!app) {
 		return;
 	}
 
-	{
-		SCOPED_AO2LOCK(lock, app);
-		app->debug = debug;
+	app->debug = debug;
+}
+
+void stasis_app_set_debug_by_name(const char *app_name, int debug)
+{
+	struct stasis_app *app = stasis_app_get_by_name(app_name);
+
+	if (!app) {
+		return;
+	}
+
+	app->debug = debug;
+	ao2_cleanup(app);
+}
+
+int stasis_app_get_debug(struct stasis_app *app)
+{
+	return (app ? app->debug : 0) || global_debug;
+}
+
+int stasis_app_get_debug_by_name(const char *app_name)
+{
+	RAII_VAR(struct stasis_app *, app, stasis_app_get_by_name(app_name), ao2_cleanup);
+
+	return (app ? app->debug : 0) || global_debug;
+}
+
+void stasis_app_set_global_debug(int debug)
+{
+	global_debug = debug;
+	if (!global_debug) {
+		struct ao2_container *app_names = stasis_app_get_all();
+		struct ao2_iterator it_app_names;
+		char *app_name;
+		struct stasis_app *app;
+
+		if (!app_names || !ao2_container_count(app_names)) {
+			ao2_cleanup(app_names);
+			return;
+		}
+
+		it_app_names = ao2_iterator_init(app_names, 0);
+		while ((app_name = ao2_iterator_next(&it_app_names))) {
+			if ((app = stasis_app_get_by_name(app_name))) {
+				stasis_app_set_debug(app, 0);
+			}
+
+			ao2_cleanup(app_name);
+			ao2_cleanup(app);
+		}
+		ao2_iterator_cleanup(&it_app_names);
+		ao2_cleanup(app_names);
 	}
 }
 
@@ -951,7 +1003,6 @@
 void app_send(struct stasis_app *app, struct ast_json *message)
 {
 	stasis_app_cb handler;
-	int debug;
 	char eid[20];
 	RAII_VAR(void *, data, NULL, ao2_cleanup);
 
@@ -964,20 +1015,12 @@
 	/* Copy off mutable state with lock held */
 	{
 		SCOPED_AO2LOCK(lock, app);
-		debug = app->debug;
 		handler = app->handler;
 		if (app->data) {
 			ao2_ref(app->data, +1);
 			data = app->data;
 		}
 		/* Name is immutable; no need to copy */
-	}
-
-	if (debug) {
-		char *dump = ast_json_dump_string_format(message, AST_JSON_PRETTY);
-		ast_verb(0, "Dispatching message to Stasis app '%s':\n%s\n",
-			app->name, dump);
-		ast_json_free(dump);
 	}
 
 	if (!handler) {
@@ -1052,7 +1095,7 @@
 	app->data = data;
 }
 
-const char *app_name(const struct stasis_app *app)
+const char *stasis_app_name(const struct stasis_app *app)
 {
 	return app->name;
 }
@@ -1069,7 +1112,7 @@
 	return 0;
 }
 
-void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a)
+void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a)
 {
 	struct ao2_iterator *channels;
 	struct ao2_iterator *endpoints;
diff --git a/res/stasis/app.h b/res/stasis/app.h
index 6ed6a29..ac4ac59 100644
--- a/res/stasis/app.h
+++ b/res/stasis/app.h
@@ -109,15 +109,6 @@
 void app_update(struct stasis_app *app, stasis_app_cb handler, void *data);
 
 /*!
- * \brief Return an application's name.
- *
- * \param app Application.
- * \return Name of the application.
- * \return \c NULL is \a app is \c NULL.
- */
-const char *app_name(const struct stasis_app *app);
-
-/*!
  * \brief Send a message to an application.
  *
  * \param app Application.
@@ -136,16 +127,6 @@
  * \return \c NULL on error
  */
 struct ast_json *app_to_json(const struct stasis_app *app);
-
-struct ast_cli_args;
-
-/*!
- * \brief Dump properties of a \c stasis_app to the CLI
- *
- * \param app The application
- * \param a The CLI arguments
- */
-void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a);
 
 /*!
  * \brief Subscribes an application to a channel.
@@ -299,13 +280,5 @@
  * \return non-zero on failure
  */
 int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan);
-
-/*!
- * \brief Enable/disable debugging on an application
- *
- * \param app The app to debug
- * \param debug If non-zero, enable debugging. If zero, disable.
- */
-void app_set_debug(struct stasis_app *app, int debug);
 
 #endif /* _ASTERISK_RES_STASIS_APP_H */
diff --git a/res/stasis/cli.c b/res/stasis/cli.c
deleted file mode 100644
index 797ead8..0000000
--- a/res/stasis/cli.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2016, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis CLI commands.
- *
- * \author Matt Jordan <mjordan at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_REGISTER_FILE()
-
-#include "asterisk/cli.h"
-#include "asterisk/astobj2.h"
-
-#include "cli.h"
-#include "app.h"
-
-
-static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ao2_container *apps;
-	struct ao2_iterator it_apps;
-	char *app;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari show apps";
-		e->usage =
-			"Usage: ari show apps\n"
-			"       Lists all registered applications.\n"
-			;
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	default:
-		break;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	apps = stasis_app_get_all();
-	if (!apps) {
-		ast_cli(a->fd, "Unable to retrieve registered applications!\n");
-		return CLI_FAILURE;
-	}
-
-	ast_cli(a->fd, "Application Name         \n");
-	ast_cli(a->fd, "=========================\n");
-	it_apps = ao2_iterator_init(apps, 0);
-	while ((app = ao2_iterator_next(&it_apps))) {
-		ast_cli(a->fd, "%-25.25s\n", app);
-		ao2_ref(app, -1);
-	}
-
-	ao2_iterator_destroy(&it_apps);
-	ao2_ref(apps, -1);
-
-	return CLI_SUCCESS;
-}
-
-struct app_complete {
-	/*! Nth app to search for */
-	int state;
-	/*! Which app currently on */
-	int which;
-};
-
-static int complete_ari_app_search(void *obj, void *arg, void *data, int flags)
-{
-	struct app_complete *search = data;
-
-	if (++search->which > search->state) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static char *complete_ari_app(struct ast_cli_args *a)
-{
-	RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup);
-	RAII_VAR(char *, app, NULL, ao2_cleanup);
-
-	struct app_complete search = {
-		.state = a->n,
-	};
-
-	if (!apps) {
-		ast_cli(a->fd, "Error getting ARI applications\n");
-		return CLI_FAILURE;
-	}
-
-	app = ao2_callback_data(apps,
-		ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
-		complete_ari_app_search, (char*)a->word, &search);
-
-	return app ? ast_strdup(app) : NULL;
-}
-
-static char *complete_ari_show_app(struct ast_cli_args *a)
-{
-	if (a->pos == 3) {
-		return complete_ari_app(a);
-	}
-
-	return NULL;
-}
-
-static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	void *app;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari show app";
-		e->usage =
-			"Usage: ari show app <application>\n"
-			"       Provide detailed information about a registered application.\n"
-			;
-		return NULL;
-	case CLI_GENERATE:
-		return complete_ari_show_app(a);
-	default:
-		break;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	app = stasis_app_get_by_name(a->argv[3]);
-	if (!app) {
-		return CLI_FAILURE;
-	}
-
-	app_to_cli(app, a);
-
-	ao2_ref(app, -1);
-
-	return CLI_SUCCESS;
-}
-
-static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	void *app;
-	int debug;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari set debug";
-		e->usage =
-			"Usage: ari set debug <application> <on|off>\n"
-			"       Enable or disable debugging on a specific application.\n"
-			;
-		return NULL;
-	case CLI_GENERATE:
-		return complete_ari_show_app(a);
-	default:
-		break;
-	}
-
-	if (a->argc != 5) {
-		return CLI_SHOWUSAGE;
-	}
-
-	app = stasis_app_get_by_name(a->argv[3]);
-	if (!app) {
-		return CLI_FAILURE;
-	}
-
-	debug = !strcmp(a->argv[4], "on");
-	app_set_debug(app, debug);
-	ast_cli(a->fd, "Debugging on '%s' %s\n",
-		app_name(app),
-		debug ? "enabled" : "disabled");
-
-	ao2_ref(app, -1);
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_ari[] = {
-	AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"),
-	AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"),
-	AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"),
-};
-
-
-int cli_init(void)
-{
-	return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
-}
-
-void cli_cleanup(void)
-{
-	ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
-}
diff --git a/res/stasis/cli.h b/res/stasis/cli.h
deleted file mode 100644
index 49235c7..0000000
--- a/res/stasis/cli.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2016, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_CLI_H
-#define _ASTERISK_RES_STASIS_CLI_H
-
-/*! \file
- *
- * \brief Internal API for Stasis application CLI commands
- *
- * \author Matt Jordan <mjordan at digium.com>
- * \since 13.13.0
- */
-
-/*!
- * \brief Initialize the CLI commands
- *
- * \retval 0 on success
- * \retval non-zero on error
- */
-int cli_init(void);
-
-/*!
- * \brief Cleanup the CLI commands
- */
-void cli_cleanup(void);
-
-#endif /* _ASTERISK_RES_STASIS_CLI_H */
diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c
index aa21ec2..d871c45 100644
--- a/res/stasis/stasis_bridge.c
+++ b/res/stasis/stasis_bridge.c
@@ -157,13 +157,13 @@
 	}
 	to_be_replaced = ast_channel_snapshot_get_latest(ast_channel_uniqueid(swap->chan));
 
-	ast_debug(3, "Copying stasis app name %s from %s to %s\n", app_name(control_app(swap_control)),
+	ast_debug(3, "Copying stasis app name %s from %s to %s\n", stasis_app_name(control_app(swap_control)),
 		ast_channel_name(swap->chan), ast_channel_name(bridge_channel->chan));
 
 	ast_channel_lock(bridge_channel->chan);
 
 	/* copy the app name from the swap channel */
-	app_set_replace_channel_app(bridge_channel->chan, app_name(control_app(swap_control)));
+	app_set_replace_channel_app(bridge_channel->chan, stasis_app_name(control_app(swap_control)));
 
 	/* set the replace channel snapshot */
 	app_set_replace_channel_snapshot(bridge_channel->chan, to_be_replaced);
diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache
index 247c121..d156ab7 100644
--- a/rest-api-templates/param_parsing.mustache
+++ b/rest-api-templates/param_parsing.mustache
@@ -85,21 +85,6 @@
 {{/has_path_parameters}}
 {{^is_websocket}}
 {{#parse_body}}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
 {{#body_parameter}}
 	args.{{c_name}} = body;
 {{/body_parameter}}
diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache
index c4e6f3d..6e96b58 100644
--- a/rest-api-templates/res_ari_resource.c.mustache
+++ b/rest-api-templates/res_ari_resource.c.mustache
@@ -78,13 +78,12 @@
 static void ast_ari_{{c_name}}_{{c_nickname}}_cb(
 	struct ast_tcptls_session_instance *ser,
 	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
+	struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
 {
 	struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
 {{#has_parameters}}
 	struct ast_variable *i;
 {{/has_parameters}}
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
diff --git a/tests/test_ari.c b/tests/test_ari.c
index da889ec..a500080 100644
--- a/tests/test_ari.c
+++ b/tests/test_ari.c
@@ -63,6 +63,7 @@
 		    struct ast_variable *get_params,
 		    struct ast_variable *path_vars,
 		    struct ast_variable *headers,
+		    struct ast_json *body,
 		    struct ast_ari_response *response)
 {
 	struct ast_json *message = ast_json_pack("{s: s, s: {}, s: {}, s: {}}",
@@ -100,9 +101,10 @@
 		struct ast_variable *get_params,			\
 		struct ast_variable *path_vars,				\
 		struct ast_variable *headers,				\
+		struct ast_json *body,						\
 		struct ast_ari_response *response)			\
 	{								\
-		handler(#name, response_code, get_params, path_vars, headers, response); \
+		handler(#name, response_code, get_params, path_vars, headers, body, response); \
 	}
 
 HANDLER(bang_get, 200)
@@ -345,7 +347,8 @@
 				 "head2", "head-two",
 				 "path_vars");
 
-	ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers, response);
+	ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers,
+		ast_json_null(), response);
 
 	ast_test_validate(test, 1 == invocation_count);
 	ast_test_validate(test, 200 == response->response_code);
@@ -382,7 +385,8 @@
 				 "path_vars",
 				 "bam", "foshizzle");
 
-	ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers, response);
+	ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers,
+		ast_json_null(), response);
 
 	ast_test_validate(test, 1 == invocation_count);
 	ast_test_validate(test, 200 == response->response_code);
@@ -419,7 +423,8 @@
 				 "path_vars",
 				 "bam", "foshizzle");
 
-	ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers, response);
+	ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers,
+		ast_json_null(), response);
 
 	ast_test_validate(test, 1 == invocation_count);
 	ast_test_validate(test, 204 == response->response_code);
@@ -469,7 +474,8 @@
 				 "head2", "head-two",
 				 "path_vars");
 
-	ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers, response);
+	ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers,
+		ast_json_null(), response);
 
 	ast_test_validate(test, 1 == invocation_count);
 	ast_test_validate(test, 200 == response->response_code);
@@ -498,7 +504,8 @@
 
 	fixture = setup_invocation_test();
 	response = response_alloc();
-	ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers, response);
+	ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers,
+		ast_json_null(), response);
 
 	ast_test_validate(test, 0 == invocation_count);
 	ast_test_validate(test, 405 == response->response_code);
@@ -526,7 +533,8 @@
 
 	fixture = setup_invocation_test();
 	response = response_alloc();
-	ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers, response);
+	ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers,
+		ast_json_null(), response);
 
 	ast_test_validate(test, 0 == invocation_count);
 	ast_test_validate(test, 404 == response->response_code);

-- 
To view, visit https://gerrit.asterisk.org/4748
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ief936f747ce47f1fb14035fbe61152cf766406bf
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: 14
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>



More information about the asterisk-commits mailing list