<p>Joshua Colp <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16163">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Joshua Colp: Looks good to me, approved; Approved for Submit
Kevin Harwell: Looks good to me, approved
George Joseph: Looks good to me, but someone else must approve
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_http_media_cache.c: Parse media URLs to find extensions.<br><br>Use the URI parsing functions to parse playback URLs in order to find<br>their file extensions.<br><br>For backwards compatibility, we first look at the full URL, then at<br>any Content-Type header, and finally at just the path portion of the<br>URL.<br><br>ASTERISK-27871 #close<br><br>Change-Id: I16d0682f6d794be96539261b3e48f237909139cb<br>---<br>M main/media_cache.c<br>M res/res_http_media_cache.c<br>M tests/test_http_media_cache.c<br>3 files changed, 200 insertions(+), 51 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/main/media_cache.c b/main/media_cache.c</span><br><span>index b303643..1899fb4 100644</span><br><span>--- a/main/media_cache.c</span><br><span>+++ b/main/media_cache.c</span><br><span>@@ -126,71 +126,30 @@</span><br><span> </span><br><span> /*!</span><br><span> * \internal</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Normalize the value of a Content-Type header</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This will trim off any optional parameters after the type/subtype.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-static void normalize_content_type_header(char *content_type)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- char *params = strchr(content_type, ';');</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (params) {</span><br><span style="color: hsl(0, 100%, 40%);">- *params-- = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- while (params > content_type && (*params == ' ' || *params == '\t')) {</span><br><span style="color: hsl(0, 100%, 40%);">- *params-- = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \internal</span><br><span> * \brief Update the name of the file backing a \c bucket_file</span><br><span> * \param preferred_file_name The preferred name of the backing file</span><br><span> */</span><br><span> static void bucket_file_update_path(struct ast_bucket_file *bucket_file,</span><br><span> const char *preferred_file_name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- char *ext;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> if (!ast_strlen_zero(preferred_file_name) && strcmp(bucket_file->path, preferred_file_name)) {</span><br><span> /* Use the preferred file name if available */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> rename(bucket_file->path, preferred_file_name);</span><br><span> ast_copy_string(bucket_file->path, preferred_file_name,</span><br><span> sizeof(bucket_file->path));</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (!strchr(bucket_file->path, '.') && (ext = strrchr(ast_sorcery_object_get_id(bucket_file), '.'))) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* If we don't have a file extension and were provided one in the URI, use it */</span><br><span style="color: hsl(0, 100%, 40%);">- char found_ext[32];</span><br><span style="color: hsl(0, 100%, 40%);">- char new_path[PATH_MAX + sizeof(found_ext)];</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strchr(bucket_file->path, '.')) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_bucket_metadata *ext =</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_bucket_file_metadata_get(bucket_file, "ext");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_bucket_file_metadata_set(bucket_file, "ext", ext);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Don't pass '.' while checking for supported extension */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ast_get_format_for_file_ext(ext + 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* If the file extension passed in the URI isn't supported check for the</span><br><span style="color: hsl(0, 100%, 40%);">- * extension based on the MIME type passed in the Content-Type header before</span><br><span style="color: hsl(0, 100%, 40%);">- * giving up.</span><br><span style="color: hsl(0, 100%, 40%);">- * If a match is found then retrieve the extension from the supported list</span><br><span style="color: hsl(0, 100%, 40%);">- * corresponding to the mime-type and use that to rename the file */</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_bucket_metadata *header = ast_bucket_file_metadata_get(bucket_file, "content-type");</span><br><span style="color: hsl(0, 100%, 40%);">- if (header) {</span><br><span style="color: hsl(0, 100%, 40%);">- char *mime_type = ast_strdup(header->value);</span><br><span style="color: hsl(0, 100%, 40%);">- if (mime_type) {</span><br><span style="color: hsl(0, 100%, 40%);">- normalize_content_type_header(mime_type);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ast_strlen_zero(mime_type)) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_get_extension_for_mime_type(mime_type, found_ext, sizeof(found_ext))) {</span><br><span style="color: hsl(0, 100%, 40%);">- ext = found_ext;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- ast_free(mime_type);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(header, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ext) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char *new_path;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_asprintf(&new_path, "%s%s", bucket_file->path, ext->value) != -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rename(bucket_file->path, new_path);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_string(bucket_file->path, new_path, sizeof(bucket_file->path));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(new_path);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(ext, -1);</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- snprintf(new_path, sizeof(new_path), "%s%s", bucket_file->path, ext);</span><br><span style="color: hsl(0, 100%, 40%);">- rename(bucket_file->path, new_path);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_copy_string(bucket_file->path, new_path, sizeof(bucket_file->path));</span><br><span> }</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c</span><br><span>index d761442..5410566 100644</span><br><span>--- a/res/res_http_media_cache.c</span><br><span>+++ b/res/res_http_media_cache.c</span><br><span>@@ -35,10 +35,12 @@</span><br><span> </span><br><span> #include <curl/curl.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/file.h"</span><br><span> #include "asterisk/module.h"</span><br><span> #include "asterisk/bucket.h"</span><br><span> #include "asterisk/sorcery.h"</span><br><span> #include "asterisk/threadstorage.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/uri.h"</span><br><span> </span><br><span> #define GLOBAL_USERAGENT "asterisk-libcurl-agent/1.0"</span><br><span> </span><br><span>@@ -155,6 +157,115 @@</span><br><span> ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static char *file_extension_from_string(const char *str, char *buffer, size_t capacity)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *ext;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ext = strrchr(str, '.');</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ext && ast_get_format_for_file_ext(ext + 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Found extension '%s' at end of string\n", ext);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_string(buffer, ext, capacity);</span><br><span style="color: hsl(120, 100%, 40%);">+ return buffer;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *file_extension_from_url(struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return file_extension_from_string(ast_sorcery_object_get_id(bucket_file), buffer, capacity);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Normalize the value of a Content-Type header</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This will trim off any optional parameters after the type/subtype.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void normalize_content_type_header(char *content_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char *params = strchr(content_type, ';');</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (params) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *params-- = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ while (params > content_type && (*params == ' ' || *params == '\t')) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *params-- = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *file_extension_from_content_type(struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check for the extension based on the MIME type passed in the Content-Type</span><br><span style="color: hsl(120, 100%, 40%);">+ * header.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * If a match is found then retrieve the extension from the supported list</span><br><span style="color: hsl(120, 100%, 40%);">+ * corresponding to the mime-type and use that to rename the file */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_bucket_metadata *header;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mime_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ header = ast_bucket_file_metadata_get(bucket_file, "content-type");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!header) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mime_type = ast_strdup(header->value);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mime_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ normalize_content_type_header(mime_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(mime_type)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_get_extension_for_mime_type(mime_type, buffer, sizeof(buffer))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Derived extension '%s' from MIME type %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ buffer,</span><br><span style="color: hsl(120, 100%, 40%);">+ mime_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mime_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(header, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return buffer;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mime_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(header, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *file_extension_from_url_path(struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_uri *uri;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ uri = ast_uri_parse(ast_sorcery_object_get_id(bucket_file));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!uri) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to parse URI: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_get_id(bucket_file));</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Just parse it as a string like before, but without the extra cruft */</span><br><span style="color: hsl(120, 100%, 40%);">+ buffer = file_extension_from_string(ast_uri_path(uri), buffer, capacity);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ return buffer;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void bucket_file_set_extension(struct ast_bucket_file *bucket_file)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We will attempt to determine an extension in the following order for backwards</span><br><span style="color: hsl(120, 100%, 40%);">+ * compatibility:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * 1. Look at tail end of URL for extension</span><br><span style="color: hsl(120, 100%, 40%);">+ * 2. Use the Content-Type header if present</span><br><span style="color: hsl(120, 100%, 40%);">+ * 3. Parse the URL (assuming we can) and look at the tail of the path</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ char buffer[64];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (file_extension_from_url(bucket_file, buffer, sizeof(buffer))</span><br><span style="color: hsl(120, 100%, 40%);">+ || file_extension_from_content_type(bucket_file, buffer, sizeof(buffer))</span><br><span style="color: hsl(120, 100%, 40%);">+ || file_extension_from_url_path(bucket_file, buffer, sizeof(buffer))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_bucket_file_metadata_set(bucket_file, "ext", buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \internal</span><br><span> * \brief Return whether or not we should always revalidate against the server</span><br><span> */</span><br><span>@@ -278,6 +389,7 @@</span><br><span> </span><br><span> if (http_code / 100 == 2) {</span><br><span> bucket_file_set_expiration(bucket_file);</span><br><span style="color: hsl(120, 100%, 40%);">+ bucket_file_set_extension(bucket_file);</span><br><span> return 0;</span><br><span> } else {</span><br><span> ast_log(LOG_WARNING, "Failed to retrieve URL '%s': server returned %ld\n",</span><br><span>diff --git a/tests/test_http_media_cache.c b/tests/test_http_media_cache.c</span><br><span>index c197539..90d1aef 100644</span><br><span>--- a/tests/test_http_media_cache.c</span><br><span>+++ b/tests/test_http_media_cache.c</span><br><span>@@ -57,6 +57,7 @@</span><br><span> struct timeval expires;</span><br><span> const char *status_text;</span><br><span> const char *etag;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *content_type;</span><br><span> };</span><br><span> </span><br><span> static struct test_options options;</span><br><span>@@ -125,6 +126,10 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(options.content_type)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_append(&http_header, 0, "Content-Type: %s\r\n", options.content_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (options.cache_control.maxage) {</span><br><span> SET_OR_APPEND_CACHE_CONTROL(cache_control);</span><br><span> ast_str_append(&cache_control, 0, "max-age=%d", options.cache_control.maxage);</span><br><span>@@ -220,6 +225,75 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AST_TEST_DEFINE(retrieve_content_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ char uri[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ info->name = __func__;</span><br><span style="color: hsl(120, 100%, 40%);">+ info->category = CATEGORY;</span><br><span style="color: hsl(120, 100%, 40%);">+ info->summary = "Test retrieval of a resource with a Content-Type header";</span><br><span style="color: hsl(120, 100%, 40%);">+ info->description =</span><br><span style="color: hsl(120, 100%, 40%);">+ "This test covers retrieval of a resource whose URL does not end with\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "a parseable extension and whose response includes a Content-Type\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "header that we recognize.";</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+ case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ options.send_file = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ options.status_code = 200;</span><br><span style="color: hsl(120, 100%, 40%);">+ options.status_text = "OK";</span><br><span style="color: hsl(120, 100%, 40%);">+ options.content_type = "audio/wav";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav?account_id=1234");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bucket_file = ast_bucket_file_retrieve(uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, bucket_file != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file)));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, !ast_strlen_zero(bucket_file->path));</span><br><span style="color: hsl(120, 100%, 40%);">+ VALIDATE_STR_METADATA(test, bucket_file, "ext", ".wav");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_TEST_DEFINE(retrieve_parsed_uri)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ char uri[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ info->name = __func__;</span><br><span style="color: hsl(120, 100%, 40%);">+ info->category = CATEGORY;</span><br><span style="color: hsl(120, 100%, 40%);">+ info->summary = "Test retrieval of a resource with a complex URI";</span><br><span style="color: hsl(120, 100%, 40%);">+ info->description =</span><br><span style="color: hsl(120, 100%, 40%);">+ "This test covers retrieval of a resource whose URL does not end with\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "a parseable extension, but the path portion of the URL does end with\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "parseable extension.";</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+ case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ options.send_file = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ options.status_code = 200;</span><br><span style="color: hsl(120, 100%, 40%);">+ options.status_text = "OK";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav?account_id=1234");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bucket_file = ast_bucket_file_retrieve(uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, bucket_file != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file)));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, !ast_strlen_zero(bucket_file->path));</span><br><span style="color: hsl(120, 100%, 40%);">+ VALIDATE_STR_METADATA(test, bucket_file, "ext", ".wav");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AST_TEST_DEFINE(retrieve_cache_control_directives)</span><br><span> {</span><br><span> RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup);</span><br><span>@@ -670,6 +744,8 @@</span><br><span> AST_TEST_REGISTER(retrieve_etag_expired);</span><br><span> AST_TEST_REGISTER(retrieve_cache_control_age);</span><br><span> AST_TEST_REGISTER(retrieve_cache_control_directives);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_TEST_REGISTER(retrieve_parsed_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_TEST_REGISTER(retrieve_content_type);</span><br><span> </span><br><span> ast_test_register_init(CATEGORY, pre_test_cb);</span><br><span> </span><br><span>@@ -688,6 +764,8 @@</span><br><span> AST_TEST_UNREGISTER(retrieve_etag_expired);</span><br><span> AST_TEST_UNREGISTER(retrieve_cache_control_age);</span><br><span> AST_TEST_UNREGISTER(retrieve_cache_control_directives);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_TEST_REGISTER(retrieve_parsed_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_TEST_REGISTER(retrieve_content_type);</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16163">change 16163</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/16163"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: I16d0682f6d794be96539261b3e48f237909139cb </div>
<div style="display:none"> Gerrit-Change-Number: 16163 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: Sean Bright <sean@seanbright.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>