[Asterisk-code-review] res_http_media_cache: Introduce options and customize (asterisk[master])
Joshua Colp
asteriskteam at digium.com
Mon Mar 6 12:16:25 CST 2023
Joshua Colp has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/19953 )
Change subject: res_http_media_cache: Introduce options and customize
......................................................................
res_http_media_cache: Introduce options and customize
Make the existing CURL parameters configurable and allow
to specify the usable protocols, proxy and DNS timeout.
ASTERISK-30340
Change-Id: I2eb02ef44190e026716720419bcbdbcc8125777b
---
A configs/samples/res_http_media_cache.conf.sample
A doc/CHANGES-staging/res_http_media_cache.txt
M res/res_http_media_cache.c
3 files changed, 348 insertions(+), 4 deletions(-)
Approvals:
Joshua Colp: Looks good to me, but someone else must approve; Approved for Submit
George Joseph: Looks good to me, approved
diff --git a/configs/samples/res_http_media_cache.conf.sample b/configs/samples/res_http_media_cache.conf.sample
new file mode 100644
index 0000000..925156b
--- /dev/null
+++ b/configs/samples/res_http_media_cache.conf.sample
@@ -0,0 +1,69 @@
+;
+; Sample configuration for res_http_media_cache
+;
+; res_http_media_cache is the HTTP backend for the core media cache. The
+; following options can be used to tune the behavior of the implementation
+; or left as default.
+;
+; See the module's and cURL's documentation for the exact meaning of these
+; options.
+
+
+[general]
+; Maximum time in seconds the transfer is allowed to complete in.
+;
+; See https://curl.se/libcurl/c/CURLOPT_TIMEOUT.html for details.
+;
+;timeout_secs = 180
+
+
+; The HTTP User-Agent to use for requests.
+;
+; See https://curl.se/libcurl/c/CURLOPT_USERAGENT.html for details.
+;
+;user_agent = asterisk-libcurl-agent/1.0
+
+
+; Follow HTTP 3xx redirects on requests. This can be combined with the
+; max_redirects option to limit the number of times a redirect will be
+; followed per request.
+;
+; See https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html for details.
+;
+;follow_location = false
+
+
+; The maximum number of redirects to follow.
+;
+; See https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html for details.
+;
+;max_redirects = 8
+
+; The HTTP/HTTPS proxy to use for requests. Leave unspecified to not use
+; a proxy. This can be a URL with scheme, host and port.
+;
+; See https://curl.se/libcurl/c/CURLOPT_PROXY.html for details.
+;
+;proxy = https://localhost:1234
+
+
+; The life-time for DNS cache entries.
+;
+; See https://curl.se/libcurl/c/CURLOPT_DNS_CACHE_TIMEOUT.html for details.
+;
+;dns_cache_timeout_secs = 60
+
+
+; The comma separated list of allowed protocols for the request. Available with
+; cURL version 7.85.0 or later.
+; See https://curl.se/libcurl/c/CURLOPT_PROTOCOLS_STR.html for details.
+;
+;protocols = http,https
+
+; The comma separated list of allowed protocols for redirects. Available with
+; cURL version 7.85.0 or later. This can be used to prevent a redirect from
+; a protocol like HTTPS to another supported protocol of cURL.
+;
+; See https://curl.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS_STR.html for details.
+;
+;redirect_protocols = http,https
diff --git a/doc/CHANGES-staging/res_http_media_cache.txt b/doc/CHANGES-staging/res_http_media_cache.txt
new file mode 100644
index 0000000..79223c0
--- /dev/null
+++ b/doc/CHANGES-staging/res_http_media_cache.txt
@@ -0,0 +1,12 @@
+Subject: res_http_media_cache
+
+The res_http_media_cache module now attempts to load
+configuration from the res_http_media_cache.conf file.
+The following options were added:
+ * timeout_secs
+ * user_agent
+ * follow_location
+ * max_redirects
+ * protocols
+ * redirect_protocols
+ * dns_cache_timeout_secs
diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c
index b4c4c65..73386fe 100644
--- a/res/res_http_media_cache.c
+++ b/res/res_http_media_cache.c
@@ -31,6 +31,41 @@
<support_level>core</support_level>
***/
+/*** DOCUMENTATION
+ <configInfo name="res_http_media_cache" language="en_US">
+ <synopsis>HTTP media cache</synopsis>
+ <configFile name="http_media_cache.conf">
+ <configObject name="general">
+ <synopsis>General configuration</synopsis>
+ <configOption name="timeout_secs" default="180">
+ <synopsis>The maximum time the transfer is allowed to complete in seconds. See https://curl.se/libcurl/c/CURLOPT_TIMEOUT.html for details.</synopsis>
+ </configOption>
+ <configOption name="user_agent">
+ <synopsis>The HTTP User-Agent to use for requests. See https://curl.se/libcurl/c/CURLOPT_USERAGENT.html for details.</synopsis>
+ </configOption>
+ <configOption name="follow_location" default="1">
+ <synopsis>Follow HTTP 3xx redirects on requests. See https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html for details.</synopsis>
+ </configOption>
+ <configOption name="max_redirects" default="8">
+ <synopsis>The maximum number of redirects to follow. See https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html for details.</synopsis>
+ </configOption>
+ <configOption name="proxy">
+ <synopsis>The proxy to use for requests. See https://curl.se/libcurl/c/CURLOPT_PROXY.html for details.</synopsis>
+ </configOption>
+ <configOption name="protocols">
+ <synopsis>The comma separated list of allowed protocols for the request. Available with cURL 7.85.0 or later. See https://curl.se/libcurl/c/CURLOPT_PROTOCOLS_STR.html for details.</synopsis>
+ </configOption>
+ <configOption name="redirect_protocols">
+ <synopsis>The comma separated list of allowed protocols for redirects. Available with cURL 7.85.0 or later. See https://curl.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS_STR.html for details.</synopsis>
+ </configOption>
+ <configOption name="dns_cache_timeout_secs" default="60">
+ <synopsis>The life-time for DNS cache entries. See https://curl.se/libcurl/c/CURLOPT_DNS_CACHE_TIMEOUT.html for details.</synopsis>
+ </configOption>
+ </configObject>
+ </configFile>
+ </configInfo>
+***/
+
#include "asterisk.h"
#include <curl/curl.h>
@@ -44,6 +79,123 @@
#define MAX_HEADER_LENGTH 1023
+#ifdef CURL_AT_LEAST_VERSION
+#if CURL_AT_LEAST_VERSION(7, 85, 0)
+#define AST_CURL_HAS_PROTOCOLS_STR 1
+#endif
+#endif
+
+static int http_media_cache_config_pre_apply(void);
+
+/*! \brief General configuration options for http media cache. */
+struct conf_general_options {
+ /*! \brief Request timeout to use */
+ int curl_timeout;
+
+ /*! \brief Follow 3xx redirects automatically. */
+ int curl_followlocation;
+
+ /*! \brief Number of redirects to follow for one request. */
+ int curl_maxredirs;
+
+ /*! \brief Life-time of CURL DNS cache entries. */
+ int curl_dns_cache_timeout;
+
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(curl_useragent); /*! \brief User-agent to use for requests. */
+ AST_STRING_FIELD(curl_proxy); /*! \brief Proxy to use for requests. None by default. */
+ AST_STRING_FIELD(curl_protocols); /*! \brief Allowed protocols to use for requests. All by default. */
+ AST_STRING_FIELD(curl_redir_protocols); /*! \brief Allowed protocols to use on redirect. All by default. */
+ );
+};
+
+/*! \brief All configuration options for http media cache. */
+struct conf {
+ /*! The general section configuration options. */
+ struct conf_general_options *general;
+};
+
+/*! \brief Locking container for safe configuration access. */
+static AO2_GLOBAL_OBJ_STATIC(confs);
+
+/*! \brief Mapping of the http media cache conf struct's general to the general context in the config file. */
+static struct aco_type general_option = {
+ .type = ACO_GLOBAL,
+ .name = "general",
+ .item_offset = offsetof(struct conf, general),
+ .category = "general",
+ .category_match = ACO_WHITELIST_EXACT,
+};
+
+static struct aco_type *general_options[] = ACO_TYPES(&general_option);
+
+/*! \brief Disposes of the http media cache conf object */
+static void conf_destructor(void *obj)
+{
+ struct conf *cfg = obj;
+ ast_string_field_free_memory(cfg->general);
+ ao2_cleanup(cfg->general);
+}
+
+/*! \brief Creates the http media cache conf object. */
+static void *conf_alloc(void)
+{
+ struct conf *cfg;
+
+ if (!(cfg = ao2_alloc(sizeof(*cfg), conf_destructor))) {
+ return NULL;
+ }
+
+ if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), NULL))) {
+ ao2_ref(cfg, -1);
+ return NULL;
+ }
+
+ if (ast_string_field_init(cfg->general, 256)) {
+ ao2_ref(cfg, -1);
+ return NULL;
+ }
+
+ return cfg;
+}
+
+/*! \brief The conf file that's processed for the module. */
+static struct aco_file conf_file = {
+ /*! The config file name. */
+ .filename = "res_http_media_cache.conf",
+ /*! The mapping object types to be processed. */
+ .types = ACO_TYPES(&general_option),
+};
+
+CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
+ .pre_apply_config = http_media_cache_config_pre_apply,
+ .files = ACO_FILES(&conf_file));
+
+/*!
+ * \brief Pre-apply callback for the config framework.
+ *
+ * This validates that used options match the ones supported by CURL.
+ */
+static int http_media_cache_config_pre_apply(void)
+{
+#ifndef AST_CURL_HAS_PROTOCOLS_STR
+ struct conf *cfg = aco_pending_config(&cfg_info);
+
+ if (!ast_strlen_zero(cfg->general->curl_protocols)) {
+ ast_log(AST_LOG_ERROR, "'protocols' not supported by linked CURL library. Please recompile against newer CURL.\n");
+ return -1;
+ }
+
+ if (!ast_strlen_zero(cfg->general->curl_redir_protocols)) {
+ ast_log(AST_LOG_ERROR, "'redirect_protocols' not supported by linked CURL library. Please recompile against newer CURL.\n");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
/*! \brief Data passed to cURL callbacks */
struct curl_bucket_file_data {
/*! The \c ast_bucket_file object that caused the operation */
@@ -324,6 +476,8 @@
*/
static CURL *get_curl_instance(struct curl_bucket_file_data *cb_data)
{
+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
+ CURLcode rc;
CURL *curl;
curl = curl_easy_init();
@@ -332,14 +486,47 @@
}
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header_callback);
- curl_easy_setopt(curl, CURLOPT_USERAGENT, AST_CURL_USER_AGENT);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 8);
curl_easy_setopt(curl, CURLOPT_URL, ast_sorcery_object_get_id(cb_data->bucket_file));
curl_easy_setopt(curl, CURLOPT_HEADERDATA, cb_data);
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, cfg->general->curl_timeout);
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, cfg->general->curl_useragent);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, cfg->general->curl_followlocation ? 1 : 0);
+ curl_easy_setopt(curl, CURLOPT_MAXREDIRS, cfg->general->curl_maxredirs);
+
+ if (!ast_strlen_zero(cfg->general->curl_proxy)) {
+ curl_easy_setopt(curl, CURLOPT_PROXY, cfg->general->curl_proxy);
+ }
+
+ if (!ast_strlen_zero(cfg->general->curl_protocols)) {
+#ifdef AST_CURL_HAS_PROTOCOLS_STR
+ CURLcode rc = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, cfg->general->curl_protocols);
+ if (rc != CURLE_OK) {
+ ast_log(AST_LOG_ERROR, "Setting protocols to '%s' failed: %d\n", cfg->general->curl_protocols, rc);
+ curl_easy_cleanup(curl);
+ return NULL;
+ }
+#endif
+ }
+ if (!ast_strlen_zero(cfg->general->curl_redir_protocols)) {
+#ifdef AST_CURL_HAS_PROTOCOLS_STR
+ CURLcode rc = curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, cfg->general->curl_redir_protocols);
+ if (rc != CURLE_OK) {
+ ast_log(AST_LOG_ERROR, "Setting redirect_protocols to '%s' failed: %d\n", cfg->general->curl_redir_protocols, rc);
+ curl_easy_cleanup(curl);
+ return NULL;
+ }
+#endif
+ }
+
+ rc = curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, cfg->general->curl_dns_cache_timeout);
+ if (rc != CURLE_OK) {
+ ast_log(AST_LOG_ERROR, "Setting dns_cache_timeout to '%d' failed: %d\n", cfg->general->curl_dns_cache_timeout, rc);
+ curl_easy_cleanup(curl);
+ return NULL;
+ }
+
return curl;
}
@@ -541,11 +728,73 @@
static int unload_module(void)
{
+ aco_info_destroy(&cfg_info);
+ ao2_global_obj_release(confs);
return 0;
}
static int load_module(void)
{
+ if (aco_info_init(&cfg_info)) {
+ aco_info_destroy(&cfg_info);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+
+ aco_option_register(&cfg_info, "timeout_secs", ACO_EXACT, general_options,
+ "180", OPT_INT_T, 0,
+ FLDSET(struct conf_general_options, curl_timeout));
+
+ aco_option_register(&cfg_info, "user_agent", ACO_EXACT, general_options,
+ AST_CURL_USER_AGENT, OPT_STRINGFIELD_T, 0,
+ STRFLDSET(struct conf_general_options, curl_useragent));
+
+ aco_option_register(&cfg_info, "follow_location", ACO_EXACT, general_options,
+ "yes", OPT_BOOL_T, 1,
+ FLDSET(struct conf_general_options, curl_followlocation));
+
+ aco_option_register(&cfg_info, "max_redirects", ACO_EXACT, general_options,
+ "8", OPT_INT_T, 0,
+ FLDSET(struct conf_general_options, curl_maxredirs));
+
+ aco_option_register(&cfg_info, "proxy", ACO_EXACT, general_options,
+ NULL, OPT_STRINGFIELD_T, 1,
+ STRFLDSET(struct conf_general_options, curl_proxy));
+
+ aco_option_register(&cfg_info, "dns_cache_timeout_secs", ACO_EXACT, general_options,
+ "60", OPT_INT_T, 0,
+ FLDSET(struct conf_general_options, curl_dns_cache_timeout));
+
+ aco_option_register(&cfg_info, "protocols", ACO_EXACT, general_options,
+ NULL, OPT_STRINGFIELD_T, 1,
+ STRFLDSET(struct conf_general_options, curl_protocols));
+
+ aco_option_register(&cfg_info, "redirect_protocols", ACO_EXACT, general_options,
+ NULL, OPT_STRINGFIELD_T, 1,
+ STRFLDSET(struct conf_general_options, curl_redir_protocols));
+
+
+ if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
+ struct conf *cfg;
+
+ ast_log(LOG_NOTICE, "Could not load res_http_media_cache config; using defaults\n");
+ cfg = conf_alloc();
+ if (!cfg) {
+ aco_info_destroy(&cfg_info);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (aco_set_defaults(&general_option, "general", cfg->general)) {
+ ast_log(LOG_ERROR, "Failed to initialize res_http_media_cache defaults.\n");
+ ao2_ref(cfg, -1);
+ aco_info_destroy(&cfg_info);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ ao2_global_obj_replace_unref(confs, cfg);
+ ao2_ref(cfg, -1);
+ }
+
if (ast_bucket_scheme_register("http", &http_bucket_wizard, &http_bucket_file_wizard,
NULL, NULL)) {
ast_log(LOG_ERROR, "Failed to register Bucket HTTP wizard scheme implementation\n");
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/19953
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I2eb02ef44190e026716720419bcbdbcc8125777b
Gerrit-Change-Number: 19953
Gerrit-PatchSet: 2
Gerrit-Owner: Holger Hans Peter Freyther <automatic at freyther.de>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at sangoma.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20230306/2a0378aa/attachment-0001.html>
More information about the asterisk-code-review
mailing list