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 = {


-- 
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to