summaryrefslogtreecommitdiff
path: root/include/asterisk
diff options
context:
space:
mode:
authorDavid M. Lee <dlee@digium.com>2013-04-22 14:58:53 +0000
committerDavid M. Lee <dlee@digium.com>2013-04-22 14:58:53 +0000
commit1c21b8575bfd70b98b1102fd3dd09fc0bc335e14 (patch)
tree9a6ef6074e545ad2768bc1994e1a233fc1443729 /include/asterisk
parent1871017cc6bd2e2ce7c638eeb6813e982377a521 (diff)
This patch adds a RESTful HTTP interface to Asterisk.
The API itself is documented using Swagger, a lightweight mechanism for documenting RESTful API's using JSON. This allows us to use swagger-ui to provide executable documentation for the API, generate client bindings in different languages, and generate a lot of the boilerplate code for implementing the RESTful bindings. The API docs live in the rest-api/ directory. The RESTful bindings are generated from the Swagger API docs using a set of Mustache templates. The code generator is written in Python, and uses Pystache. Pystache has no dependencies, and be installed easily using pip. Code generation code lives in rest-api-templates/. The generated code reduces a lot of boilerplate when it comes to handling HTTP requests. It also helps us have greater consistency in the REST API. (closes issue ASTERISK-20891) Review: https://reviewboard.asterisk.org/r/2376/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@386232 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'include/asterisk')
-rw-r--r--include/asterisk/http.h5
-rw-r--r--include/asterisk/json.h34
-rw-r--r--include/asterisk/stasis_app.h44
-rw-r--r--include/asterisk/stasis_http.h171
-rw-r--r--include/asterisk/strings.h42
5 files changed, 282 insertions, 14 deletions
diff --git a/include/asterisk/http.h b/include/asterisk/http.h
index 3400240a1..db424d3d3 100644
--- a/include/asterisk/http.h
+++ b/include/asterisk/http.h
@@ -58,7 +58,10 @@ enum ast_http_method {
AST_HTTP_GET = 0,
AST_HTTP_POST,
AST_HTTP_HEAD,
- AST_HTTP_PUT, /*!< Not supported in Asterisk */
+ AST_HTTP_PUT,
+ AST_HTTP_DELETE,
+ AST_HTTP_OPTIONS,
+ AST_HTTP_MAX_METHOD, /*!< Last entry in ast_http_method enum */
};
struct ast_http_uri;
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index 62e21293b..d06416f58 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -586,16 +586,33 @@ int ast_json_object_iter_set(struct ast_json *object, struct ast_json_iter *iter
/*!@{*/
/*!
+ * \brief Encoding format type.
+ * \since 12.0.0
+ */
+enum ast_json_encoding_format
+{
+ /*! Compact format, low human readability */
+ AST_JSON_COMPACT,
+ /*! Formatted for human readability */
+ AST_JSON_PRETTY,
+};
+
+#define ast_json_dump_string(root) ast_json_dump_string_format(root, AST_JSON_COMPACT)
+
+/*!
* \brief Encode a JSON value to a string.
* \since 12.0.0
*
* Returned string must be freed by calling ast_free().
*
- * \param JSON value.
+ * \param root JSON value.
+ * \param format encoding format type.
* \return String encoding of \a root.
* \return \c NULL on error.
*/
-char *ast_json_dump_string(struct ast_json *root);
+char *ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format);
+
+#define ast_json_dump_str(root, dst) ast_json_dump_str_format(root, dst, AST_JSON_COMPACT)
/*!
* \brief Encode a JSON value to an \ref ast_str.
@@ -605,10 +622,13 @@ char *ast_json_dump_string(struct ast_json *root);
*
* \param root JSON value.
* \param dst \ref ast_str to store JSON encoding.
+ * \param format encoding format type.
* \return 0 on success.
* \return -1 on error. The contents of \a dst are undefined.
*/
-int ast_json_dump_str(struct ast_json *root, struct ast_str **dst);
+int ast_json_dump_str_format(struct ast_json *root, struct ast_str **dst, enum ast_json_encoding_format format);
+
+#define ast_json_dump_file(root, output) ast_json_dump_file_format(root, output, AST_JSON_COMPACT)
/*!
* \brief Encode a JSON value to a \c FILE.
@@ -616,10 +636,13 @@ int ast_json_dump_str(struct ast_json *root, struct ast_str **dst);
*
* \param root JSON value.
* \param output File to write JSON encoding to.
+ * \param format encoding format type.
* \return 0 on success.
* \return -1 on error. The contents of \a output are undefined.
*/
-int ast_json_dump_file(struct ast_json *root, FILE *output);
+int ast_json_dump_file_format(struct ast_json *root, FILE *output, enum ast_json_encoding_format format);
+
+#define ast_json_dump_new_file(root, path) ast_json_dump_new_file_format(root, path, AST_JSON_COMPACT)
/*!
* \brief Encode a JSON value to a file at the given location.
@@ -627,10 +650,11 @@ int ast_json_dump_file(struct ast_json *root, FILE *output);
*
* \param root JSON value.
* \param path Path to file to write JSON encoding to.
+ * \param format encoding format type.
* \return 0 on success.
* \return -1 on error. The contents of \a output are undefined.
*/
-int ast_json_dump_new_file(struct ast_json *root, const char *path);
+int ast_json_dump_new_file_format(struct ast_json *root, const char *path, enum ast_json_encoding_format format);
#define AST_JSON_ERROR_TEXT_LENGTH 160
#define AST_JSON_ERROR_SOURCE_LENGTH 80
diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h
index caec19bbc..a789e4012 100644
--- a/include/asterisk/stasis_app.h
+++ b/include/asterisk/stasis_app.h
@@ -66,7 +66,7 @@ struct ast_channel_snapshot;
* \param argv Arguments for the application.
*/
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
- char *argv[]);
+ char *argv[]);
/*! @} */
@@ -126,22 +126,50 @@ int stasis_app_send(const char *app_name, struct ast_json *message);
struct stasis_app_control;
/*!
- * \brief Returns the handler for the given channel
+ * \brief Returns the handler for the given channel.
* \param chan Channel to handle.
- * \return NULL channel not in Stasis application
- * \return Pointer to stasis handler.
+ * \return NULL channel not in Stasis application.
+ * \return Pointer to \c res_stasis handler.
*/
struct stasis_app_control *stasis_app_control_find_by_channel(
const struct ast_channel *chan);
/*!
- * \brief Exit \c app_stasis and continue execution in the dialplan.
+ * \brief Returns the handler for the channel with the given id.
+ * \param channel_id Uniqueid of the channel.
+ * \return NULL channel not in Stasis application, or channel does not exist.
+ * \return Pointer to \c res_stasis handler.
+ */
+struct stasis_app_control *stasis_app_control_find_by_channel_id(
+ const char *channel_id);
+
+/*!
+ * \brief Exit \c res_stasis and continue execution in the dialplan.
*
- * If the channel is no longer in \c app_stasis, this function does nothing.
+ * If the channel is no longer in \c res_stasis, this function does nothing.
*
- * \param handler Handler for \c app_stasis
+ * \param control Control for \c res_stasis
+ */
+void stasis_app_control_continue(struct stasis_app_control *control);
+
+/*!
+ * \brief Answer the channel associated with this control.
+ * \param control Control for \c res_stasis.
+ * \return 0 for success.
+ * \return -1 for error.
+ */
+int stasis_app_control_answer(struct stasis_app_control *control);
+
+/*! @} */
+
+/*! @{ */
+
+/*!
+ * \brief Build a JSON object from a \ref ast_channel_snapshot.
+ * \return JSON object representing channel snapshot.
+ * \return \c NULL on error
*/
-void stasis_app_control_continue(struct stasis_app_control *handler);
+struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot);
/*! @} */
diff --git a/include/asterisk/stasis_http.h b/include/asterisk/stasis_http.h
new file mode 100644
index 000000000..cc0ceeee4
--- /dev/null
+++ b/include/asterisk/stasis_http.h
@@ -0,0 +1,171 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@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_STASIS_HTTP_H
+#define _ASTERISK_STASIS_HTTP_H
+
+/*! \file
+ *
+ * \brief Stasis RESTful API hooks.
+ *
+ * This header file is used mostly as glue code between generated declarations
+ * and res_stasis_http.c.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk/http.h"
+#include "asterisk/json.h"
+#include "asterisk/http_websocket.h"
+
+struct stasis_http_response;
+
+/*!
+ * \brief Callback type for RESTful method handlers.
+ * \param get_params GET parameters from the HTTP request.
+ * \param path_vars Path variables from any wildcard path segments.
+ * \param headers HTTP headers from the HTTP requiest.
+ * \param[out] response The RESTful response.
+ */
+typedef void (*stasis_rest_callback)(struct ast_variable *get_params,
+ struct ast_variable *path_vars,
+ struct ast_variable *headers,
+ struct stasis_http_response *response);
+
+/*!
+ * \brief Handler for a single RESTful path segment.
+ */
+struct stasis_rest_handlers {
+ /*! Path segement to handle */
+ const char *path_segment;
+ /*! If true (non-zero), path_segment is a wildcard, and will match all values.
+ *
+ * Value of the segement will be passed into the \a path_vars parameter of the callback.
+ */
+ int is_wildcard;
+ /*! Callbacks for all handled HTTP methods. */
+ stasis_rest_callback callbacks[AST_HTTP_MAX_METHOD];
+ /*! Number of children in the children array */
+ size_t num_children;
+ /*! Handlers for sub-paths */
+ struct stasis_rest_handlers *children[];
+};
+
+/*!
+ * Response type for RESTful requests
+ */
+struct stasis_http_response {
+ /*! Response message */
+ struct ast_json *message;
+ /*! \r\n seperated response headers */
+ struct ast_str *headers;
+ /*! HTTP response code.
+ * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html */
+ int response_code;
+ /*! Corresponding text for the response code */
+ const char *response_text; // Shouldn't http.c handle this?
+};
+
+/*!
+ * Add a resource for REST handling.
+ * \param handler Handler to add.
+ * \return 0 on success.
+ * \return non-zero on failure.
+ */
+int stasis_http_add_handler(struct stasis_rest_handlers *handler);
+
+/*!
+ * Remove a resource for REST handling.
+ * \param handler Handler to add.
+ * \return 0 on success.
+ * \return non-zero on failure.
+ */
+int stasis_http_remove_handler(struct stasis_rest_handlers *handler);
+
+/*!
+ * \internal
+ * \brief Stasis RESTful invocation handler.
+ *
+ * Only call from res_stasis_http and test_stasis_http. Only public to allow
+ * for unit testing.
+ *
+ * \param uri HTTP URI, relative to the API path.
+ * \param method HTTP method.
+ * \param get_params HTTP \c GET parameters.
+ * \param headers HTTP headers.
+ * \param[out] response RESTful HTTP response.
+ */
+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);
+
+/*!
+ * \internal
+ * \brief Service function for API declarations.
+ *
+ * Only call from res_stasis_http and test_stasis_http. Only public to allow
+ * for unit testing.
+ *
+ * \param uri Requested URI, relative to the docs path.
+ * \param headers HTTP headers.
+ * \param[out] response RESTful HTTP response.
+ */
+void stasis_http_get_docs(const char *uri, struct ast_variable *headers, struct stasis_http_response *response);
+
+/*!
+ * \internal
+ * \brief Stasis WebSocket connection handler
+ * \param session WebSocket session.
+ * \param parameters HTTP \c GET parameters.
+ * \param headers HTTP headers.
+ */
+void stasis_websocket_callback(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers);
+
+/*!
+ * \brief Fill in an error \a stasis_http_response.
+ * \param response Response to fill in.
+ * \param response_code HTTP response code.
+ * \param response_text Text corresponding to the HTTP response code.
+ * \param message_fmt Error message format string.
+ */
+void stasis_http_response_error(struct stasis_http_response *response,
+ int response_code,
+ const char *response_text,
+ const char *message_fmt, ...)
+__attribute__((format(printf, 4, 5)));
+
+/*!
+ * \brief Fill in an \c OK (200) \a stasis_http_response.
+ * \param response Response to fill in.
+ * \param message JSON response. This reference is stolen, so just \ref
+ * ast_json_incref if you need to keep a reference to it.
+ */
+void stasis_http_response_ok(struct stasis_http_response *response,
+ struct ast_json *message);
+
+/*!
+ * \brief Fill in a <tt>No Content</tt> (204) \a stasis_http_response.
+ */
+void stasis_http_response_no_content(struct stasis_http_response *response);
+
+/*!
+ * \brief Fill in \a response with a 500 message for allocation failures.
+ * \param response Response to fill in.
+ */
+void stasis_http_response_alloc_failed(struct stasis_http_response *response);
+
+#endif /* _ASTERISK_STASIS_HTTP_H */
diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h
index d16e9f7bd..967eb82a0 100644
--- a/include/asterisk/strings.h
+++ b/include/asterisk/strings.h
@@ -82,6 +82,48 @@ static force_inline int attribute_pure ast_strlen_zero(const char *s)
*/
#define S_COR(a, b, c) ({typeof(&((b)[0])) __x = (b); (a) && !ast_strlen_zero(__x) ? (__x) : (c);})
+/*
+ \brief Checks whether a string begins with another.
+ \since 12.0.0
+ \param str String to check.
+ \param prefix Prefix to look for.
+ \param 1 if \a str begins with \a prefix, 0 otherwise.
+ */
+static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
+{
+ ast_assert(str != NULL);
+ ast_assert(prefix != NULL);
+ while (*str == *prefix && *prefix != '\0') {
+ ++str;
+ ++prefix;
+ }
+ return *prefix == '\0';
+}
+
+/*
+ \brief Checks whether a string ends with another.
+ \since 12.0.0
+ \param str String to check.
+ \param suffix Suffix to look for.
+ \param 1 if \a str ends with \a suffix, 0 otherwise.
+ */
+static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
+{
+ size_t str_len;
+ size_t suffix_len;
+
+ ast_assert(str != NULL);
+ ast_assert(suffix != NULL);
+ str_len = strlen(str);
+ suffix_len = strlen(suffix);
+
+ if (suffix_len > str_len) {
+ return 0;
+ }
+
+ return strcmp(str + str_len - suffix_len, suffix) == 0;
+}
+
/*!
* \brief return Yes or No depending on the argument.
*