[asterisk-commits] mjordan: branch mjordan/trunk-http-stuff-and-things r431572 - in /team/mjorda...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Feb 4 21:32:11 CST 2015
Author: mjordan
Date: Wed Feb 4 21:32:03 2015
New Revision: 431572
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=431572
Log:
res_http_media_cache: Update the various callbacks
We have CRUD! Although the -D doesn't do anything.
Modified:
team/mjordan/trunk-http-stuff-and-things/main/media_cache.c
team/mjordan/trunk-http-stuff-and-things/res/res_http_media_cache.c
Modified: team/mjordan/trunk-http-stuff-and-things/main/media_cache.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/trunk-http-stuff-and-things/main/media_cache.c?view=diff&rev=431572&r1=431571&r2=431572
==============================================================================
--- team/mjordan/trunk-http-stuff-and-things/main/media_cache.c (original)
+++ team/mjordan/trunk-http-stuff-and-things/main/media_cache.c Wed Feb 4 21:32:03 2015
@@ -108,7 +108,7 @@
if (metadata) {
ast_db_put(hash, metadata->name, metadata->value);
ao2_ref(metadata, -1);
- }
+ }
}
static void media_cache_item_sync_to_astdb(struct ast_bucket_file *bucket_file)
Modified: team/mjordan/trunk-http-stuff-and-things/res/res_http_media_cache.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/trunk-http-stuff-and-things/res/res_http_media_cache.c?view=diff&rev=431572&r1=431571&r2=431572
==============================================================================
--- team/mjordan/trunk-http-stuff-and-things/res/res_http_media_cache.c (original)
+++ team/mjordan/trunk-http-stuff-and-things/res/res_http_media_cache.c Wed Feb 4 21:32:03 2015
@@ -44,52 +44,57 @@
#define GLOBAL_USERAGENT "asterisk-libcurl-agent/1.0"
+#define MAX_HEADER_LENGTH 1023
+
+/*! \brief Data passed to cURL callbacks */
struct curl_bucket_file_data {
+ /*! The \c ast_bucket_file object that caused the operation */
struct ast_bucket_file *bucket_file;
+ /*! File to write data to */
FILE *out_file;
};
+/*!
+ * \internal \brief The cURL header callback function
+ */
static size_t curl_header_callback(char *buffer, size_t size, size_t nitems, void *data)
{
struct curl_bucket_file_data *cb_data = data;
size_t realsize;
- size_t offset;
- size_t value_len;
char *value;
- char *dupd_value;
- char *clean_value;
+ char *header;
realsize = size * nitems;
+ if (realsize > MAX_HEADER_LENGTH) {
+ ast_log(LOG_WARNING, "cURL header length of '%zu' is too large: max %d\n",
+ realsize, MAX_HEADER_LENGTH);
+ return 0;
+ }
+
/* buffer may not be NULL terminated */
- value = memchr(buffer, ':', realsize);
+ header = ast_alloca(realsize + 1);
+ memcpy(header, buffer, realsize);
+ header[realsize] = '\0';
+
+ value = strchr(header, ':');
if (!value) {
ast_log(LOG_WARNING, "Failed to split received header in cURL request\n");
return 0;
}
- offset = value - buffer;
- value_len = realsize - offset;
*value++ = '\0';
- if (strcmp(buffer, "ETag")
- && strcmp(buffer, "Cache-Control")
- && strcmp(buffer, "Last-Modified")) {
+ if (strcasecmp(header, "ETag")
+ && strcasecmp(header, "Cache-Control")
+ && strcasecmp(header, "Last-Modified")
+ && strcasecmp(header, "Expires")) {
return realsize;
}
- dupd_value = ast_malloc(value_len + 1);
- if (!dupd_value) {
- return 0;
- }
- strncpy(dupd_value, value, value_len);
- dupd_value[value_len] = '\0';
- clean_value = dupd_value;
- clean_value = ast_skip_blanks(clean_value);
- clean_value = ast_trim_blanks(clean_value);
-
- ast_bucket_file_metadata_set(cb_data->bucket_file, buffer, clean_value);
-
- ast_free(dupd_value);
+ value = ast_trim_blanks(ast_skip_blanks(value));
+
+ ast_bucket_file_metadata_set(cb_data->bucket_file, header, value);
+
return realsize;
}
@@ -103,29 +108,72 @@
return realsize;
}
-static int bucket_http_wizard_create(const struct ast_sorcery *sorcery, void *data,
- void *object)
-{
- char curl_errbuf[CURL_ERROR_SIZE + 1]; /* add one to be safe */
- struct ast_bucket_file *bucket_file = object;
+static void bucket_file_set_expiration(struct ast_bucket_file *bucket_file)
+{
+ struct ast_bucket_metadata *metadata;
+ char time_buf[32];
+ struct timeval actual_expires = ast_tvnow();
+
+ metadata = ast_bucket_file_metadata_get(bucket_file, "cache-control");
+ if (metadata) {
+ char *str_max_age;
+
+ str_max_age = strstr(metadata->value, "s-maxage");
+ if (!str_max_age) {
+ str_max_age = strstr(metadata->value, "max-age");
+ }
+
+ if (str_max_age) {
+ unsigned int max_age;
+ char *equal = strchr(str_max_age, '=');
+ if (equal && (sscanf(equal + 1, "%30u", &max_age) == 1)) {
+ actual_expires.tv_sec += max_age;
+ }
+ }
+ ao2_ref(metadata, -1);
+ } else {
+ metadata = ast_bucket_file_metadata_get(bucket_file, "expires");
+ if (metadata) {
+ struct tm expires_time;
+
+ strptime(metadata->value, "%a, %d %b %Y %T %z", &expires_time);
+ actual_expires.tv_sec = mktime(&expires_time);
+
+ ao2_ref(metadata, -1);
+ }
+ }
+
+ /* Use 'now' if we didn't get an expiration time */
+ snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);
+
+ ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf);
+}
+
+
+
+static long bucket_file_execute_curl(struct ast_bucket_file *bucket_file,
+ void (* const pre_exec)(struct ast_bucket_file *, CURL *, void *),
+ void *arg)
+{
+ char curl_errbuf[CURL_ERROR_SIZE + 1];
const char *uri = ast_sorcery_object_get_id(bucket_file);
- CURL *curl;
+ long http_code = -1;
struct curl_bucket_file_data cb_data = {
.bucket_file = bucket_file,
};
+ CURL *curl;
cb_data.out_file = fopen(bucket_file->path, "wb");
if (!cb_data.out_file) {
+ ast_log(LOG_WARNING, "Failed to open file '%s' for writing\n",
+ bucket_file->path);
return -1;
}
- /* TODO:
- * -- force a refresh by pulling down the URI
- * -- populate the object
- */
curl = curl_easy_init();
if (!curl) {
fclose(cb_data.out_file);
+ unlink(bucket_file->path);
return -1;
}
@@ -140,42 +188,164 @@
curl_errbuf[CURL_ERROR_SIZE] = '\0';
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
+ if (pre_exec) {
+ pre_exec(bucket_file, curl, arg);
+ }
+
if (curl_easy_perform(curl)) {
+ fclose(cb_data.out_file);
+ unlink(bucket_file->path);
ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, uri);
- }
-
- fclose(cb_data.out_file);
- return -1;
+ return -1;
+ }
+
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
+
+ curl_easy_cleanup(curl);
+
+ return http_code;
+}
+
+static int bucket_http_wizard_create(const struct ast_sorcery *sorcery, void *data,
+ void *object)
+{
+ struct ast_bucket_file *bucket_file = object;
+ long http_code;
+ int res = -1;
+
+ http_code = bucket_file_execute_curl(bucket_file, NULL, NULL);
+
+ if (http_code / 100 == 2) {
+ bucket_file_set_expiration(bucket_file);
+ res = 0;
+ }
+
+ return res;
+}
+
+static int bucket_file_always_revalidate(struct ast_bucket_file *bucket_file)
+{
+ RAII_VAR(struct ast_bucket_metadata *, metadata,
+ ast_bucket_file_metadata_get(bucket_file, "cache-control"),
+ ao2_cleanup);
+
+ if (!metadata) {
+ return 0;
+ }
+
+ if (strstr(metadata->value, "no-cache")
+ || strstr(metadata->value, "must-revalidate")) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*! \internal
+ * \brief Return whether or not the item has expired
+ */
+static int bucket_file_expired(struct ast_bucket_file *bucket_file)
+{
+ RAII_VAR(struct ast_bucket_metadata *, metadata,
+ ast_bucket_file_metadata_get(bucket_file, "__actual_expires"),
+ ao2_cleanup);
+ struct timeval current_time = ast_tvnow();
+ struct timeval expires = { .tv_sec = 0, .tv_usec = 0 };
+
+ if (!metadata) {
+ return 1;
+ }
+
+ if (sscanf(metadata->value, "%lu", &expires.tv_sec) != 1) {
+ return 1;
+ }
+
+ return ast_tvcmp(current_time, expires) == 1 ? 1 : 0;
+}
+
+static void update_pre_exec(struct ast_bucket_file *bucket_file, CURL *curl, void *obj)
+{
+ struct ast_bucket_metadata *metadata;
+ struct curl_slist **header_list = obj;
+
+ metadata = ast_bucket_file_metadata_get(bucket_file, "etag");
+ if (metadata) {
+ char etag_buf[256];
+
+ snprintf(etag_buf, sizeof(etag_buf), "If-None-Match: %s", metadata->value);
+ (*header_list) = curl_slist_append(*header_list, etag_buf);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *header_list);
+ ao2_ref(metadata, -1);
+ }
}
static int bucket_http_wizard_update(const struct ast_sorcery *sorcery, void *data,
void *object)
{
- /*if (!strcmp(ast_sorcery_object_get_id(object), VALID_RESOURCE)) {
+ struct ast_bucket_file *bucket_file = object;
+ struct curl_slist *header_list = NULL;
+ long http_code;
+ int res = -1;
+
+ if (!bucket_file_expired(bucket_file) && !bucket_file_always_revalidate(bucket_file)) {
return 0;
- }*/
-
- return -1;
+ }
+
+ http_code = bucket_file_execute_curl(bucket_file, &update_pre_exec, &header_list);
+
+ if (header_list) {
+ curl_slist_free_all(header_list);
+ }
+
+ if (http_code / 100 == 2) {
+ bucket_file_set_expiration(bucket_file);
+ res = 0;
+ }
+
+ return res;
}
static void *bucket_http_wizard_retrieve_id(const struct ast_sorcery *sorcery,
void *data, const char *type, const char *id)
{
- /* TODO:
- * -- hit the provided URI and see if we need to download it
- * -- if we do, pull it down and update the resource
- * -- if not, simply return what's there
- */
+ struct ast_bucket_file *bucket_file;
+
if (strcmp(type, "file")) {
- return NULL;
- }
- return NULL;
+ ast_log(LOG_WARNING, "Failed to create storage: invalid bucket type '%s'\n", type);
+ return NULL;
+ }
+
+ if (ast_strlen_zero(id)) {
+ ast_log(LOG_WARNING, "Failed to create storage: no URI\n");
+ return NULL;
+ }
+
+ bucket_file = ast_bucket_file_alloc(id);
+ if (!bucket_file) {
+ ast_log(LOG_WARNING, "Failed to create storage for '%s'\n", id);
+ return NULL;
+ }
+
+ if (ast_bucket_file_temporary_create(bucket_file)) {
+ ast_log(LOG_WARNING, "Failed to create temporary storage for '%s'\n", id);
+ ao2_ref(bucket_file, -1);
+ return NULL;
+ }
+
+ if (bucket_http_wizard_update(sorcery, data, bucket_file)) {
+ ast_log(LOG_WARNING, "Failed to retrieve resource at '%s'\n'", id);
+ ao2_ref(bucket_file, -1);
+ return NULL;
+ }
+
+ return bucket_file;
}
static int bucket_http_wizard_delete(const struct ast_sorcery *sorcery, void *data,
void *object)
{
- return -1;
+ /* Nothing to delete here, move along! */
+ return 0;
}
static struct ast_sorcery_wizard bucket_wizard = {
More information about the asterisk-commits
mailing list