Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 80 of file res_http_media_cache.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 818 of file res_http_media_cache.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 818 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 818 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 434 of file res_http_media_cache.c.

435{
436 RAII_VAR(struct ast_bucket_metadata *, metadata,
437 ast_bucket_file_metadata_get(bucket_file, "cache-control"),
439
440 if (!metadata) {
441 return 0;
442 }
443
444 if (strstr(metadata->value, "no-cache")
445 || strstr(metadata->value, "must-revalidate")) {
446 return 1;
447 }
448
449 return 0;
450}
#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:359
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 455 of file res_http_media_cache.c.

456{
457 RAII_VAR(struct ast_bucket_metadata *, metadata,
458 ast_bucket_file_metadata_get(bucket_file, "__actual_expires"),
460 struct timeval current_time = ast_tvnow();
461 struct timeval expires = { .tv_sec = 0, .tv_usec = 0 };
462
463 if (!metadata) {
464 return 1;
465 }
466
467 if ((expires.tv_sec = ast_string_to_time_t(metadata->value)) == -1) {
468 return 1;
469 }
470
471 return ast_tvcmp(current_time, expires) == -1 ? 0 : 1;
472}
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 559 of file res_http_media_cache.c.

560{
561 struct curl_bucket_file_data cb_data = {
563 };
564 long http_code;
565 CURL *curl;
566
567 cb_data.out_file = fopen(bucket_file->path, "wb");
568 if (!cb_data.out_file) {
569 ast_log(LOG_WARNING, "Failed to open file '%s' for writing: %s (%d)\n",
570 bucket_file->path, strerror(errno), errno);
571 return -1;
572 }
573
574 curl = get_curl_instance(&cb_data);
575 if (!curl) {
576 fclose(cb_data.out_file);
577 return -1;
578 }
579
580 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_callback);
581 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&cb_data);
582
583 http_code = execute_curl_instance(curl);
584
585 fclose(cb_data.out_file);
586
587 if (http_code / 100 == 2) {
590 return 0;
591 } else {
592 ast_log(LOG_WARNING, "Failed to retrieve URL '%s': server returned %ld\n",
594 }
595
596 return -1;
597}
#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 268 of file res_http_media_cache.c.

269{
270 struct ast_bucket_metadata *metadata;
271 char time_buf[32], secs[AST_TIME_T_LEN];
272 struct timeval actual_expires = ast_tvnow();
273
274 metadata = ast_bucket_file_metadata_get(bucket_file, "cache-control");
275 if (metadata) {
276 char *str_max_age;
277
278 str_max_age = strstr(metadata->value, "s-maxage");
279 if (!str_max_age) {
280 str_max_age = strstr(metadata->value, "max-age");
281 }
282
283 if (str_max_age) {
284 unsigned int max_age;
285 char *equal = strchr(str_max_age, '=');
286 if (equal && (sscanf(equal + 1, "%30u", &max_age) == 1)) {
287 actual_expires.tv_sec += max_age;
288 }
289 }
290 ao2_ref(metadata, -1);
291 } else {
292 metadata = ast_bucket_file_metadata_get(bucket_file, "expires");
293 if (metadata) {
294 struct tm expires_time;
295
296 strptime(metadata->value, "%a, %d %b %Y %T %z", &expires_time);
297 expires_time.tm_isdst = -1;
298 actual_expires.tv_sec = mktime(&expires_time);
299
300 ao2_ref(metadata, -1);
301 }
302 }
303
304 /* Use 'now' if we didn't get an expiration time */
305 ast_time_t_to_string(actual_expires.tv_sec, secs, sizeof(secs));
306 snprintf(time_buf, sizeof(time_buf), "%30s", secs);
307
308 ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf);
309}
#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:334
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 417 of file res_http_media_cache.c.

418{
419 /* Using Content-Type first allows for the most flexibility for whomever
420 * is serving up the audio file. If that doesn't turn up anything useful
421 * we'll try to parse the URL and use the extension */
422
423 char buffer[64];
424
425 if (file_extension_from_content_type(bucket_file, buffer, sizeof(buffer))
426 || file_extension_from_url_path(bucket_file, buffer, sizeof(buffer))) {
427 ast_bucket_file_metadata_set(bucket_file, "ext", buffer);
428 }
429}
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 642 of file res_http_media_cache.c.

644{
645 struct ast_bucket_file *bucket_file = object;
646
647 return bucket_file_run_curl(bucket_file);
648}
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 687 of file res_http_media_cache.c.

689{
690 struct ast_bucket_file *bucket_file = object;
691
692 unlink(bucket_file->path);
693
694 return 0;
695}

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 599 of file res_http_media_cache.c.

600{
601 struct ast_bucket_file *bucket_file = object;
602 struct ast_bucket_metadata *metadata;
603 struct curl_slist *header_list = NULL;
604 long http_code;
605 CURL *curl;
606 struct curl_bucket_file_data cb_data = {
608 };
609 char etag_buf[256];
610
612 return 0;
613 }
614
615 /* See if we have an ETag for this item. If not, it's stale. */
616 metadata = ast_bucket_file_metadata_get(bucket_file, "etag");
617 if (!metadata) {
618 return 1;
619 }
620
621 curl = get_curl_instance(&cb_data);
622
623 /* Set the ETag header on our outgoing request */
624 snprintf(etag_buf, sizeof(etag_buf), "If-None-Match: %s", metadata->value);
625 header_list = curl_slist_append(header_list, etag_buf);
626 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
627 curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
628 ao2_ref(metadata, -1);
629
630 http_code = execute_curl_instance(curl);
631
632 curl_slist_free_all(header_list);
633
634 if (http_code == 304) {
636 return 0;
637 }
638
639 return 1;
640}
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 650 of file res_http_media_cache.c.

652{
653 struct ast_bucket_file *bucket_file;
654
655 if (strcmp(type, "file")) {
656 ast_log(LOG_WARNING, "Failed to create storage: invalid bucket type '%s'\n", type);
657 return NULL;
658 }
659
660 if (ast_strlen_zero(id)) {
661 ast_log(LOG_WARNING, "Failed to create storage: no URI\n");
662 return NULL;
663 }
664
665 bucket_file = ast_bucket_file_alloc(id);
666 if (!bucket_file) {
667 ast_log(LOG_WARNING, "Failed to create storage for '%s'\n", id);
668 return NULL;
669 }
670
671 if (ast_bucket_file_temporary_create(bucket_file)) {
672 ast_log(LOG_WARNING, "Failed to create temporary storage for '%s'\n", id);
673 ast_sorcery_delete(sorcery, bucket_file);
674 ao2_ref(bucket_file, -1);
675 return NULL;
676 }
677
678 if (bucket_file_run_curl(bucket_file)) {
679 ast_sorcery_delete(sorcery, bucket_file);
680 ao2_ref(bucket_file, -1);
681 return NULL;
682 }
683
684 return bucket_file;
685}
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
Definition: bucket.c:663
int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
Common file snapshot creation callback for creating a temporary file.
Definition: bucket.c:899
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 141 of file res_http_media_cache.c.

142{
143 struct conf *cfg;
144
145 if (!(cfg = ao2_alloc(sizeof(*cfg), conf_destructor))) {
146 return NULL;
147 }
148
149 if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), NULL))) {
150 ao2_ref(cfg, -1);
151 return NULL;
152 }
153
154 if (ast_string_field_init(cfg->general, 256)) {
155 ao2_ref(cfg, -1);
156 return NULL;
157 }
158
159 return cfg;
160}
#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 133 of file res_http_media_cache.c.

134{
135 struct conf *cfg = obj;
137 ao2_cleanup(cfg->general);
138}
#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 255 of file res_http_media_cache.c.

256{
257 struct curl_bucket_file_data *cb_data = data;
258 size_t realsize;
259
260 realsize = fwrite(ptr, size, nitems, cb_data->out_file);
261
262 return realsize;
263}

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 210 of file res_http_media_cache.c.

211{
212 struct curl_bucket_file_data *cb_data = data;
213 size_t realsize;
214 char *value;
215 char *header;
216
217 realsize = size * nitems;
218
219 if (realsize > MAX_HEADER_LENGTH) {
220 ast_log(LOG_WARNING, "cURL header length of '%zu' is too large: max %d\n",
221 realsize, MAX_HEADER_LENGTH);
222 return 0;
223 }
224
225 /* buffer may not be NULL terminated */
226 header = ast_alloca(realsize + 1);
227 memcpy(header, buffer, realsize);
228 header[realsize] = '\0';
229 value = strchr(header, ':');
230 if (!value) {
231 /* Not a header we care about; bail */
232 return realsize;
233 }
234 *value++ = '\0';
235
236 if (strcasecmp(header, "ETag")
237 && strcasecmp(header, "Cache-Control")
238 && strcasecmp(header, "Last-Modified")
239 && strcasecmp(header, "Content-Type")
240 && strcasecmp(header, "Expires")) {
241 return realsize;
242 }
243
246
248
249 return realsize;
250}
#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 348 of file res_http_media_cache.c.

349{
350 int res = 0;
351
352 /* Compare the provided Content-Type directly, parameters and all */
353 res = ast_get_extension_for_mime_type(mime_type, buffer, sizeof(buffer));
354 if (!res) {
355 char *m = ast_strdupa(mime_type);
356 /* Strip MIME type parameters and then check */
358 res = ast_get_extension_for_mime_type(m, buffer, sizeof(buffer));
359 }
360 }
361
362 return res;
363}
#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:2019
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 536 of file res_http_media_cache.c.

537{
538 char curl_errbuf[CURL_ERROR_SIZE + 1];
539 long http_code;
540
541 curl_errbuf[CURL_ERROR_SIZE] = '\0';
542 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
543
544 if (curl_easy_perform(curl)) {
545 ast_log(LOG_WARNING, "%s\n", curl_errbuf);
546 return -1;
547 }
548
549 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
550
551 curl_easy_cleanup(curl);
552
553 return http_code;
554}

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 365 of file res_http_media_cache.c.

366{
367 /* Check for the extension based on the MIME type passed in the Content-Type
368 * header.
369 *
370 * If a match is found then retrieve the extension from the supported list
371 * corresponding to the mime-type and use that to rename the file */
372
374
375 header = ast_bucket_file_metadata_get(bucket_file, "content-type");
376 if (!header) {
377 return NULL;
378 }
379
380 if (derive_extension_from_mime_type(header->value, buffer, capacity)) {
381 ast_debug(3, "Derived extension '%s' from MIME type %s\n",
382 buffer,
383 header->value);
384 ao2_ref(header, -1);
385 return buffer;
386 }
387
388 ao2_ref(header, -1);
389
390 return NULL;
391}
#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 311 of file res_http_media_cache.c.

312{
313 const char *ext;
314
315 ext = strrchr(str, '.');
316 if (ext && ast_get_format_for_file_ext(ext + 1)) {
317 ast_debug(3, "Found extension '%s' at end of string\n", ext);
318 ast_copy_string(buffer, ext, capacity);
319 return buffer;
320 }
321
322 return NULL;
323}
const char * str
Definition: app_jack.c:147
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:2006
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 393 of file res_http_media_cache.c.

394{
395 const char *path;
396 struct ast_uri *uri;
397
399 if (!uri) {
400 ast_log(LOG_ERROR, "Failed to parse URI: %s\n",
401 ast_sorcery_object_get_id(bucket_file));
402 return NULL;
403 }
404
406 if (!path) {
408 return NULL;
409 }
410
411 /* Just parse it as a string like before, but without the extra cruft */
412 buffer = file_extension_from_string(path, buffer, capacity);
414 return buffer;
415}
#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 477 of file res_http_media_cache.c.

478{
480 CURLcode rc;
481 CURL *curl;
482
483 curl = curl_easy_init();
484 if (!curl) {
485 return NULL;
486 }
487
488 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
489 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header_callback);
490 curl_easy_setopt(curl, CURLOPT_URL, ast_sorcery_object_get_id(cb_data->bucket_file));
491 curl_easy_setopt(curl, CURLOPT_HEADERDATA, cb_data);
492
493 curl_easy_setopt(curl, CURLOPT_TIMEOUT, cfg->general->curl_timeout);
494 curl_easy_setopt(curl, CURLOPT_USERAGENT, cfg->general->curl_useragent);
495 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, cfg->general->curl_followlocation ? 1 : 0);
496 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, cfg->general->curl_maxredirs);
497
498 if (!ast_strlen_zero(cfg->general->curl_proxy)) {
499 curl_easy_setopt(curl, CURLOPT_PROXY, cfg->general->curl_proxy);
500 }
501
502 if (!ast_strlen_zero(cfg->general->curl_protocols)) {
503#ifdef AST_CURL_HAS_PROTOCOLS_STR
504 CURLcode rc = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, cfg->general->curl_protocols);
505 if (rc != CURLE_OK) {
506 ast_log(AST_LOG_ERROR, "Setting protocols to '%s' failed: %d\n", cfg->general->curl_protocols, rc);
507 curl_easy_cleanup(curl);
508 return NULL;
509 }
510#endif
511 }
512 if (!ast_strlen_zero(cfg->general->curl_redir_protocols)) {
513#ifdef AST_CURL_HAS_PROTOCOLS_STR
514 CURLcode rc = curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, cfg->general->curl_redir_protocols);
515 if (rc != CURLE_OK) {
516 ast_log(AST_LOG_ERROR, "Setting redirect_protocols to '%s' failed: %d\n", cfg->general->curl_redir_protocols, rc);
517 curl_easy_cleanup(curl);
518 return NULL;
519 }
520#endif
521 }
522
523 rc = curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, cfg->general->curl_dns_cache_timeout);
524 if (rc != CURLE_OK) {
525 ast_log(AST_LOG_ERROR, "Setting dns_cache_timeout to '%d' failed: %d\n", cfg->general->curl_dns_cache_timeout, rc);
526 curl_easy_cleanup(curl);
527 return NULL;
528 }
529
530 return curl;
531}
#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 179 of file res_http_media_cache.c.

180{
181#ifndef AST_CURL_HAS_PROTOCOLS_STR
182 struct conf *cfg = aco_pending_config(&cfg_info);
183
185 ast_log(AST_LOG_ERROR, "'protocols' not supported by linked CURL library. Please recompile against newer CURL.\n");
186 return -1;
187 }
188
190 ast_log(AST_LOG_ERROR, "'redirect_protocols' not supported by linked CURL library. Please recompile against newer CURL.\n");
191 return -1;
192 }
193#endif
194
195 return 0;
196}
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 736 of file res_http_media_cache.c.

737{
738 if (aco_info_init(&cfg_info)) {
739 aco_info_destroy(&cfg_info);
741 }
742
743
744 aco_option_register(&cfg_info, "timeout_secs", ACO_EXACT, general_options,
745 "180", OPT_INT_T, 0,
746 FLDSET(struct conf_general_options, curl_timeout));
747
748 aco_option_register(&cfg_info, "user_agent", ACO_EXACT, general_options,
750 STRFLDSET(struct conf_general_options, curl_useragent));
751
752 aco_option_register(&cfg_info, "follow_location", ACO_EXACT, general_options,
753 "yes", OPT_BOOL_T, 1,
754 FLDSET(struct conf_general_options, curl_followlocation));
755
756 aco_option_register(&cfg_info, "max_redirects", ACO_EXACT, general_options,
757 "8", OPT_INT_T, 0,
758 FLDSET(struct conf_general_options, curl_maxredirs));
759
760 aco_option_register(&cfg_info, "proxy", ACO_EXACT, general_options,
762 STRFLDSET(struct conf_general_options, curl_proxy));
763
764 aco_option_register(&cfg_info, "dns_cache_timeout_secs", ACO_EXACT, general_options,
765 "60", OPT_INT_T, 0,
766 FLDSET(struct conf_general_options, curl_dns_cache_timeout));
767
768 aco_option_register(&cfg_info, "protocols", ACO_EXACT, general_options,
770 STRFLDSET(struct conf_general_options, curl_protocols));
771
772 aco_option_register(&cfg_info, "redirect_protocols", ACO_EXACT, general_options,
774 STRFLDSET(struct conf_general_options, curl_redir_protocols));
775
776
777 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
778 struct conf *cfg;
779
780 ast_log(LOG_NOTICE, "Could not load res_http_media_cache config; using defaults\n");
781 cfg = conf_alloc();
782 if (!cfg) {
783 aco_info_destroy(&cfg_info);
785 }
786
787 if (aco_set_defaults(&general_option, "general", cfg->general)) {
788 ast_log(LOG_ERROR, "Failed to initialize res_http_media_cache defaults.\n");
789 ao2_ref(cfg, -1);
790 aco_info_destroy(&cfg_info);
792 }
793
795 ao2_ref(cfg, -1);
796 }
797
799 NULL, NULL)) {
800 ast_log(LOG_ERROR, "Failed to register Bucket HTTP wizard scheme implementation\n");
802 }
803
805 NULL, NULL)) {
806 ast_log(LOG_ERROR, "Failed to register Bucket HTTPS wizard scheme implementation\n");
808 }
809
811}
#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 333 of file res_http_media_cache.c.

334{
335 char *params = strchr(content_type, ';');
336
337 if (params) {
338 *params-- = 0;
339 while (params > content_type && (*params == ' ' || *params == '\t')) {
340 *params-- = 0;
341 }
342 return 1;
343 }
344
345 return 0;
346}

Referenced by derive_extension_from_mime_type().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 729 of file res_http_media_cache.c.

730{
731 aco_info_destroy(&cfg_info);
733 return 0;
734}
#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 818 of file res_http_media_cache.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 818 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 163 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 122 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 130 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 705 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 697 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 721 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 713 of file res_http_media_cache.c.

Referenced by load_module().