<p>Gaurav Khurana has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/8207">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add the ability to read the media file type from HTTP header for playback<br><br>How it works today:<br>media_cache tries to parse out the extension of the media file to be played<br>from the URI provided to Asterisk while caching the file.<br><br>What's expected:<br>Better will be to have Asterisk get extension from other ways too. One of the<br>common ways is to get the type of content from the CONTENT-TYPE header in the<br>HTTP response for fetching the media file using the URI provided.<br><br>Steps to Reproduce:<br>Provide a URL of the form: http://host/media/1234 to Asterisk for media<br>playback. It fails to play and logs show the following error line:<br><br>[Sep 15 15:48:05] WARNING [29148] [C-00000092] file.c:<br>File http://host/media/1234 does not exist in any format<br><br>Scenario this issue is blocking:<br>In the case where the media files are stored in some cloud object store,<br>following can block the media being played via Asterisk:<br><br>Cloud storage generally needs authenticated access to the storage. The way<br>to do that is by using signed URIs. With the signed URIs there's no way to<br>preserve the name of the file.<br>In most cases Cloud storage returns a key to access the object and preserving<br>file name is also not a thing there<br><br>ASTERISK-27286<br><br> Reporter: Gaurav Khurana<br><br>Change-Id: I1b14692a49b2c1ac67688f58757184122e92ba89<br>---<br>M formats/format_pcm.c<br>M formats/format_vox.c<br>M formats/format_wav.c<br>M include/asterisk/file.h<br>M include/asterisk/mod_format.h<br>M main/bucket.c<br>M main/file.c<br>M main/format_cap.c<br>M main/media_cache.c<br>M res/res_http_media_cache.c<br>10 files changed, 100 insertions(+), 8 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/07/8207/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/formats/format_pcm.c b/formats/format_pcm.c<br>index c12ef6b..a3d85e7 100644<br>--- a/formats/format_pcm.c<br>+++ b/formats/format_pcm.c<br>@@ -500,6 +500,7 @@<br> static struct ast_format_def pcm_f = {<br>    .name = "pcm",<br>      .exts = "pcm|ulaw|ul|mu|ulw",<br>+      .mime_types = "audio/basic",<br>        .write = pcm_write,<br>   .seek = pcm_seek,<br>     .trunc = pcm_trunc,<br>diff --git a/formats/format_vox.c b/formats/format_vox.c<br>index 0775f85..b23744a 100644<br>--- a/formats/format_vox.c<br>+++ b/formats/format_vox.c<br>@@ -130,6 +130,7 @@<br> static struct ast_format_def vox_f = {<br>    .name = "vox",<br>      .exts = "vox",<br>+     .mime_types = "audio/x-vox",<br>        .write = vox_write,<br>   .seek = vox_seek,<br>     .trunc = vox_trunc,<br>diff --git a/formats/format_wav.c b/formats/format_wav.c<br>index fcdaf39..446b18a 100644<br>--- a/formats/format_wav.c<br>+++ b/formats/format_wav.c<br>@@ -534,6 +534,7 @@<br> static struct ast_format_def wav_f = {<br>    .name = "wav",<br>      .exts = "wav",<br>+     .mime_types = "audio/wav|audio/x-wav",<br>      .open = wav_open,<br>     .rewrite = wav_rewrite,<br>       .write = wav_write,<br>diff --git a/include/asterisk/file.h b/include/asterisk/file.h<br>index 01e5797..4b557b0 100644<br>--- a/include/asterisk/file.h<br>+++ b/include/asterisk/file.h<br>@@ -422,6 +422,26 @@<br>  */<br> struct ast_format *ast_get_format_for_file_ext(const char *file_ext);<br> <br>+/*!<br>+ * \brief Get the extensions associated with the given MIME TYPE<br>+ *<br>+ * \param file_ext The file extension for which to find the format<br>+ *<br>+ * \retval NULL if not found<br>+ * \retval A pointer to the ast_format associated with this file extension<br>+ */<br>+<br>+int ast_get_extensions_for_mime_type(const char *mime_type, char *exts);<br>+<br>+/*!<br>+ * \brief Check if the file extension is a supported extension<br>+ *<br>+ * \param file_ext The file extension for which to find the format<br>+ *<br>+ * \retval 1 if not supported<br>+ * \retval 0 if supported<br>+ */<br>+int ast_is_file_ext_supported(const char *file_ext);<br> #if defined(__cplusplus) || defined(c_plusplus)<br> }<br> #endif<br>diff --git a/include/asterisk/mod_format.h b/include/asterisk/mod_format.h<br>index 7e05a28..7d067bb 100644<br>--- a/include/asterisk/mod_format.h<br>+++ b/include/asterisk/mod_format.h<br>@@ -44,6 +44,7 @@<br>      char name[80];          /*!< Name of format */<br>     char exts[80];          /*!< Extensions (separated by | if more than one) <br>                                                  * this format can read.  First is assumed for writing (e.g. .mp3) */<br>+        char mime_types[80]; /*!< MIME Types related to the format (separated by | if more than one)*/<br>     struct ast_format *format;      /*!< Format of frames it uses/provides (one only) */<br>       /*!<br>    * \brief Prepare an input stream for playback.<br>diff --git a/main/bucket.c b/main/bucket.c<br>index 7b8c689..f8e572e 100644<br>--- a/main/bucket.c<br>+++ b/main/bucket.c<br>@@ -930,7 +930,7 @@<br>     if (fd < 0) {<br>              return -1;<br>    }<br>-<br>+ <br>      close(fd);<br>    return 0;<br> }<br>diff --git a/main/file.c b/main/file.c<br>index 4239ddd..6da04ab 100644<br>--- a/main/file.c<br>+++ b/main/file.c<br>@@ -349,6 +349,22 @@<br>      return 0;<br> }<br> <br>+/* compare type against the list 'mime_types' */<br>+/* XXX need a better algorithm */<br>+static int mime_types_compare(const char *mime_types, const char *type)<br>+{<br>+        char tmp[256];<br>+       char *stringp = tmp, *mime_type;<br>+<br>+  ast_copy_string(tmp, mime_types, sizeof(tmp));<br>+       while ((mime_type = strsep(&stringp, "|"))) {<br>+          if (!strcmp(mime_type, type))<br>+                        return 1;<br>+    }<br>+<br>+ return 0;<br>+}<br>+<br> /*!<br>  * \internal<br>  * \brief Close the file stream by canceling any pending read / write callbacks<br>@@ -1922,6 +1938,33 @@<br>       return NULL;<br> }<br> <br>+int ast_get_extensions_for_mime_type(const char *mime_type, char *exts)<br>+{<br>+    struct ast_format_def *f;<br>+    SCOPED_RDLOCK(lock, &formats.lock);<br>+      AST_RWLIST_TRAVERSE(&formats, f, list) {<br>+         if (mime_types_compare(f->mime_types, mime_type)) {<br>+                       if (exts){<br>+                           ast_copy_string(exts, f->exts, strlen(f->exts) + 1);<br>+                           return 0;<br>+                    }<br>+            }<br>+    }<br>+<br>+ return 1;<br>+}<br>+int ast_is_file_ext_supported(const char *file_ext)<br>+{<br>+      struct ast_format_def *f;<br>+    SCOPED_RDLOCK(lock, &formats.lock);<br>+      AST_RWLIST_TRAVERSE(&formats, f, list) {<br>+         if (exts_compare(f->exts, file_ext)) {<br>+            return 0;<br>+            }<br>+    }<br>+<br>+ return 1;<br>+}<br> static struct ast_cli_entry cli_file[] = {<br>    AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")<br> };<br>diff --git a/main/format_cap.c b/main/format_cap.c<br>index ed7afc2..6a070cf 100644<br>--- a/main/format_cap.c<br>+++ b/main/format_cap.c<br>@@ -621,7 +621,7 @@<br>                   return 1;<br>             }<br>     }<br>-<br>+ <br>      return 0;<br> }<br> <br>diff --git a/main/media_cache.c b/main/media_cache.c<br>index e92cce5..c85df3d 100644<br>--- a/main/media_cache.c<br>+++ b/main/media_cache.c<br>@@ -37,6 +37,7 @@<br> #include "asterisk/bucket.h"<br> #include "asterisk/astdb.h"<br> #include "asterisk/cli.h"<br>+#include "asterisk/file.h"<br> #include "asterisk/media_cache.h"<br> <br> /*! The name of the AstDB family holding items in the cache. */<br>@@ -200,10 +201,33 @@<br>  } else if (!strchr(bucket_file->path, '.') && (ext = strrchr(ast_sorcery_object_get_id(bucket_file), '.'))) {<br>              /* If we don't have a file extension and were provided one in the URI, use it */<br>          char new_path[PATH_MAX];<br>-<br>+          char temp_ext[PATH_MAX];<br>+             strcpy(temp_ext, ext);<br>+               /*Don't pass '.' while checking for supported extension*/<br>+                if (ast_is_file_ext_supported(ext + 1)){<br>+                     /* If the file extension passed in the URI isn't supported check for the<br>+                  * extension based on the MIME TYPE passed in CONTENT_TYPE header before<br>+                      * giving up<br>+                  * If a match is found then retrieve the extension from the supported list corresponding<br>+                      * to the mime-type and use that to rename the file*/<br>+                        struct ast_bucket_metadata *header = ast_bucket_file_metadata_get(bucket_file, "content-type");<br>+                    if (header != NULL) {<br>+                                const char *mime_type = header->value;<br>+                            char *exts = ast_malloc(sizeof(char) * PATH_MAX);<br>+                            if (!ast_get_extensions_for_mime_type(mime_type, exts)){<br>+                                     /*Pick the first extension that matches the mime-type*/<br>+                                      char *tmp = strsep(&exts, "|");<br>+                                        <br>+                                     /*Not updating the original ext here to keep the key for media-cache same*/<br>+                                  snprintf(temp_ext, strlen(temp_ext), ".%s", tmp);<br>+                          }<br>+                            <br>+                             ast_free(exts);<br>+                      }<br>+            }<br>+        <br>          ast_bucket_file_metadata_set(bucket_file, "ext", ext);<br>-<br>-          snprintf(new_path, sizeof(new_path), "%s%s", bucket_file->path, ext);<br>+           snprintf(new_path, sizeof(new_path), "%s%s", bucket_file->path, temp_ext);<br>               rename(bucket_file->path, new_path);<br>               ast_copy_string(bucket_file->path, new_path, sizeof(bucket_file->path));<br>        }<br>@@ -233,7 +257,7 @@<br>                                *ext = '\0';<br>                  }<br>                     ao2_ref(bucket_file, -1);<br>-<br>+                 <br>                      ast_debug(5, "Returning media at local file: %s\n", file_path);<br>                     return 0;<br>             }<br>@@ -264,7 +288,7 @@<br>        }<br>     ao2_link_flags(media_cache, bucket_file, OBJ_NOLOCK);<br>         ao2_ref(bucket_file, -1);<br>-<br>+ <br>      ast_debug(5, "Returning media at local file: %s\n", file_path);<br> <br>  return 0;<br>@@ -354,7 +378,7 @@<br> <br>     snprintf(tmp, sizeof(tmp), "%jd", (intmax_t)st.st_size);<br>    ast_bucket_file_metadata_set(bucket_file, "size", tmp);<br>-<br>+    <br>   ext = strrchr(file_path_ptr, '.');<br>    if (ext) {<br>            ast_bucket_file_metadata_set(bucket_file, "ext", ext + 1);<br>diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c<br>index 991abfb..0bf62a3 100644<br>--- a/res/res_http_media_cache.c<br>+++ b/res/res_http_media_cache.c<br>@@ -86,6 +86,7 @@<br>      if (strcasecmp(header, "ETag")<br>              && strcasecmp(header, "Cache-Control")<br>              && strcasecmp(header, "Last-Modified")<br>+             && strcasecmp(header, "Content-Type")<br>               && strcasecmp(header, "Expires")) {<br>                 return realsize;<br>      }<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/8207">change 8207</a>. To unsubscribe, 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/8207"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I1b14692a49b2c1ac67688f58757184122e92ba89 </div>
<div style="display:none"> Gerrit-Change-Number: 8207 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Gaurav Khurana <gkhurana@godaddy.com> </div>