mirror of
https://github.com/asterisk/asterisk.git
synced 2026-07-28 00:10:25 -07:00
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
This commit is contained in:
@@ -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;
|
||||
|
||||
+29
-5
@@ -585,17 +585,34 @@ 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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* If the channel is no longer in \c app_stasis, this function does nothing.
|
||||
*
|
||||
* \param handler Handler for \c app_stasis
|
||||
* \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.
|
||||
*/
|
||||
void stasis_app_control_continue(struct stasis_app_control *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 res_stasis, this function does nothing.
|
||||
*
|
||||
* \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
|
||||
*/
|
||||
struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot);
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user