Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Functions | Variables
res_http_media_cache.c File Reference
#include "asterisk.h"
#include <curl/curl.h>
#include "asterisk/file.h"
#include "asterisk/module.h"
#include "asterisk/bucket.h"
#include "asterisk/sorcery.h"
#include "asterisk/threadstorage.h"
#include "asterisk/uri.h"
Include dependency graph for res_http_media_cache.c:

Go to the source code of this file.

Data Structures

struct  conf
 All configuration options for http media cache. More...
 
struct  conf_general_options
 General configuration options for http media cache. More...
 
struct  curl_bucket_file_data
 Data passed to cURL callbacks. More...
 

Macros

#define MAX_HEADER_LENGTH   1023
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static AO2_GLOBAL_OBJ_STATIC (confs)
 Locking container for safe configuration access. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int bucket_file_always_revalidate (struct ast_bucket_file *bucket_file)
 
static int bucket_file_expired (struct ast_bucket_file *bucket_file)
 
static int bucket_file_run_curl (struct ast_bucket_file *bucket_file)
 
static void bucket_file_set_expiration (struct ast_bucket_file *bucket_file)
 
static void bucket_file_set_extension (struct ast_bucket_file *bucket_file)
 
static int bucket_http_wizard_create (const struct ast_sorcery *sorcery, void *data, void *object)
 
static int bucket_http_wizard_delete (const struct ast_sorcery *sorcery, void *data, void *object)
 
static int bucket_http_wizard_is_stale (const struct ast_sorcery *sorcery, void *data, void *object)
 
static void * bucket_http_wizard_retrieve_id (const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
 
static void * conf_alloc (void)
 Creates the http media cache conf object. More...
 
static void conf_destructor (void *obj)
 Disposes of the http media cache conf object. More...
 
 CONFIG_INFO_STANDARD (cfg_info, confs, conf_alloc,.pre_apply_config=http_media_cache_config_pre_apply,.files=ACO_FILES(&conf_file))
 
static size_t curl_body_callback (void *ptr, size_t size, size_t nitems, void *data)
 
static size_t curl_header_callback (char *buffer, size_t size, size_t nitems, void *data)
 
static int derive_extension_from_mime_type (const char *mime_type, char *buffer, size_t capacity)
 
static long execute_curl_instance (CURL *curl)
 Execute the CURL. More...
 
static char * file_extension_from_content_type (struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)
 
static char * file_extension_from_string (const char *str, char *buffer, size_t capacity)
 
static char * file_extension_from_url_path (struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)
 
static CURL * get_curl_instance (struct curl_bucket_file_data *cb_data)
 
static int http_media_cache_config_pre_apply (void)
 Pre-apply callback for the config framework. More...
 
static int load_module (void)
 
static int normalize_content_type_header (char *content_type)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "HTTP Media Cache Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .requires = "res_curl", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct aco_file conf_file
 The conf file that's processed for the module. More...
 
static struct aco_type general_option
 Mapping of the http media cache conf struct's general to the general context in the config file. More...
 
static struct aco_typegeneral_options [] = ACO_TYPES(&general_option)
 
static struct ast_sorcery_wizard http_bucket_file_wizard
 
static struct ast_sorcery_wizard http_bucket_wizard
 
static struct ast_sorcery_wizard https_bucket_file_wizard
 
static struct ast_sorcery_wizard https_bucket_wizard
 

Detailed Description

Author
Matt Jordan <mjordan@digium.com> 

HTTP backend for the core media cache

Definition in file res_http_media_cache.c.

Macro Definition Documentation

◆ MAX_HEADER_LENGTH

#define MAX_HEADER_LENGTH   1023

Definition at line 116 of file res_http_media_cache.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 854 of file res_http_media_cache.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 854 of file res_http_media_cache.c.

◆ AO2_GLOBAL_OBJ_STATIC()

static AO2_GLOBAL_OBJ_STATIC ( confs  )
static

Locking container for safe configuration access.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 854 of file res_http_media_cache.c.

◆ bucket_file_always_revalidate()

static int bucket_file_always_revalidate ( struct ast_bucket_file bucket_file)
static

Definition at line 470 of file res_http_media_cache.c.

471{
472 RAII_VAR(struct ast_bucket_metadata *, metadata,
473 ast_bucket_file_metadata_get(bucket_file, "cache-control"),
475
476 if (!metadata) {
477 return 0;
478 }
479
480 if (strstr(metadata->value, "no-cache")
481 || strstr(metadata->value, "must-revalidate")) {
482 return 1;
483 }
484
485 return 0;
486}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ast_bucket_metadata * ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name)
Retrieve a metadata attribute from a file.
Definition: bucket.c:329
Bucket metadata structure, AO2 key value pair.
Definition: bucket.h:47
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References ao2_cleanup, ast_bucket_file_metadata_get(), and RAII_VAR.

Referenced by bucket_http_wizard_is_stale().

◆ bucket_file_expired()

static int bucket_file_expired ( struct ast_bucket_file bucket_file)
static

Definition at line 491 of file res_http_media_cache.c.

492{
493 RAII_VAR(struct ast_bucket_metadata *, metadata,
494 ast_bucket_file_metadata_get(bucket_file, "__actual_expires"),
496 struct timeval current_time = ast_tvnow();
497 struct timeval expires = { .tv_sec = 0, .tv_usec = 0 };
498
499 if (!metadata) {
500 return 1;
501 }
502
503 if ((expires.tv_sec = ast_string_to_time_t(metadata->value)) == -1) {
504 return 1;
505 }
506
507 return ast_tvcmp(current_time, expires) == -1 ? 0 : 1;
508}
time_t ast_string_to_time_t(const char *str)
Returns a time_t from a string containing seconds since the epoch.
Definition: time.c:163
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
Definition: time.h:137
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ao2_cleanup, ast_bucket_file_metadata_get(), ast_string_to_time_t(), ast_tvcmp(), ast_tvnow(), and RAII_VAR.

Referenced by bucket_http_wizard_is_stale().

◆ bucket_file_run_curl()

static int bucket_file_run_curl ( struct ast_bucket_file bucket_file)
static

Definition at line 595 of file res_http_media_cache.c.

596{
597 struct curl_bucket_file_data cb_data = {
599 };
600 long http_code;
601 CURL *curl;
602
603 cb_data.out_file = fopen(bucket_file->path, "wb");
604 if (!cb_data.out_file) {
605 ast_log(LOG_WARNING, "Failed to open file '%s' for writing: %s (%d)\n",
606 bucket_file->path, strerror(errno), errno);
607 return -1;
608 }
609
610 curl = get_curl_instance(&cb_data);
611 if (!curl) {
612 fclose(cb_data.out_file);
613 return -1;
614 }
615
616 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_callback);
617 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&cb_data);
618
619 http_code = execute_curl_instance(curl);
620
621 fclose(cb_data.out_file);
622
623 if (http_code / 100 == 2) {
626 return 0;
627 } else {
628 ast_log(LOG_WARNING, "Failed to retrieve URL '%s': server returned %ld\n",
630 }
631
632 return -1;
633}
#define ast_log
Definition: astobj2.c:42
#define LOG_WARNING
int errno
static void bucket_file_set_expiration(struct ast_bucket_file *bucket_file)
static void bucket_file_set_extension(struct ast_bucket_file *bucket_file)
static size_t curl_body_callback(void *ptr, size_t size, size_t nitems, void *data)
static CURL * get_curl_instance(struct curl_bucket_file_data *cb_data)
static long execute_curl_instance(CURL *curl)
Execute the CURL.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
char path[PATH_MAX]
Local path to this file.
Definition: bucket.h:95
Data passed to cURL callbacks.
struct ast_bucket_file * bucket_file

References ast_log, ast_sorcery_object_get_id(), curl_bucket_file_data::bucket_file, bucket_file_set_expiration(), bucket_file_set_extension(), curl_body_callback(), errno, execute_curl_instance(), get_curl_instance(), LOG_WARNING, curl_bucket_file_data::out_file, and ast_bucket_file::path.

Referenced by bucket_http_wizard_create(), and bucket_http_wizard_retrieve_id().

◆ bucket_file_set_expiration()

static void bucket_file_set_expiration ( struct ast_bucket_file bucket_file)
static

Definition at line 304 of file res_http_media_cache.c.

305{
306 struct ast_bucket_metadata *metadata;
307 char time_buf[32], secs[AST_TIME_T_LEN];
308 struct timeval actual_expires = ast_tvnow();
309
310 metadata = ast_bucket_file_metadata_get(bucket_file, "cache-control");
311 if (metadata) {
312 char *str_max_age;
313
314 str_max_age = strstr(metadata->value, "s-maxage");
315 if (!str_max_age) {
316 str_max_age = strstr(metadata->value, "max-age");
317 }
318
319 if (str_max_age) {
320 unsigned int max_age;
321 char *equal = strchr(str_max_age, '=');
322 if (equal && (sscanf(equal + 1, "%30u", &max_age) == 1)) {
323 actual_expires.tv_sec += max_age;
324 }
325 }
326 ao2_ref(metadata, -1);
327 } else {
328 metadata = ast_bucket_file_metadata_get(bucket_file, "expires");
329 if (metadata) {
330 struct tm expires_time;
331
332 strptime(metadata->value, "%a, %d %b %Y %T %z", &expires_time);
333 expires_time.tm_isdst = -1;
334 actual_expires.tv_sec = mktime(&expires_time);
335
336 ao2_ref(metadata, -1);
337 }
338 }
339
340 /* Use 'now' if we didn't get an expiration time */
341 ast_time_t_to_string(actual_expires.tv_sec, secs, sizeof(secs));
342 snprintf(time_buf, sizeof(time_buf), "%30s", secs);
343
344 ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf);
345}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
Set a metadata attribute on a file to a specific value.
Definition: bucket.c:304
const char * value
Value of the attribute.
Definition: bucket.h:51
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition: time.c:152
#define AST_TIME_T_LEN
Definition: time.h:45

References ao2_ref, ast_bucket_file_metadata_get(), ast_bucket_file_metadata_set(), AST_TIME_T_LEN, ast_time_t_to_string(), ast_tvnow(), and ast_bucket_metadata::value.

Referenced by bucket_file_run_curl(), and bucket_http_wizard_is_stale().

◆ bucket_file_set_extension()

static void bucket_file_set_extension ( struct ast_bucket_file bucket_file)
static

Definition at line 453 of file res_http_media_cache.c.

454{
455 /* Using Content-Type first allows for the most flexibility for whomever
456 * is serving up the audio file. If that doesn't turn up anything useful
457 * we'll try to parse the URL and use the extension */
458
459 char buffer[64];
460
461 if (file_extension_from_content_type(bucket_file, buffer, sizeof(buffer))
462 || file_extension_from_url_path(bucket_file, buffer, sizeof(buffer))) {
463 ast_bucket_file_metadata_set(bucket_file, "ext", buffer);
464 }
465}
static char * file_extension_from_content_type(struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)
static char * file_extension_from_url_path(struct ast_bucket_file *bucket_file, char *buffer, size_t capacity)

References ast_bucket_file_metadata_set(), file_extension_from_content_type(), and file_extension_from_url_path().

Referenced by bucket_file_run_curl().

◆ bucket_http_wizard_create()

static int bucket_http_wizard_create ( const struct ast_sorcery sorcery,
void *  data,
void *  object 
)
static

Definition at line 678 of file res_http_media_cache.c.

680{
681 struct ast_bucket_file *bucket_file = object;
682
683 return bucket_file_run_curl(bucket_file);
684}
static int bucket_file_run_curl(struct ast_bucket_file *bucket_file)
Bucket file structure, contains reference to file and information about it.
Definition: bucket.h:78

References bucket_file_run_curl().

◆ bucket_http_wizard_delete()

static int bucket_http_wizard_delete ( const struct ast_sorcery sorcery,
void *  data,
void *  object 
)
static

Definition at line 723 of file res_http_media_cache.c.

725{
726 struct ast_bucket_file *bucket_file = object;
727
728 unlink(bucket_file->path);
729
730 return 0;
731}

References ast_bucket_file::path.

◆ bucket_http_wizard_is_stale()

static int bucket_http_wizard_is_stale ( const struct ast_sorcery sorcery,
void *  data,
void *  object 
)
static

Definition at line 635 of file res_http_media_cache.c.

636{
637 struct ast_bucket_file *bucket_file = object;
638 struct ast_bucket_metadata *metadata;
639 struct curl_slist *header_list = NULL;
640 long http_code;
641 CURL *curl;
642 struct curl_bucket_file_data cb_data = {
644 };
645 char etag_buf[256];
646
648 return 0;
649 }
650
651 /* See if we have an ETag for this item. If not, it's stale. */
652 metadata = ast_bucket_file_metadata_get(bucket_file, "etag");
653 if (!metadata) {
654 return 1;
655 }
656
657 curl = get_curl_instance(&cb_data);
658
659 /* Set the ETag header on our outgoing request */
660 snprintf(etag_buf, sizeof(etag_buf), "If-None-Match: %s", metadata->value);
661 header_list = curl_slist_append(header_list, etag_buf);
662 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
663 curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
664 ao2_ref(metadata, -1);
665
666 http_code = execute_curl_instance(curl);
667
668 curl_slist_free_all(header_list);
669
670 if (http_code == 304) {
672 return 0;
673 }
674
675 return 1;
676}
static int bucket_file_expired(struct ast_bucket_file *bucket_file)
static int bucket_file_always_revalidate(struct ast_bucket_file *bucket_file)
#define NULL
Definition: resample.c:96

References ao2_ref, ast_bucket_file_metadata_get(), curl_bucket_file_data::bucket_file, bucket_file_always_revalidate(), bucket_file_expired(), bucket_file_set_expiration(), execute_curl_instance(), get_curl_instance(), NULL, and ast_bucket_metadata::value.

◆ bucket_http_wizard_retrieve_id()

static void * bucket_http_wizard_retrieve_id ( const struct ast_sorcery sorcery,
void *  data,
const char *  type,
const char *  id 
)
static

Definition at line 686 of file res_http_media_cache.c.

688{
689 struct ast_bucket_file *bucket_file;
690
691 if (strcmp(type, "file")) {
692 ast_log(LOG_WARNING, "Failed to create storage: invalid bucket type '%s'\n", type);
693 return NULL;
694 }
695
696 if (ast_strlen_zero(id)) {
697 ast_log(LOG_WARNING, "Failed to create storage: no URI\n");
698 return NULL;
699 }
700
701 bucket_file = ast_bucket_file_alloc(id);
702 if (!bucket_file) {
703 ast_log(LOG_WARNING, "Failed to create storage for '%s'\n", id);
704 return NULL;
705 }
706
707 if (ast_bucket_file_temporary_create(bucket_file)) {
708 ast_log(LOG_WARNING, "Failed to create temporary storage for '%s'\n", id);
709 ast_sorcery_delete(sorcery, bucket_file);
710 ao2_ref(bucket_file, -1);
711 return NULL;
712 }
713
714 if (bucket_file_run_curl(bucket_file)) {
715 ast_sorcery_delete(sorcery, bucket_file);
716 ao2_ref(bucket_file, -1);
717 return NULL;
718 }
719
720 return bucket_file;
721}
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
Definition: bucket.c:633
int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
Common file snapshot creation callback for creating a temporary file.
Definition: bucket.c:869
static const char type[]
Definition: chan_ooh323.c:109
static struct ast_sorcery * sorcery
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

References ao2_ref, ast_bucket_file_alloc(), ast_bucket_file_temporary_create(), ast_log, ast_sorcery_delete(), ast_strlen_zero(), bucket_file_run_curl(), LOG_WARNING, NULL, sorcery, and type.

◆ conf_alloc()

static void * conf_alloc ( void  )
static

Creates the http media cache conf object.

Definition at line 177 of file res_http_media_cache.c.

178{
179 struct conf *cfg;
180
181 if (!(cfg = ao2_alloc(sizeof(*cfg), conf_destructor))) {
182 return NULL;
183 }
184
185 if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), NULL))) {
186 ao2_ref(cfg, -1);
187 return NULL;
188 }
189
190 if (ast_string_field_init(cfg->general, 256)) {
191 ao2_ref(cfg, -1);
192 return NULL;
193 }
194
195 return cfg;
196}
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static void conf_destructor(void *obj)
Disposes of the http media cache conf object.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
All configuration options for http media cache.
struct conf_general_options * general

References ao2_alloc, ao2_ref, ast_string_field_init, conf_destructor(), conf::general, and NULL.

Referenced by load_module().

◆ conf_destructor()

static void conf_destructor ( void *  obj)
static

Disposes of the http media cache conf object.

Definition at line 169 of file res_http_media_cache.c.

170{
171 struct conf *cfg = obj;
173 ao2_cleanup(cfg->general);
174}
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

References ao2_cleanup, ast_string_field_free_memory, and conf::general.

Referenced by conf_alloc().

◆ CONFIG_INFO_STANDARD()

CONFIG_INFO_STANDARD ( cfg_info  ,
confs  ,
conf_alloc  ,
pre_apply_config = http_media_cache_config_pre_apply,
files = ACO_FILES(&conf_file) 
)

◆ curl_body_callback()

static size_t curl_body_callback ( void *  ptr,
size_t  size,
size_t  nitems,
void *  data 
)
static

Definition at line 291 of file res_http_media_cache.c.

292{
293 struct curl_bucket_file_data *cb_data = data;
294 size_t realsize;
295
296 realsize = fwrite(ptr, size, nitems, cb_data->out_file);
297
298 return realsize;
299}

References curl_bucket_file_data::out_file.

Referenced by bucket_file_run_curl().

◆ curl_header_callback()

static size_t curl_header_callback ( char *  buffer,
size_t  size,
size_t  nitems,
void *  data 
)
static

Definition at line 246 of file res_http_media_cache.c.

247{
248 struct curl_bucket_file_data *cb_data = data;
249 size_t realsize;
250 char *value;
251 char *header;
252
253 realsize = size * nitems;
254
255 if (realsize > MAX_HEADER_LENGTH) {
256 ast_log(LOG_WARNING, "cURL header length of '%zu' is too large: max %d\n",
257 realsize, MAX_HEADER_LENGTH);
258 return 0;
259 }
260
261 /* buffer may not be NULL terminated */
262 header = ast_alloca(realsize + 1);
263 memcpy(header, buffer, realsize);
264 header[realsize] = '\0';
265 value = strchr(header, ':');
266 if (!value) {
267 /* Not a header we care about; bail */
268 return realsize;
269 }
270 *value++ = '\0';
271
272 if (strcasecmp(header, "ETag")
273 && strcasecmp(header, "Cache-Control")
274 && strcasecmp(header, "Last-Modified")
275 && strcasecmp(header, "Content-Type")
276 && strcasecmp(header, "Expires")) {
277 return realsize;
278 }
279
282
284
285 return realsize;
286}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define MAX_HEADER_LENGTH
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1321
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition: strings.h:186
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
int value
Definition: syslog.c:37

References ast_alloca, ast_bucket_file_metadata_set(), ast_log, ast_skip_blanks(), ast_str_to_lower(), ast_trim_blanks(), curl_bucket_file_data::bucket_file, LOG_WARNING, MAX_HEADER_LENGTH, and value.

Referenced by get_curl_instance().

◆ derive_extension_from_mime_type()

static int derive_extension_from_mime_type ( const char *  mime_type,
char *  buffer,
size_t  capacity 
)
static

Definition at line 384 of file res_http_media_cache.c.

385{
386 int res = 0;
387
388 /* Compare the provided Content-Type directly, parameters and all */
389 res = ast_get_extension_for_mime_type(mime_type, buffer, sizeof(buffer));
390 if (!res) {
391 char *m = ast_strdupa(mime_type);
392 /* Strip MIME type parameters and then check */
394 res = ast_get_extension_for_mime_type(m, buffer, sizeof(buffer));
395 }
396 }
397
398 return res;
399}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ast_get_extension_for_mime_type(const char *mime_type, char *buffer, size_t capacity)
Get a suitable filename extension for the given MIME type.
Definition: file.c:2027
static int normalize_content_type_header(char *content_type)

References ast_get_extension_for_mime_type(), ast_strdupa, and normalize_content_type_header().

Referenced by file_extension_from_content_type().

◆ execute_curl_instance()

static long execute_curl_instance ( CURL *  curl)
static

Execute the CURL.

Definition at line 572 of file res_http_media_cache.c.

573{
574 char curl_errbuf[CURL_ERROR_SIZE + 1];
575 long http_code;
576
577 curl_errbuf[CURL_ERROR_SIZE] = '\0';
578 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
579
580 if (curl_easy_perform(curl)) {
581 ast_log(LOG_WARNING, "%s\n", curl_errbuf);
582 return -1;
583 }
584
585 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
586
587 curl_easy_cleanup(curl);
588
589 return http_code;
590}

References ast_log, and LOG_WARNING.

Referenced by bucket_file_run_curl(), and bucket_http_wizard_is_stale().

◆ file_extension_from_content_type()

static char * file_extension_from_content_type ( struct ast_bucket_file bucket_file,
char *  buffer,
size_t  capacity 
)
static

Definition at line 401 of file res_http_media_cache.c.

402{
403 /* Check for the extension based on the MIME type passed in the Content-Type
404 * header.
405 *
406 * If a match is found then retrieve the extension from the supported list
407 * corresponding to the mime-type and use that to rename the file */
408
410
411 header = ast_bucket_file_metadata_get(bucket_file, "content-type");
412 if (!header) {
413 return NULL;
414 }
415
416 if (derive_extension_from_mime_type(header->value, buffer, capacity)) {
417 ast_debug(3, "Derived extension '%s' from MIME type %s\n",
418 buffer,
419 header->value);
420 ao2_ref(header, -1);
421 return buffer;
422 }
423
424 ao2_ref(header, -1);
425
426 return NULL;
427}
#define ast_debug(level,...)
Log a DEBUG message.
static int derive_extension_from_mime_type(const char *mime_type, char *buffer, size_t capacity)
const ast_string_field value

References ao2_ref, ast_bucket_file_metadata_get(), ast_debug, derive_extension_from_mime_type(), NULL, and header::value.

Referenced by bucket_file_set_extension().

◆ file_extension_from_string()

static char * file_extension_from_string ( const char *  str,
char *  buffer,
size_t  capacity 
)
static

Definition at line 347 of file res_http_media_cache.c.

348{
349 const char *ext;
350
351 ext = strrchr(str, '.');
352 if (ext && ast_get_format_for_file_ext(ext + 1)) {
353 ast_debug(3, "Found extension '%s' at end of string\n", ext);
354 ast_copy_string(buffer, ext, capacity);
355 return buffer;
356 }
357
358 return NULL;
359}
const char * str
Definition: app_jack.c:150
struct ast_format * ast_get_format_for_file_ext(const char *file_ext)
Get the ast_format associated with the given file extension.
Definition: file.c:2014
const char * ext
Definition: http.c:150
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425

References ast_copy_string(), ast_debug, ast_get_format_for_file_ext(), ext, NULL, and str.

Referenced by file_extension_from_url_path().

◆ file_extension_from_url_path()

static char * file_extension_from_url_path ( struct ast_bucket_file bucket_file,
char *  buffer,
size_t  capacity 
)
static

Definition at line 429 of file res_http_media_cache.c.

430{
431 const char *path;
432 struct ast_uri *uri;
433
435 if (!uri) {
436 ast_log(LOG_ERROR, "Failed to parse URI: %s\n",
437 ast_sorcery_object_get_id(bucket_file));
438 return NULL;
439 }
440
442 if (!path) {
444 return NULL;
445 }
446
447 /* Just parse it as a string like before, but without the extra cruft */
448 buffer = file_extension_from_string(path, buffer, capacity);
450 return buffer;
451}
#define LOG_ERROR
static char * file_extension_from_string(const char *str, char *buffer, size_t capacity)
Stores parsed uri information.
Definition: uri.c:30
char * path
Definition: uri.c:40
char uri[0]
Definition: uri.c:44
const char * ast_uri_path(const struct ast_uri *uri)
Retrieve the uri path.
Definition: uri.c:135
struct ast_uri * ast_uri_parse(const char *uri)
Parse the given uri into a structure.
Definition: uri.c:195

References ao2_cleanup, ast_log, ast_sorcery_object_get_id(), ast_uri_parse(), ast_uri_path(), file_extension_from_string(), LOG_ERROR, NULL, ast_uri::path, and ast_uri::uri.

Referenced by bucket_file_set_extension().

◆ get_curl_instance()

static CURL * get_curl_instance ( struct curl_bucket_file_data cb_data)
static

Definition at line 513 of file res_http_media_cache.c.

514{
516 CURLcode rc;
517 CURL *curl;
518
519 curl = curl_easy_init();
520 if (!curl) {
521 return NULL;
522 }
523
524 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
525 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header_callback);
526 curl_easy_setopt(curl, CURLOPT_URL, ast_sorcery_object_get_id(cb_data->bucket_file));
527 curl_easy_setopt(curl, CURLOPT_HEADERDATA, cb_data);
528
529 curl_easy_setopt(curl, CURLOPT_TIMEOUT, cfg->general->curl_timeout);
530 curl_easy_setopt(curl, CURLOPT_USERAGENT, cfg->general->curl_useragent);
531 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, cfg->general->curl_followlocation ? 1 : 0);
532 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, cfg->general->curl_maxredirs);
533
534 if (!ast_strlen_zero(cfg->general->curl_proxy)) {
535 curl_easy_setopt(curl, CURLOPT_PROXY, cfg->general->curl_proxy);
536 }
537
538 if (!ast_strlen_zero(cfg->general->curl_protocols)) {
539#ifdef AST_CURL_HAS_PROTOCOLS_STR
540 CURLcode rc = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, cfg->general->curl_protocols);
541 if (rc != CURLE_OK) {
542 ast_log(AST_LOG_ERROR, "Setting protocols to '%s' failed: %d\n", cfg->general->curl_protocols, rc);
543 curl_easy_cleanup(curl);
544 return NULL;
545 }
546#endif
547 }
548 if (!ast_strlen_zero(cfg->general->curl_redir_protocols)) {
549#ifdef AST_CURL_HAS_PROTOCOLS_STR
550 CURLcode rc = curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, cfg->general->curl_redir_protocols);
551 if (rc != CURLE_OK) {
552 ast_log(AST_LOG_ERROR, "Setting redirect_protocols to '%s' failed: %d\n", cfg->general->curl_redir_protocols, rc);
553 curl_easy_cleanup(curl);
554 return NULL;
555 }
556#endif
557 }
558
559 rc = curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, cfg->general->curl_dns_cache_timeout);
560 if (rc != CURLE_OK) {
561 ast_log(AST_LOG_ERROR, "Setting dns_cache_timeout to '%d' failed: %d\n", cfg->general->curl_dns_cache_timeout, rc);
562 curl_easy_cleanup(curl);
563 return NULL;
564 }
565
566 return curl;
567}
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define AST_LOG_ERROR
static size_t curl_header_callback(char *buffer, size_t size, size_t nitems, void *data)

References ao2_cleanup, ao2_global_obj_ref, ast_log, AST_LOG_ERROR, ast_sorcery_object_get_id(), ast_strlen_zero(), curl_bucket_file_data::bucket_file, curl_header_callback(), NULL, and RAII_VAR.

Referenced by bucket_file_run_curl(), and bucket_http_wizard_is_stale().

◆ http_media_cache_config_pre_apply()

static int http_media_cache_config_pre_apply ( void  )
static

Pre-apply callback for the config framework.

This validates that used options match the ones supported by CURL.

Definition at line 215 of file res_http_media_cache.c.

216{
217#ifndef AST_CURL_HAS_PROTOCOLS_STR
218 struct conf *cfg = aco_pending_config(&cfg_info);
219
221 ast_log(AST_LOG_ERROR, "'protocols' not supported by linked CURL library. Please recompile against newer CURL.\n");
222 return -1;
223 }
224
226 ast_log(AST_LOG_ERROR, "'redirect_protocols' not supported by linked CURL library. Please recompile against newer CURL.\n");
227 return -1;
228 }
229#endif
230
231 return 0;
232}
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
const ast_string_field curl_protocols
const ast_string_field curl_redir_protocols

References aco_pending_config(), ast_log, AST_LOG_ERROR, ast_strlen_zero(), conf_general_options::curl_protocols, conf_general_options::curl_redir_protocols, and conf::general.

◆ load_module()

static int load_module ( void  )
static

Definition at line 772 of file res_http_media_cache.c.

773{
774 if (aco_info_init(&cfg_info)) {
775 aco_info_destroy(&cfg_info);
777 }
778
779
780 aco_option_register(&cfg_info, "timeout_secs", ACO_EXACT, general_options,
781 "180", OPT_INT_T, 0,
782 FLDSET(struct conf_general_options, curl_timeout));
783
784 aco_option_register(&cfg_info, "user_agent", ACO_EXACT, general_options,
786 STRFLDSET(struct conf_general_options, curl_useragent));
787
788 aco_option_register(&cfg_info, "follow_location", ACO_EXACT, general_options,
789 "yes", OPT_BOOL_T, 1,
790 FLDSET(struct conf_general_options, curl_followlocation));
791
792 aco_option_register(&cfg_info, "max_redirects", ACO_EXACT, general_options,
793 "8", OPT_INT_T, 0,
794 FLDSET(struct conf_general_options, curl_maxredirs));
795
796 aco_option_register(&cfg_info, "proxy", ACO_EXACT, general_options,
798 STRFLDSET(struct conf_general_options, curl_proxy));
799
800 aco_option_register(&cfg_info, "dns_cache_timeout_secs", ACO_EXACT, general_options,
801 "60", OPT_INT_T, 0,
802 FLDSET(struct conf_general_options, curl_dns_cache_timeout));
803
804 aco_option_register(&cfg_info, "protocols", ACO_EXACT, general_options,
806 STRFLDSET(struct conf_general_options, curl_protocols));
807
808 aco_option_register(&cfg_info, "redirect_protocols", ACO_EXACT, general_options,
810 STRFLDSET(struct conf_general_options, curl_redir_protocols));
811
812
813 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
814 struct conf *cfg;
815
816 ast_log(LOG_NOTICE, "Could not load res_http_media_cache config; using defaults\n");
817 cfg = conf_alloc();
818 if (!cfg) {
819 aco_info_destroy(&cfg_info);
821 }
822
823 if (aco_set_defaults(&general_option, "general", cfg->general)) {
824 ast_log(LOG_ERROR, "Failed to initialize res_http_media_cache defaults.\n");
825 ao2_ref(cfg, -1);
826 aco_info_destroy(&cfg_info);
828 }
829
831 ao2_ref(cfg, -1);
832 }
833
835 NULL, NULL)) {
836 ast_log(LOG_ERROR, "Failed to register Bucket HTTP wizard scheme implementation\n");
838 }
839
841 NULL, NULL)) {
842 ast_log(LOG_ERROR, "Failed to register Bucket HTTPS wizard scheme implementation\n");
844 }
845
847}
#define AST_CURL_USER_AGENT
Definition: asterisk.h:44
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb)
Register support for a specific scheme.
Definition: bucket.h:137
@ ACO_EXACT
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_INT_T
Type for default option handler for signed integers.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define LOG_NOTICE
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static void * conf_alloc(void)
Creates the http media cache conf object.
static struct aco_type general_option
Mapping of the http media cache conf struct's general to the general context in the config file.
static struct ast_sorcery_wizard http_bucket_wizard
static struct aco_type * general_options[]
static struct ast_sorcery_wizard http_bucket_file_wizard
static struct ast_sorcery_wizard https_bucket_wizard
static struct ast_sorcery_wizard https_bucket_file_wizard
General configuration options for http media cache.

References ACO_EXACT, aco_info_destroy(), aco_info_init(), aco_option_register, aco_process_config(), ACO_PROCESS_ERROR, aco_set_defaults(), ao2_global_obj_replace_unref, ao2_ref, ast_bucket_scheme_register, AST_CURL_USER_AGENT, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, conf_alloc(), FLDSET, conf::general, general_option, general_options, http_bucket_file_wizard, http_bucket_wizard, https_bucket_file_wizard, https_bucket_wizard, LOG_ERROR, LOG_NOTICE, NULL, OPT_BOOL_T, OPT_INT_T, OPT_STRINGFIELD_T, and STRFLDSET.

◆ normalize_content_type_header()

static int normalize_content_type_header ( char *  content_type)
static

Definition at line 369 of file res_http_media_cache.c.

370{
371 char *params = strchr(content_type, ';');
372
373 if (params) {
374 *params-- = 0;
375 while (params > content_type && (*params == ' ' || *params == '\t')) {
376 *params-- = 0;
377 }
378 return 1;
379 }
380
381 return 0;
382}

Referenced by derive_extension_from_mime_type().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 765 of file res_http_media_cache.c.

766{
767 aco_info_destroy(&cfg_info);
769 return 0;
770}
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859

References aco_info_destroy(), and ao2_global_obj_release.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "HTTP Media Cache Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .requires = "res_curl", }
static

Definition at line 854 of file res_http_media_cache.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 854 of file res_http_media_cache.c.

◆ conf_file

struct aco_file conf_file
static

The conf file that's processed for the module.

Definition at line 199 of file res_http_media_cache.c.

◆ general_option

struct aco_type general_option
static

Mapping of the http media cache conf struct's general to the general context in the config file.

Definition at line 158 of file res_http_media_cache.c.

Referenced by load_module().

◆ general_options

struct aco_type* general_options[] = ACO_TYPES(&general_option)
static

Definition at line 166 of file res_http_media_cache.c.

Referenced by load_module().

◆ http_bucket_file_wizard

struct ast_sorcery_wizard http_bucket_file_wizard
static

Definition at line 741 of file res_http_media_cache.c.

Referenced by load_module().

◆ http_bucket_wizard

struct ast_sorcery_wizard http_bucket_wizard
static

Definition at line 733 of file res_http_media_cache.c.

Referenced by load_module().

◆ https_bucket_file_wizard

struct ast_sorcery_wizard https_bucket_file_wizard
static

Definition at line 757 of file res_http_media_cache.c.

Referenced by load_module().

◆ https_bucket_wizard

struct ast_sorcery_wizard https_bucket_wizard
static

Definition at line 749 of file res_http_media_cache.c.

Referenced by load_module().