Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
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.
 
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.
 
static void conf_destructor (void *obj)
 Disposes of the http media cache conf object.
 
 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.
 
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.
 
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 = ASTERISK_GPL_KEY , .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.
 
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 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:981

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 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:2381
char path[PATH_MAX]
Local path to this file.
Definition bucket.h:95
Data passed to cURL callbacks.
struct ast_bucket_file * bucket_file
static CURL * get_curl_instance(void)

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[]
static struct ast_sorcery * sorcery
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition sorcery.c:2302
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.
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

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 *attribute_pure 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:2053
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:2040
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.

◆ 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 = ASTERISK_GPL_KEY , .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.

199 {
200 /*! The config file name. */
201 .filename = "res_http_media_cache.conf",
202 /*! The mapping object types to be processed. */
203 .types = ACO_TYPES(&general_option),
204};
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.

◆ 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.

158 {
159 .type = ACO_GLOBAL,
160 .name = "general",
161 .item_offset = offsetof(struct conf, general),
162 .category = "general",
163 .category_match = ACO_WHITELIST_EXACT,
164};
@ ACO_GLOBAL
@ ACO_WHITELIST_EXACT

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.

741 {
742 .name = "http",
744 .retrieve_id = bucket_http_wizard_retrieve_id,
746 .is_stale = bucket_http_wizard_is_stale,
747};
static int bucket_http_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
static int bucket_http_wizard_create(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 int bucket_http_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)

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.

733 {
734 .name = "http",
736 .retrieve_id = bucket_http_wizard_retrieve_id,
738 .is_stale = bucket_http_wizard_is_stale,
739};

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.

757 {
758 .name = "https",
760 .retrieve_id = bucket_http_wizard_retrieve_id,
762 .is_stale = bucket_http_wizard_is_stale,
763};

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.

749 {
750 .name = "https",
752 .retrieve_id = bucket_http_wizard_retrieve_id,
754 .is_stale = bucket_http_wizard_is_stale,
755};

Referenced by load_module().