[Asterisk-code-review] res_http_media_cache: Introduce options and customize (asterisk[20])

Holger Hans Peter Freyther asteriskteam at digium.com
Thu Dec 15 02:21:13 CST 2022


Holger Hans Peter Freyther has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/19713 )


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: I3f8efbdf50f233df26197aa2836f5a206baa33ce
---
A doc/CHANGES-staging/res_http_media_cache.txt
M res/res_http_media_cache.c
2 files changed, 247 insertions(+), 4 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/13/19713/1

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..8549817
--- /dev/null
+++ b/doc/CHANGES-staging/res_http_media_cache.txt
@@ -0,0 +1,5 @@
+Subject: res_http_media_cache
+
+The res_http_media_cache module now attempts to load
+configuration from the res_http_media_cache.conf file.
+This can be used to control various CURL options.
diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c
index cd5fe42..244596b 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="useragent">
+					<synopsis>The HTTP User-Agent to use for requests. See https://curl.se/libcurl/c/CURLOPT_USERAGENT.html for details.</synopsis>
+				</configOption>
+				<configOption name="followlocation" default="1">
+					<synopsis>Follow HTTP 3xx redirects on requests. See https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html for details.</synopsis>
+				</configOption>
+				<configOption name="maxredirects" 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.html for details.</synopsis>
+				</configOption>
+				<configOption name="redir_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,96 @@
 
 #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
+
+/*! \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,
+		.files = ACO_FILES(&conf_file));
+
+
 /*! \brief Data passed to cURL callbacks */
 struct curl_bucket_file_data {
 	/*! The \c ast_bucket_file object that caused the operation */
@@ -317,6 +442,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();
@@ -325,14 +452,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);
+	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 redir_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;
 }
 
@@ -534,11 +694,75 @@
 
 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, "useragent", ACO_EXACT, general_options,
+			AST_CURL_USER_AGENT, OPT_STRINGFIELD_T, 0,
+			STRFLDSET(struct conf_general_options, curl_useragent));
+
+	aco_option_register(&cfg_info, "followlocation", ACO_EXACT, general_options,
+			"yes", OPT_BOOL_T, 1,
+			FLDSET(struct conf_general_options, curl_followlocation));
+
+	aco_option_register(&cfg_info, "maxredirects", 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));
+
+#ifdef AST_CURL_HAS_PROTOCOLS_STR
+	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, "redir_protocols", ACO_EXACT, general_options,
+			NULL, OPT_STRINGFIELD_T, 1,
+			STRFLDSET(struct conf_general_options, curl_redir_protocols));
+#endif
+
+
+	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/+/19713
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 20
Gerrit-Change-Id: I3f8efbdf50f233df26197aa2836f5a206baa33ce
Gerrit-Change-Number: 19713
Gerrit-PatchSet: 1
Gerrit-Owner: Holger Hans Peter Freyther <automatic at freyther.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20221215/1c064ced/attachment-0001.html>


More information about the asterisk-code-review mailing list