[asterisk-commits] dlee: branch dlee/stasis-http r379121 - /team/dlee/stasis-http/res/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jan 15 13:35:26 CST 2013
Author: dlee
Date: Tue Jan 15 13:35:23 2013
New Revision: 379121
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=379121
Log:
stasis_http.c cleanups
Modified:
team/dlee/stasis-http/res/res_stasis_http.c
Modified: team/dlee/stasis-http/res/res_stasis_http.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/res/res_stasis_http.c?view=diff&rev=379121&r1=379120&r2=379121
==============================================================================
--- team/dlee/stasis-http/res/res_stasis_http.c (original)
+++ team/dlee/stasis-http/res/res_stasis_http.c Tue Jan 15 13:35:23 2013
@@ -47,13 +47,30 @@
/*! WebSocket protocol for Stasis */
static const char * const ws_protocol = "stasis";
-static void response_error(struct stasis_http_response *response, const char *message, int response_code, const char *response_text)
+/*!
+ * \internal
+ * \brief Fill in an error \a stasis_http_response.
+ * \param response Response to fill in.
+ * \param message Error message.
+ * \param response_code HTTP response code.
+ * \param response_text Text corresponding to the HTTP response code.
+ */
+static void response_error(struct stasis_http_response *response,
+ const char *message,
+ int response_code,
+ const char *response_text)
{
response->message = ast_json_pack("{s: s}", "message", message);
response->response_code = response_code;
response->response_text = response_text;
}
+/*!
+ * \internal
+ * \brief Fill in an OK \a stasis_http_response.
+ * \param response Response to fill in.
+ * \param message JSON response.
+ */
static void response_ok(struct stasis_http_response *response, struct ast_json *message)
{
response->message = message;
@@ -61,13 +78,22 @@
response->response_text = "OK";
}
-/*! Stasis RESTful invocation handler */
+/*!
+ * \internal
+ * \brief Stasis RESTful invocation handler.
+ * \param uri HTTP URI.
+ * \param method HTTP method.
+ * \param get_params HTTP \c GET parameters.
+ * \param headers HTTP headers.
+ * \param[out] response RESTful HTTP response.
+ */
static void stasis_http_invoke(const char *uri,
enum ast_http_method method,
struct ast_variable *get_params,
struct ast_variable *headers,
struct stasis_http_response *response)
{
+ RAII_VAR(char *, response_text, NULL, ast_free);
struct stasis_rest_handlers *handler = stasis_root_handler();
struct ast_variable *path_vars = NULL;
char *path = ast_strdupa(uri);
@@ -124,33 +150,46 @@
}
}
-static void stasis_http_api(const char *uri, struct ast_variable *headers, struct stasis_http_response *response) {
- char *file;
- struct ast_str *path = ast_str_alloca(512);
- char *api_abs_path = NULL;
- char *file_abs_path = NULL;
+/*!
+ * \internal
+ * \brief Service function for API declarations.
+ * \param uri Requested URI.
+ * \param headers HTTP headers.
+ * \param[out] response RESTful HTTP response.
+ */
+static void stasis_http_get_api(const char *uri, struct ast_variable *headers, struct stasis_http_response *response) {
+ RAII_VAR(struct ast_str *, absolute_path_builder, ast_str_create(80), ast_free);
+ RAII_VAR(char *, absolute_api_dirname, NULL, free);
+ RAII_VAR(char *, absolute_filename, NULL, free);
+ RAII_VAR(struct ast_json *, obj, NULL, ast_json_unref);
+ char *relative_filename = NULL;
struct ast_variable *host = NULL;
- struct ast_json *obj;
- struct ast_json_error error;
+ struct ast_json_error error = {};
+
+ if (absolute_path_builder == NULL) {
+ ast_log(LOG_ERROR, "Allocation failed.");
+ response_error(response, "Allocation failed", 500, "Internal Server Error");
+ return;
+ }
+
+ /* absolute path to the rest-api directory */
+ ast_str_append(&absolute_path_builder, 0, "%s", ast_config_AST_DATA_DIR);
+ ast_str_append(&absolute_path_builder, 0, "/rest-api/");
+ absolute_api_dirname = realpath(ast_str_buffer(absolute_path_builder), NULL);
+ if (absolute_api_dirname == NULL) {
+ ast_log(LOG_ERROR, "Error determining real directory for rest-api\n");
+ response_error(response, "Cannot find rest-api directory", 500, "Internal Server Error");
+ return;
+ }
/* Get filename from URI by dropping the first path segment */
- file = ast_strdupa(uri);
- strsep(&file, "/");
-
- /* absolute path to the rest-api directory */
- ast_str_append(&path, 1024, "%s", ast_config_AST_DATA_DIR);
- ast_str_append(&path, 1024, "/rest-api/");
- api_abs_path = realpath(ast_str_buffer(path), NULL);
- if (api_abs_path == NULL) {
- ast_log(LOG_ERROR, "Error determining real path for rest-api\n");
- response_error(response, "Cannot find rest-api path", 500, "Internal Server Error");
- goto done;
- }
+ relative_filename = ast_strdupa(uri);
+ strsep(&relative_filename, "/");
/* absolute path to the requested file */
- ast_str_append(&path, 1024, "%s", file);
- file_abs_path = realpath(ast_str_buffer(path), NULL);
- if (file_abs_path == NULL) {
+ ast_str_append(&absolute_path_builder, 0, "%s", relative_filename);
+ absolute_filename = realpath(ast_str_buffer(absolute_path_builder), NULL);
+ if (absolute_filename == NULL) {
switch (errno) {
case ENAMETOOLONG:
case ENOENT:
@@ -162,21 +201,21 @@
break;
default:
ast_log(LOG_ERROR, "Error determining real path for uri '%s': %s\n", uri, strerror(errno));
- response_error(response, "Cannot determine path", 500, "Internal Server Error");
+ response_error(response, "Cannot find file", 500, "Internal Server Error");
break;
}
- goto done;
- }
-
- if (!ast_begins_with(file_abs_path, api_abs_path)) {
+ return;
+ }
+
+ if (!ast_begins_with(absolute_filename, absolute_api_dirname)) {
/* HACKERZ! */
- ast_log(LOG_ERROR, "Invalid attempt to access '%s' (not in %s)\n", file_abs_path, api_abs_path);
+ ast_log(LOG_ERROR, "Invalid attempt to access '%s' (not in %s)\n", absolute_filename, absolute_api_dirname);
response_error(response, "Resource not found", 404, "Not Found");
goto done;
}
/* Load resource object from file */
- obj = ast_json_load_new_file(file_abs_path, &error);
+ obj = ast_json_load_new_file(absolute_filename, &error);
if (obj == NULL) {
response_error(response, "Yikes! Cannot parse resource", 500, "Internal Server Error");
goto done;
@@ -198,13 +237,22 @@
}
response_ok(response, obj);
-
-done:
- free(file_abs_path);
- free(api_abs_path);
-}
-
-/*! \brief Stasis HTTP handler */
+}
+
+/*!
+ * \internal
+ * \brief Stasis HTTP handler.
+ *
+ * This handler takes the HTTP request and turns it into the appropriate
+ * RESTful request (conversion to JSON, routing, etc.)
+ *
+ * \param ser TCP session.
+ * \param urih URI handler.
+ * \param uri URI requested.
+ * \param method HTTP method.
+ * \param get_params HTTP \c GET params.
+ * \param headers HTTP headers.
+ */
static int stasis_http_callback(struct ast_tcptls_session_instance *ser,
const struct ast_http_uri *urih,
const char *uri,
@@ -212,14 +260,11 @@
struct ast_variable *get_params,
struct ast_variable *headers)
{
- struct ast_str *http_headers = ast_str_create(40);
- struct ast_str *out = ast_str_create(256);
+ RAII_VAR(struct ast_str *, http_headers, ast_str_create(40), ast_free);
+ RAII_VAR(struct ast_str *, response_text, ast_str_create(256), ast_free);
struct stasis_http_response response = {};
- char *response_text;
if (!http_headers || !out) {
- ast_free(http_headers);
- ast_free(out);
return -1;
}
@@ -230,7 +275,7 @@
response.response_code = 405;
response.response_text = "Method Not Allowed";
} else {
- stasis_http_api(uri, headers, &response);
+ stasis_http_get_api(uri, headers, &response);
}
} else {
/* Other RESTful resources */
@@ -241,18 +286,17 @@
ast_assert(response.response_code > 0);
ast_str_set(&http_headers, 0, "Content-type: application/json\r\nAccess-Control-Allow-Origin: *\r\n");
- response_text = ast_json_dump_string(response.message);
- ast_str_set(&out, 0, "%s\n", response_text);
- free(response_text);
+ response_text = ast_json_dump_str(response.message);
+
+ ast_http_send(ser, method, response.response_code, response.response_text, http_headers, response_text, 0, 0);
+
ast_json_unref(response.message);
-
- ast_http_send(ser, AST_HTTP_UNKNOWN, response.response_code, response.response_text, http_headers, out, 0, 0);
return 0;
}
static struct ast_http_uri http_uri = {
.callback = stasis_http_callback,
- .description = "Asterisk Stasis",
+ .description = "Asterisk RESTful API",
.uri = "stasis",
.has_subtree = 1,
@@ -260,22 +304,32 @@
.key = __FILE__,
};
+/*!
+ * \internal
+ * \brief Helper to write a JSON object to a WebSocket.
+ * \param session WebSocket session.
+ * \param message JSON message.
+ * \return 0 on success.
+ * \return -1 on error.
+ */
static int ast_websocket_write_json(struct ast_websocket *session, struct ast_json *message) {
- char *str = ast_json_dump_string(message);
- int ret;
+ RAII_VAR(char *str, ast_json_dump_string(message), ast_free);
if (str == NULL) {
ast_log(LOG_ERROR, "Failed to encode JSON object\n");
return -1;
}
- ret = ast_websocket_write(session, AST_WEBSOCKET_OPCODE_TEXT, str, strlen(str));
-
- free(str);
- return ret;
-}
-
-/*! \brief Stasis WebSocket connection handler */
+ return ast_websocket_write(session, AST_WEBSOCKET_OPCODE_TEXT, str, strlen(str));
+}
+
+/*!
+ * \internal
+ * \brief Stasis WebSocket connection handler
+ * \param session WebSocket session.
+ * \param parameters HTTP \c GET parameters.
+ * \param headers HTTP headers.
+ */
static void stasis_websocket_callback(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
{
int res;
@@ -299,19 +353,24 @@
}
if (opcode == AST_WEBSOCKET_OPCODE_TEXT) {
+ RAII_VAR(struct ast_json *, req, NULL, ast_json_unref);
struct ast_json_error err = {};
- char *text = ast_strndup(payload, payload_len); /* Null terminate the string */
- struct ast_json *req = ast_json_load_string(text, &err);
- ast_free(text);
+
+ req = ast_json_load_buf(payload, payload_len, &err);
+
if (req == NULL) {
- struct ast_json *resp = ast_json_object_create();
- ast_json_object_set(resp, "error", ast_json_stringf("Error parsing message: %s", err.text));
- ast_json_object_set(resp, "line", ast_json_integer_create(err.line));
- ast_json_object_set(resp, "column", ast_json_integer_create(err.column));
- ast_json_object_set(resp, "message", ast_json_string_create(text));
- ast_websocket_write_json(session, resp);
- ast_json_unref(resp);
- continue;
+ /* Parse error */
+ RAII_VAR(struct ast_json *, resp, NULL, ast_json_unref);
+ resp = ast_json_pack("{ s: o, s: i, s: i, s: s }",
+ "error", ast_json_stringf("Error parsing message: %s", err.text),
+ "line", err.line,
+ "column", err.column,
+ "message", err.text);
+ if (resp) {
+ ast_websocket_write_json(session, resp);
+ } else {
+ ast_log(LOG_ERROR, "Error sending error message. That's just messed up.\n");
+ }
}
ast_log(LOG_ERROR, "TODO\n");
ast_json_unref(req);
More information about the asterisk-commits
mailing list