LCOV - code coverage report
Current view: top level - utils - cache.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 438 494 88.7 %
Date: 2021-04-29 23:48:07 Functions: 47 49 95.9 %

          Line data    Source code
       1             : /*
       2             :  *                                      GPAC Multimedia Framework
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre, Pierre Souchay
       5             :  *                      Copyright (c) Telecom ParisTech 2010-2020
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *   This file is part of GPAC / common tools sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #ifndef GPAC_DISABLE_CORE_TOOLS
      27             : 
      28             : #include <gpac/cache.h>
      29             : #include <gpac/network.h>
      30             : #include <gpac/download.h>
      31             : #include <gpac/token.h>
      32             : #include <gpac/thread.h>
      33             : #include <gpac/list.h>
      34             : #include <gpac/base_coding.h>
      35             : #include <gpac/tools.h>
      36             : #include <gpac/config_file.h>
      37             : #include <stdio.h>
      38             : #include <string.h>
      39             : 
      40             : #if defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500
      41             : #include <unistd.h>
      42             : #endif
      43             : 
      44             : static const char * CACHE_SECTION_NAME = "cache";
      45             : static const char * CACHE_SECTION_NAME_URL = "url";
      46             : static const char * CACHE_SECTION_NAME_RANGE = "range";
      47             : static const char * CACHE_SECTION_NAME_ETAG = "ETag";
      48             : static const char * CACHE_SECTION_NAME_MIME_TYPE = "Content-Type";
      49             : static const char * CACHE_SECTION_NAME_CONTENT_SIZE = "Content-Length";
      50             : static const char * CACHE_SECTION_NAME_LAST_MODIFIED = "Last-Modified";
      51             : 
      52             : enum CacheValid
      53             : {
      54             :         MUST_REVALIDATE = 1,
      55             :         IS_HTTPS = 1<<1,
      56             :         CORRUPTED = 1<<2,
      57             :         NO_CACHE = 1<<3,
      58             :     DELETED = 1<<4
      59             : };
      60             : 
      61             : struct __CacheReaderStruct {
      62             :         FILE * readPtr;
      63             :         s64 readPosition;
      64             : };
      65             : 
      66             : typedef struct __DownloadedRangeStruc {
      67             :         u32 start;
      68             :         u32 end;
      69             :         const char * filename;
      70             : } * DownloadedRange;
      71             : 
      72             : //#define ENABLE_WRITE_MX
      73             : 
      74             : /**
      75             : * This opaque structure handles the data from the cache
      76             : */
      77             : struct __DownloadedCacheEntryStruct
      78             : {
      79             :         /**
      80             :         * URL of the cache (never NULL)
      81             :         */
      82             :         char * url;
      83             :         /**
      84             :         * Hash of the cache (never NULL)
      85             :         */
      86             :         char * hash;
      87             :         /**
      88             :         * Name of the cache filename, (can be NULL)
      89             :         */
      90             :         char * cache_filename;
      91             :         /**
      92             :         * Name of the cached properties filename , (can be NULL)
      93             :         */
      94             :         GF_Config * properties;
      95             :         /**
      96             :         * Theorical size of cache if any
      97             :         */
      98             :         u32          contentLength;
      99             :         /**
     100             :         * Real size of cache
     101             :         */
     102             :         u32          cacheSize;
     103             :         /**
     104             :         * GMT timestamp for revalidation
     105             :         */
     106             :         u32          validity;
     107             :         /**
     108             :         * The last modification time on the server
     109             :         */
     110             :         char *       serverLastModified;
     111             :         /**
     112             :         * The last modification time of the cache if any
     113             :         */
     114             :         char *       diskLastModified;
     115             :         /**
     116             :         * ETag if any
     117             :         */
     118             :         char * serverETag;
     119             :         /**
     120             :         * ETag if any
     121             :         */
     122             :         char * diskETag;
     123             :         /**
     124             :         * Mime-type (never NULL)
     125             :         */
     126             :         char * mimeType;
     127             :         /**
     128             :         * Write pointer for the cache
     129             :         */
     130             :         FILE * writeFilePtr;
     131             :         /**
     132             :         * Bytes written during this cache session
     133             :         */
     134             :         u32 written_in_cache;
     135             :         /**
     136             :         * Flag indicating whether we have to revalidate
     137             :         */
     138             :         enum CacheValid   flags;
     139             : 
     140             :         const GF_DownloadSession * write_session;
     141             : 
     142             : #ifdef ENABLE_WRITE_MX
     143             :         GF_Mutex * write_mutex;
     144             : #endif
     145             : 
     146             :         GF_List * sessions;
     147             : 
     148             :         Bool deletableFilesOnDelete;
     149             : 
     150             :         GF_DownloadManager * dm;
     151             : 
     152             :         /*start and end range of the cache*/
     153             :         u64 range_start, range_end;
     154             : 
     155             :         Bool continue_file;
     156             :         Bool file_exists;
     157             : 
     158             :         u32 previousRangeContentLength;
     159             :         /*set once headers have been processed*/
     160             :         Bool headers_done;
     161             :         /**
     162             :         * Set to 1 if file is not stored on disk
     163             :         */
     164             :         Bool memory_stored;
     165             :         u32 mem_allocated;
     166             :         u8 *mem_storage;
     167             :         char *forced_headers;
     168             :         u32 downtime;
     169             : 
     170             :     GF_Blob cache_blob;
     171             :     GF_Blob *external_blob;
     172             :     Bool persistent;
     173             : };
     174             : 
     175         212 : Bool gf_cache_entry_persistent(const DownloadedCacheEntry entry)
     176             : {
     177         212 :         return entry ? entry->persistent : GF_FALSE;
     178             : }
     179         214 : void gf_cache_entry_set_persistent(const DownloadedCacheEntry entry)
     180             : {
     181         214 :         if (entry) entry->persistent = GF_TRUE;
     182         214 : }
     183             : 
     184           1 : Bool delete_cache_files(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) {
     185             :         const char * startPattern;
     186             :         int sz;
     187             :         assert( cbck );
     188             :         assert( item_name );
     189             :         assert( item_path);
     190             :         startPattern = (const char *) cbck;
     191           1 :         sz = (u32) strlen( startPattern );
     192           1 :         if (!strncmp(startPattern, item_name, sz)) {
     193           0 :                 if (GF_OK != gf_file_delete(item_path))
     194           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] : failed to cleanup file %s\n", item_path));
     195             :         }
     196           1 :         return GF_FALSE;
     197             : }
     198             : 
     199             : static const char * cache_file_prefix = "gpac_cache_";
     200             : 
     201        2639 : Bool gather_cache_size(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info)
     202             : {
     203             :         u64 *out_size = (u64 *)cbck;
     204        2639 :         if (!strncmp(cache_file_prefix, item_name, strlen(cache_file_prefix))) {
     205        1613 :                 *out_size += file_info->size;
     206             :         }
     207        2639 :         return 0;
     208             : }
     209             : 
     210         151 : u64 gf_cache_get_size(const char * directory) {
     211         151 :         u64 size = 0;
     212         151 :         gf_enum_directory(directory, GF_FALSE, gather_cache_size, (void*)&size, NULL);
     213         151 :         return size;
     214             : }
     215             : 
     216           1 : GF_Err gf_cache_delete_all_cached_files(const char * directory) {
     217           1 :         GF_LOG(GF_LOG_INFO, GF_LOG_CACHE, ("Deleting cached files in %s...\n", directory));
     218           1 :         return gf_enum_directory( directory, GF_FALSE, delete_cache_files, (void*)cache_file_prefix, NULL);
     219             : }
     220             : 
     221         541 : void gf_cache_entry_set_delete_files_when_deleted(const DownloadedCacheEntry entry) {
     222         541 :         if (entry && !entry->persistent)
     223         461 :                 entry->deletableFilesOnDelete = GF_TRUE;
     224         541 : }
     225             : 
     226         804 : Bool gf_cache_entry_is_delete_files_when_deleted(const DownloadedCacheEntry entry)
     227             : {
     228         804 :         if (!entry)
     229             :                 return GF_FALSE;
     230         804 :         return entry->deletableFilesOnDelete;
     231             : }
     232             : 
     233             : #define CHECK_ENTRY if (!entry) { GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] entry is null at " __FILE__ ":%d\n", __LINE__)); return GF_BAD_PARAM; }
     234             : 
     235             : /*
     236             : * Getters functions
     237             : */
     238             : 
     239           0 : const char * gf_cache_get_etag_on_server ( const DownloadedCacheEntry entry )
     240             : {
     241          59 :         return entry ? entry->serverETag : NULL;
     242             : }
     243             : 
     244        1628 : const char * gf_cache_get_mime_type ( const DownloadedCacheEntry entry )
     245             : {
     246        1628 :         return entry ? entry->mimeType : NULL;
     247             : }
     248             : 
     249             : 
     250         803 : GF_Err gf_cache_set_headers_processed(const DownloadedCacheEntry entry)
     251             : {
     252         803 :         if (!entry) return GF_BAD_PARAM;
     253         774 :         entry->headers_done = GF_TRUE;
     254         774 :         return GF_OK;
     255             : }
     256             : 
     257           5 : Bool gf_cache_are_headers_processed(const DownloadedCacheEntry entry)
     258             : {
     259           5 :         if (!entry) return GF_FALSE;
     260           0 :         return entry->headers_done;
     261             : }
     262             : 
     263         770 : GF_Err gf_cache_set_etag_on_server(const DownloadedCacheEntry entry, const char * eTag ) {
     264         770 :         if (!entry)
     265             :                 return GF_BAD_PARAM;
     266         768 :         if (entry->serverETag)
     267         143 :                 gf_free(entry->serverETag);
     268         768 :         entry->serverETag = eTag ? gf_strdup(eTag) : NULL;
     269         768 :         return GF_OK;
     270             : }
     271             : 
     272         124 : GF_Err gf_cache_set_etag_on_disk(const DownloadedCacheEntry entry, const char * eTag ) {
     273         124 :         if (!entry)
     274             :                 return GF_BAD_PARAM;
     275         124 :         if (entry->diskETag)
     276          18 :                 gf_free(entry->diskETag);
     277         124 :         entry->diskETag = eTag ? gf_strdup(eTag) : NULL;
     278         124 :         return GF_OK;
     279             : }
     280             : 
     281         651 : GF_Err gf_cache_set_mime_type(const DownloadedCacheEntry entry, const char * mime_type ) {
     282         651 :         if (!entry)
     283             :                 return GF_BAD_PARAM;
     284         651 :         if (entry->mimeType)
     285          52 :                 gf_free(entry->mimeType);
     286         651 :         entry->mimeType = mime_type? gf_strdup( mime_type) : NULL;
     287         651 :         return GF_OK;
     288             : }
     289             : 
     290         184 : u64 gf_cache_get_start_range( const DownloadedCacheEntry entry )
     291             : {
     292         184 :         return entry ? entry->range_start : 0;
     293             : }
     294             : 
     295         194 : u64 gf_cache_get_end_range( const DownloadedCacheEntry entry )
     296             : {
     297         194 :         return entry ? entry->range_end : 0;
     298             : }
     299             : 
     300        4951 : const char * gf_cache_get_url ( const DownloadedCacheEntry entry )
     301             : {
     302        4951 :         return entry ? entry->url : NULL;
     303             : }
     304             : 
     305           0 : const char * gf_cache_get_last_modified_on_server ( const DownloadedCacheEntry entry )
     306             : {
     307          59 :         return entry ? entry->serverLastModified : NULL;
     308             : }
     309             : 
     310         633 : GF_Err gf_cache_set_last_modified_on_server ( const DownloadedCacheEntry entry, const char * newLastModified )
     311             : {
     312         633 :         if (!entry)
     313             :                 return GF_BAD_PARAM;
     314         631 :         if (entry->serverLastModified)
     315          45 :                 gf_free(entry->serverLastModified);
     316         631 :         entry->serverLastModified = newLastModified ? gf_strdup(newLastModified) : NULL;
     317         631 :         return GF_OK;
     318             : }
     319             : 
     320         124 : GF_Err gf_cache_set_last_modified_on_disk ( const DownloadedCacheEntry entry, const char * newLastModified )
     321             : {
     322         124 :         if (!entry)
     323             :                 return GF_BAD_PARAM;
     324         124 :         if (entry->diskLastModified)
     325          11 :                 gf_free(entry->diskLastModified);
     326         124 :         entry->diskLastModified = newLastModified ? gf_strdup(newLastModified) : NULL;
     327         124 :         return GF_OK;
     328             : }
     329             : 
     330             : #define _CACHE_TMP_SIZE 4096
     331             : 
     332         128 : GF_Err gf_cache_flush_disk_cache ( const DownloadedCacheEntry entry )
     333             : {
     334             :         char buff[100];
     335         128 :         CHECK_ENTRY;
     336         128 :         if ( !entry->properties)
     337             :                 return GF_OK;
     338         128 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] gf_cache_flush_disk_cache:%d for entry=%p\n", __LINE__, entry));
     339         128 :         gf_cfg_set_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_URL, entry->url);
     340             : 
     341         128 :         sprintf(buff, LLD"-"LLD, entry->range_start, entry->range_end);
     342         128 :         gf_cfg_set_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_RANGE, buff);
     343             : 
     344         128 :         if (entry->mimeType)
     345         108 :                 gf_cfg_set_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_MIME_TYPE, entry->mimeType);
     346         128 :         if (entry->diskETag)
     347          69 :                 gf_cfg_set_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_ETAG, entry->diskETag);
     348         128 :         if (entry->diskLastModified)
     349          51 :                 gf_cfg_set_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_LAST_MODIFIED, entry->diskLastModified);
     350             :         {
     351         128 :                 snprintf(buff, 16, "%d", entry->contentLength);
     352         128 :                 gf_cfg_set_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_CONTENT_SIZE, buff);
     353             :         }
     354         128 :         return gf_cfg_save ( entry->properties );
     355             : }
     356             : 
     357           2 : u32 gf_cache_get_cache_filesize ( const DownloadedCacheEntry entry )
     358             : {
     359           2 :         return entry ? entry->cacheSize : -1;
     360             : }
     361             : 
     362        1615 : const char * gf_cache_get_cache_filename( const DownloadedCacheEntry entry )
     363             : {
     364        1615 :         return entry ? entry->cache_filename : NULL;
     365             : }
     366             : 
     367         698 : GF_Err gf_cache_get_http_headers(const DownloadedCacheEntry entry, const char **etag, const char **last_modif)
     368             : {
     369         698 :         if (!entry || !etag || !last_modif)
     370             :                 return GF_BAD_PARAM;
     371             : 
     372         696 :         *etag = *last_modif = NULL;
     373         696 :         if (entry->flags)
     374             :                 return GF_OK;
     375         638 :         if (gf_cache_check_if_cache_file_is_corrupted(entry))
     376             :                 return GF_OK;
     377             : 
     378         100 :         *etag = entry->diskETag;
     379         100 :         *last_modif = entry->diskLastModified;
     380         100 :         if (entry->persistent && entry->memory_stored) {
     381          84 :                 *etag = entry->serverETag;
     382          84 :                 *last_modif = entry->serverLastModified;
     383             :         }
     384             :         return GF_OK;
     385             : }
     386             : 
     387             : #define _CACHE_HASH_SIZE 20
     388             : #define _CACHE_MAX_EXTENSION_SIZE 6
     389             : static const char * default_cache_file_suffix = ".dat";
     390             : static const char * cache_file_info_suffix = ".txt";
     391             : 
     392         685 : DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char * cache_directory, const char * url , u64 start_range, u64 end_range, Bool mem_storage, GF_Mutex *mx)
     393             : {
     394             :         char tmp[_CACHE_TMP_SIZE];
     395             :         u8 hash[_CACHE_HASH_SIZE];
     396             :         int sz;
     397             :         char ext[_CACHE_MAX_EXTENSION_SIZE];
     398             :         DownloadedCacheEntry entry = NULL;
     399         685 :         if ( !dm || !url || !cache_directory) {
     400           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE,
     401             :                        ("[CACHE] gf_cache_create_entry :%d, dm=%p, url=%s cache_directory=%s, aborting.\n", __LINE__, dm, url, cache_directory));
     402             :                 return entry;
     403             :         }
     404         685 :         sz = (u32) strlen ( url );
     405         685 :         if ( sz > _CACHE_TMP_SIZE )
     406             :         {
     407           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE,
     408             :                        ("[CACHE] gf_cache_create_entry:%d : ERROR, URL is too long (%d chars), more than %d chars.\n", __LINE__, sz, _CACHE_TMP_SIZE ));
     409             :                 return entry;
     410             :         }
     411         685 :         tmp[0] = '\0';
     412             :         /*generate hash of the full url*/
     413         685 :         if (start_range && end_range) {
     414             :                 sprintf(tmp, "%s_"LLD"-"LLD, url, start_range, end_range );
     415             :         } else {
     416             :                 strcpy ( tmp, url );
     417             :         }
     418         685 :         gf_sha1_csum ((u8*) tmp, (u32) strlen ( tmp ), hash );
     419         685 :         tmp[0] = 0;
     420             :         {
     421             :                 int i;
     422       14385 :                 for ( i=0; i<20; i++ )
     423             :                 {
     424             :                         char t[3];
     425       13700 :                         t[2] = 0;
     426       13700 :                         sprintf ( t, "%02X", hash[i] );
     427             :                         strcat ( tmp, t );
     428             :                 }
     429             :         }
     430             :         assert ( strlen ( tmp ) == (_CACHE_HASH_SIZE * 2) );
     431             : 
     432         685 :         GF_SAFEALLOC(entry, struct __DownloadedCacheEntryStruct);
     433             : 
     434         685 :         if ( !entry ) {
     435           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("gf_cache_create_entry:%d : out of memory !\n", __LINE__));
     436             :                 return NULL;
     437             :         }
     438         685 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, entry=%p\n", __LINE__, entry));
     439             : 
     440         685 :         entry->url = gf_strdup ( url );
     441         685 :         entry->hash = gf_strdup ( tmp );
     442             : 
     443         685 :         entry->memory_stored = mem_storage;
     444             : 
     445         685 :         entry->cacheSize = 0;
     446         685 :         entry->contentLength = 0;
     447         685 :         entry->serverETag = NULL;
     448         685 :         entry->diskETag = NULL;
     449         685 :         entry->flags = 0;
     450         685 :         entry->validity = 0;
     451         685 :         entry->diskLastModified = NULL;
     452         685 :         entry->serverLastModified = NULL;
     453         685 :         entry->dm = dm;
     454         685 :         entry->range_start = start_range;
     455         685 :         entry->range_end = end_range;
     456             : 
     457             : #ifdef ENABLE_WRITE_MX
     458             :         {
     459             :                 char name[1024];
     460             :                 snprintf(name, sizeof(name), "CachedEntryWriteMx=%p, url=%s", (void*) entry, url);
     461             :                 entry->write_mutex = gf_mx_new(name);
     462             :                 assert(entry->write_mutex);
     463             :         }
     464             : #endif
     465             : 
     466         685 :         entry->deletableFilesOnDelete = GF_FALSE;
     467         685 :         entry->write_session = NULL;
     468         685 :         entry->sessions = gf_list_new();
     469             : 
     470         685 :         if (entry->memory_stored) {
     471         620 :                 entry->cache_filename = (char*)gf_malloc ( strlen ("gmem://") + 8 + strlen("@") + 16 + 1);
     472             :         } else {
     473             :                 /* Sizeof cache directory + hash + possible extension */
     474          65 :                 entry->cache_filename = (char*)gf_malloc ( strlen ( cache_directory ) + strlen(cache_file_prefix) + strlen(tmp) + _CACHE_MAX_EXTENSION_SIZE + 1);
     475             :         }
     476             : 
     477         685 :         if ( !entry->hash || !entry->url || !entry->cache_filename || !entry->sessions)
     478             :         {
     479             :                 GF_Err err;
     480             :                 /* Probably out of memory */
     481           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, aborting due to OUT of MEMORY !\n", __LINE__));
     482           0 :                 err = gf_cache_delete_entry ( entry );
     483           0 :                 if ( err != GF_OK ) {
     484           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, failed to delete cache entry!\n", __LINE__));
     485             :                 }
     486             :                 return NULL;
     487             :         }
     488             : 
     489         685 :         if (entry->memory_stored) {
     490         620 :                 entry->cache_blob.mx = mx;
     491         620 :                 entry->cache_blob.data = entry->mem_storage;
     492         620 :                 entry->cache_blob.size = entry->contentLength;
     493         620 :                 sprintf(entry->cache_filename, "gmem://%p", &entry->cache_blob);
     494         620 :                 return entry;
     495             :         }
     496             : 
     497             : 
     498          65 :         tmp[0] = '\0';
     499             :         strcpy ( entry->cache_filename, cache_directory );
     500          65 :         strcat( entry->cache_filename, cache_file_prefix );
     501          65 :         strcat ( entry->cache_filename, entry->hash );
     502             :         strcpy ( tmp, url );
     503             : 
     504             :         {
     505             :                 char * parser;
     506          65 :                 parser = strrchr ( tmp, '?' );
     507          65 :                 if ( parser )
     508           0 :                         parser[0] = '\0';
     509          65 :                 parser = strrchr ( tmp, '#' );
     510          65 :                 if ( parser )
     511           0 :                         parser[0] = '\0';
     512          65 :                 parser = strrchr ( tmp, '.' );
     513          65 :                 if ( parser && ( strlen ( parser ) < _CACHE_MAX_EXTENSION_SIZE ) )
     514             :                         strncpy(ext, parser, _CACHE_MAX_EXTENSION_SIZE);
     515             :                 else
     516           4 :                         strncpy(ext, default_cache_file_suffix, _CACHE_MAX_EXTENSION_SIZE);
     517             :                 assert (strlen(ext));
     518          65 :                 strcat( entry->cache_filename, ext);
     519             :         }
     520          65 :         tmp[0] = '\0';
     521             :         strcpy( tmp, cache_file_prefix);
     522          65 :         strcat( tmp, entry->hash );
     523             :         strcat( tmp , ext);
     524          65 :         strcat ( tmp, cache_file_info_suffix );
     525          65 :         entry->properties = gf_cfg_force_new ( cache_directory, tmp );
     526          65 :         if ( !entry->properties )
     527             :         {
     528             :                 GF_Err err;
     529             :                 /* out of memory ? */
     530           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, aborting due to OUT of MEMORY !\n", __LINE__));
     531           0 :                 err = gf_cache_delete_entry ( entry );
     532           0 :                 if ( err != GF_OK ) {
     533           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, failed to delete cache entry!\n", __LINE__));
     534             :                 }
     535             :                 return NULL;
     536             :         }
     537          65 :         gf_cache_set_etag_on_disk(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_ETAG));
     538          65 :         gf_cache_set_etag_on_server(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_ETAG));
     539          65 :         gf_cache_set_mime_type(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_MIME_TYPE));
     540          65 :         gf_cache_set_last_modified_on_disk(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_LAST_MODIFIED));
     541          65 :         gf_cache_set_last_modified_on_server(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_LAST_MODIFIED));
     542             :         {
     543          65 :                 const char * keyValue = gf_cfg_get_key ( entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_URL );
     544          65 :                 if ( keyValue == NULL || stricmp ( url, keyValue ) )
     545          41 :                         entry->flags |= CORRUPTED;
     546             : 
     547          65 :                 keyValue = gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_RANGE);
     548          65 :                 if (keyValue) {
     549             :                         u64 s, e;
     550          24 :                         sscanf(keyValue, LLD"-"LLD, &s, &e);
     551             :                         /*mark as corrupted if not same range (we don't support this for the time being ...*/
     552          24 :                         if ((s!=entry->range_start) || (e!=entry->range_end))
     553           0 :                                 entry->flags |= CORRUPTED;
     554             :                 }
     555             :         }
     556          65 :         gf_cache_check_if_cache_file_is_corrupted(entry);
     557             : 
     558          65 :         return entry;
     559             : }
     560             : 
     561         729 : GF_Err gf_cache_set_content_length( const DownloadedCacheEntry entry, u32 length )
     562             : {
     563         729 :         CHECK_ENTRY;
     564         729 :         if (entry->continue_file) {
     565          40 :                 entry->contentLength = entry->previousRangeContentLength + length;
     566             :         } else {
     567         689 :                 entry->contentLength = length;
     568             :         }
     569             :         return GF_OK;
     570             : }
     571             : 
     572       20911 : u32 gf_cache_get_content_length( const DownloadedCacheEntry entry)
     573             : {
     574       20911 :         if (!entry) return 0;
     575       20902 :         if (entry->external_blob) {
     576       20865 :                 return entry->external_blob->size;
     577             :         }
     578          37 :         return entry->contentLength;
     579             : }
     580             : 
     581        1732 : GF_Err gf_cache_close_write_cache( const DownloadedCacheEntry entry, const GF_DownloadSession * sess, Bool success )
     582             : {
     583             :         GF_Err e = GF_OK;
     584        1732 :         CHECK_ENTRY;
     585        1732 :         if (!sess || !entry->write_session || entry->write_session != sess)
     586             :                 return GF_OK;
     587             :         assert( sess == entry->write_session );
     588         767 :         if (entry->writeFilePtr) {
     589          64 :                 GF_LOG(GF_LOG_INFO, GF_LOG_CACHE,
     590             :                        ("[CACHE] Closing file %s, %d bytes written.\n", entry->cache_filename, entry->written_in_cache));
     591             : 
     592          64 :                 if (gf_fflush( entry->writeFilePtr ) || gf_fclose( entry->writeFilePtr )) {
     593           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to flush/close file on disk\n"));
     594             :                         e = GF_IO_ERR;
     595             :                 }
     596             :                 if (!e) {
     597          64 :                         e = gf_cache_flush_disk_cache(entry);
     598          64 :                         if (e) {
     599           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to flush cache entry on disk\n"));
     600             :                         }
     601             :                 }
     602          64 :                 if (!e && success) {
     603          59 :                         e = gf_cache_set_last_modified_on_disk( entry, gf_cache_get_last_modified_on_server(entry));
     604          59 :                         if (e) {
     605           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to set last-modified\n"));
     606             :                         } else {
     607          59 :                                 e = gf_cache_set_etag_on_disk( entry, gf_cache_get_etag_on_server(entry));
     608          59 :                                 if (e) {
     609           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to set etag\n"));
     610             :                                 }
     611             :                         }
     612             :                 }
     613          64 :                 if (!e) {
     614          64 :                         e = gf_cache_flush_disk_cache(entry);
     615          64 :                         if (e) {
     616           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to flush cache entry on disk after etag/last-modified\n"));
     617             :                         }
     618             :                 }
     619             : 
     620             : #if defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500
     621             :                 /* On  UNIX, be sure to flush all the data */
     622             :                 sync();
     623             : #endif
     624          64 :                 entry->writeFilePtr = NULL;
     625          64 :                 if (GF_OK != e) {
     626           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to fully write file on cache, e=%d\n", e));
     627             :                 }
     628             :         }
     629         767 :         entry->write_session = NULL;
     630             : #ifdef ENABLE_WRITE_MX
     631             :         gf_mx_v(entry->write_mutex);
     632             : #endif
     633         767 :         return e;
     634             : }
     635             : 
     636         767 : GF_Err gf_cache_open_write_cache( const DownloadedCacheEntry entry, const GF_DownloadSession * sess, GF_Mutex *mx )
     637             : {
     638         767 :         CHECK_ENTRY;
     639         767 :         if (!sess)
     640             :                 return GF_BAD_PARAM;
     641             : #ifdef ENABLE_WRITE_MX
     642             :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE,("[CACHE] Locking write mutex %p for entry=%s\n", (void*) (entry->write_mutex), entry->url) );
     643             :         gf_mx_p(entry->write_mutex);
     644             : #endif
     645         767 :         entry->write_session = sess;
     646         767 :         if (!entry->continue_file) {
     647             :                 assert( ! entry->writeFilePtr);
     648             : 
     649         727 :                 entry->written_in_cache = 0;
     650             :         }
     651         767 :         entry->flags &= ~CORRUPTED;
     652             : 
     653         767 :         if (entry->memory_stored) {
     654         703 :                 if (!entry->cache_blob.mx)
     655           0 :                         entry->cache_blob.mx = mx;
     656             : 
     657         703 :                 gf_mx_p(entry->cache_blob.mx);
     658             : 
     659         703 :                 GF_LOG(GF_LOG_INFO, GF_LOG_CACHE, ("[CACHE] Opening cache file %s for write (%s)...\n", entry->cache_filename, entry->url));
     660         703 :                 if (!entry->mem_allocated || (entry->mem_allocated < entry->contentLength)) {
     661         673 :                         if (entry->contentLength) entry->mem_allocated = entry->contentLength;
     662          36 :                         else if (!entry->mem_allocated) entry->mem_allocated = 81920;
     663         673 :                         entry->mem_storage = (u8*)gf_realloc(entry->mem_storage, sizeof(char)* (entry->mem_allocated + 2) );
     664             :                 }
     665         703 :                 entry->cache_blob.data = entry->mem_storage;
     666         703 :                 entry->cache_blob.size = entry->contentLength;
     667         703 :                 sprintf(entry->cache_filename, "gmem://%p", &entry->cache_blob);
     668         703 :                 gf_mx_v(entry->cache_blob.mx);
     669             : 
     670         703 :                 if (!entry->mem_allocated) {
     671           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] Failed to create memory storage for file %s\n", entry->url));
     672             :                         return GF_OUT_OF_MEM;
     673             :                 }
     674             :                 return GF_OK;
     675             :         }
     676             : 
     677          64 :         GF_LOG(GF_LOG_INFO, GF_LOG_CACHE, ("[CACHE] Opening cache file %s for write (%s)...\n", entry->cache_filename, entry->url));
     678          64 :         entry->writeFilePtr = gf_fopen(entry->cache_filename, entry->continue_file ? "a+b" : "wb");
     679          64 :         if (!entry->writeFilePtr) {
     680           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE,
     681             :                        ("[CACHE] Error while opening cache file %s for writting.\n", entry->cache_filename));
     682           0 :                 entry->write_session = NULL;
     683             : #ifdef ENABLE_WRITE_MX
     684             :                 gf_mx_v(entry->write_mutex);
     685             : #endif
     686           0 :                 return GF_IO_ERR;
     687             :         }
     688          64 :         entry->file_exists = GF_TRUE;
     689          64 :         if (entry->continue_file )
     690           0 :                 gf_fseek(entry->writeFilePtr, 0, SEEK_END);
     691             :         return GF_OK;
     692             : }
     693             : 
     694        4293 : GF_Err gf_cache_write_to_cache( const DownloadedCacheEntry entry, const GF_DownloadSession * sess, const char * data, const u32 size, GF_Mutex *mx) {
     695             :         u32 read;
     696        4293 :         CHECK_ENTRY;
     697             : 
     698        4293 :         if (!data || (!entry->writeFilePtr && !entry->mem_storage) || sess != entry->write_session) {
     699           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("Incorrect parameter : data=%p, writeFilePtr=%p mem_storage=%p at "__FILE__"\n", data, entry->writeFilePtr, entry->mem_storage));
     700             :                 return GF_BAD_PARAM;
     701             :         }
     702             : 
     703        4293 :         if (entry->memory_stored) {
     704        3637 :                 if (!entry->cache_blob.mx)
     705           0 :                         entry->cache_blob.mx = mx;
     706             :                 assert(mx);
     707        3637 :                 gf_mx_p(entry->cache_blob.mx);
     708        3637 :                 if (entry->written_in_cache + size > entry->mem_allocated) {
     709          24 :                         u32 new_size = MAX(entry->mem_allocated*2, entry->written_in_cache + size);
     710          24 :                         entry->mem_storage = (u8*)gf_realloc(entry->mem_storage, (new_size+2));
     711          24 :                         entry->mem_allocated = new_size;
     712          24 :                         entry->cache_blob.data = entry->mem_storage;
     713          24 :                         entry->cache_blob.size = entry->contentLength;
     714          24 :                         sprintf(entry->cache_filename, "gmem://%p", &entry->cache_blob);
     715          24 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Reallocating memory cache to %d bytes\n", new_size));
     716             :                 }
     717        3637 :                 memcpy(entry->mem_storage + entry->written_in_cache, data, size);
     718        3637 :                 entry->written_in_cache += size;
     719        3637 :                 memset(entry->mem_storage + entry->written_in_cache, 0, 2);
     720        3637 :                 entry->cache_blob.size = entry->written_in_cache;
     721        3637 :                 gf_mx_v(entry->cache_blob.mx);
     722             : 
     723        3637 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Storing %d bytes to memory\n", size));
     724             :                 return GF_OK;
     725             :         }
     726             : 
     727         656 :         read = (u32) gf_fwrite(data, size, entry->writeFilePtr);
     728         656 :         if (read > 0)
     729         656 :                 entry->written_in_cache+= read;
     730         656 :         if (read != size) {
     731             :                 /* Something bad happened */
     732           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE,
     733             :                        ("[CACHE] Error while writting %d bytes of data to cache : has written only %d bytes.", size, read));
     734           0 :                 gf_cache_close_write_cache(entry, sess, GF_FALSE);
     735           0 :                 gf_file_delete(entry->cache_filename);
     736           0 :                 return GF_IO_ERR;
     737             :         }
     738         656 :         if (gf_fflush(entry->writeFilePtr)) {
     739           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE,
     740             :                        ("[CACHE] Error while flushing data bytes to cache file : %s.", entry->cache_filename));
     741           0 :                 gf_cache_close_write_cache(entry, sess, GF_FALSE);
     742           0 :                 gf_file_delete(entry->cache_filename);
     743           0 :                 return GF_IO_ERR;
     744             :         }
     745         656 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Writing %d bytes to cache\n", size));
     746             :         return GF_OK;
     747             : }
     748             : 
     749         682 : GF_Err gf_cache_delete_entry ( const DownloadedCacheEntry entry )
     750             : {
     751         682 :         if ( !entry )
     752             :                 return GF_OK;
     753         682 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] gf_cache_delete_entry:%d, entry=%p, url=%s\n", __LINE__, entry, entry->url));
     754         682 :         if (entry->writeFilePtr) {
     755             :                 /** Cache should have been close before, abornormal situation */
     756           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] gf_cache_delete_entry:%d, entry=%p, cache has not been closed properly\n", __LINE__, entry));
     757           0 :                 gf_fclose(entry->writeFilePtr);
     758             :         }
     759             : #ifdef ENABLE_WRITE_MX
     760             :         if (entry->write_mutex) {
     761             :                 gf_mx_del(entry->write_mutex);
     762             :         }
     763             : #endif
     764         682 :         if (entry->file_exists && entry->deletableFilesOnDelete) {
     765           9 :                 GF_LOG(GF_LOG_INFO, GF_LOG_CACHE, ("[CACHE] url %s cleanup, deleting %s...\n", entry->url, entry->cache_filename));
     766             :                 //if file exists, delete it (dash client may trash m3u8 files on the fly while converting them to MPD ...)
     767           9 :                 if (gf_file_exists(entry->cache_filename) && (gf_file_delete(entry->cache_filename)!=GF_OK) ) {
     768           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CACHE, ("[CACHE] gf_cache_delete_entry:%d, failed to delete file %s\n", __LINE__, entry->cache_filename));
     769             :                 }
     770             :         }
     771             : #ifdef ENABLE_WRITE_MX
     772             :         entry->write_mutex = NULL;
     773             : #endif
     774         682 :         entry->write_session = NULL;
     775         682 :         entry->writeFilePtr = NULL;
     776         682 :         if (entry->serverETag)
     777         578 :                 gf_free(entry->serverETag);
     778         682 :         entry->serverETag = NULL;
     779             : 
     780         682 :         if (entry->diskETag)
     781          49 :                 gf_free(entry->diskETag);
     782         682 :         entry->diskETag = NULL;
     783             : 
     784         682 :         if (entry->serverLastModified)
     785         533 :                 gf_free(entry->serverLastModified);
     786         682 :         entry->serverLastModified = NULL;
     787             : 
     788         682 :         if (entry->diskLastModified)
     789          39 :                 gf_free(entry->diskLastModified);
     790         682 :         entry->diskLastModified = NULL;
     791             : 
     792         682 :         if ( entry->hash ) {
     793         682 :                 gf_free ( entry->hash );
     794         682 :                 entry->hash = NULL;
     795             :         }
     796         682 :         if ( entry->url ) {
     797         682 :                 gf_free ( entry->url );
     798         682 :                 entry->url = NULL;
     799             :         }
     800         682 :         if ( entry->mimeType ) {
     801         576 :                 gf_free ( entry->mimeType );
     802         576 :                 entry->mimeType = NULL;
     803             :         }
     804         682 :         if (entry->mem_storage && entry->mem_allocated) {
     805         588 :                 gf_free(entry->mem_storage);
     806             :         }
     807         682 :         if ( entry->forced_headers ) {
     808          25 :                 gf_free ( entry->forced_headers );
     809             :         }
     810             : 
     811         682 :         if ( entry->cache_filename ) {
     812         682 :                 gf_free ( entry->cache_filename );
     813         682 :                 entry->cache_filename = NULL;
     814             :         }
     815         682 :         if ( entry->properties ) {
     816             :                 const char * propfile = NULL;
     817          64 :                 if (entry->deletableFilesOnDelete)
     818          13 :                         propfile = gf_cfg_get_filename(entry->properties);
     819             : 
     820          13 :                 if (propfile) {
     821             :                         //this may fail because the prop file is not yet flushed to disk
     822          13 :                         gf_file_delete( propfile );
     823             :                 }
     824             : 
     825          64 :         gf_cfg_del ( entry->properties );
     826          64 :         entry->properties = NULL;
     827             :     }
     828         682 :         entry->dm = NULL;
     829         682 :         if (entry->sessions) {
     830             :                 assert( gf_list_count(entry->sessions) == 0);
     831         682 :                 gf_list_del(entry->sessions);
     832         682 :                 entry->sessions = NULL;
     833             :         }
     834             : 
     835         682 :         gf_free (entry);
     836         682 :         return GF_OK;
     837             : }
     838             : 
     839         732 : Bool gf_cache_check_if_cache_file_is_corrupted(const DownloadedCacheEntry entry)
     840             : {
     841             :         FILE *the_cache = NULL;
     842         732 :         if (entry->cache_filename && strncmp(entry->cache_filename, "gmem://", 7))
     843          87 :                 the_cache = gf_fopen ( entry->cache_filename, "rb" );
     844             : 
     845          87 :         if ( the_cache ) {
     846             :                 char * endPtr;
     847          34 :                 const char * keyValue = gf_cfg_get_key ( entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_CONTENT_SIZE );
     848             : 
     849          34 :                 entry->cacheSize = ( u32 ) gf_fsize(the_cache);
     850          34 :                 gf_fclose ( the_cache );
     851          34 :                 if (keyValue) {
     852          34 :                         entry->contentLength = (u32) strtoul( keyValue, &endPtr, 10);
     853          34 :                         if (*endPtr!='\0' || entry->contentLength != entry->cacheSize) {
     854           2 :                                 entry->flags |= CORRUPTED;
     855           2 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, Cache corrupted: file and cache info size mismatch.\n", __LINE__));
     856             :                         }
     857             :                 } else {
     858           0 :                         entry->flags |= CORRUPTED;
     859           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CACHE, ("[CACHE] gf_cache_create_entry:%d, CACHE is corrupted !\n", __LINE__));
     860             :                 }
     861         698 :         } else if (!entry->mem_storage) {
     862         596 :                 entry->flags |= CORRUPTED;
     863             :         }
     864         732 :         return entry->flags & CORRUPTED;
     865             : }
     866             : 
     867         804 : s32 gf_cache_remove_session_from_cache_entry(DownloadedCacheEntry entry, GF_DownloadSession * sess) {
     868             :         u32 i;
     869             :         s32 count;
     870         804 :         if (!entry || !sess || !entry->sessions)
     871             :                 return -1;
     872         804 :         count = gf_list_count(entry->sessions);
     873         804 :         for (i = 0 ; i < (u32)count; i++) {
     874         804 :                 GF_DownloadSession *s = (GF_DownloadSession*)gf_list_get(entry->sessions, i);
     875         804 :                 if (s == sess) {
     876         804 :                         gf_list_rem(entry->sessions, i);
     877         804 :                         count --;
     878         804 :                         break;
     879             :                 }
     880             :         }
     881         804 :         if (entry->write_session == sess) {
     882             :                 /* OK, this is not optimal to close it since we are in a mutex,
     883             :                 * but we don't want to risk to have another session opening
     884             :                 * a not fully closed cache entry */
     885           0 :                 if (entry->writeFilePtr) {
     886           0 :                         if (gf_fclose(entry->writeFilePtr)) {
     887           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CACHE] gf_cache_remove_session_from_cache_entry:%d, Failed to properly close cache file '%s' of url '%s', cache may be corrupted !\n", __LINE__, entry->cache_filename, entry->url));
     888             :                         }
     889             :                 }
     890           0 :                 entry->writeFilePtr = NULL;
     891           0 :                 entry->write_session = NULL;
     892             : #ifdef ENABLE_WRITE_MX
     893             :                 gf_mx_v(entry->write_mutex);
     894             : #endif
     895             :         }
     896             :         return count;
     897             : }
     898             : 
     899         986 : u32 gf_cache_get_sessions_count_for_cache_entry(const DownloadedCacheEntry entry)
     900             : {
     901         986 :         if (!entry)
     902             :                 return 0;
     903         986 :         return gf_list_count(entry->sessions);
     904             : }
     905             : 
     906             : 
     907         804 : s32 gf_cache_add_session_to_cache_entry(DownloadedCacheEntry entry, GF_DownloadSession * sess) {
     908             :         u32 i;
     909             :         s32 count;
     910         804 :         if (!entry || !sess || !entry->sessions)
     911             :                 return -1;
     912         804 :         count = gf_list_count(entry->sessions);
     913         804 :         for (i = 0 ; i < (u32)count; i++) {
     914           0 :                 GF_DownloadSession *s = (GF_DownloadSession*)gf_list_get(entry->sessions, i);
     915           0 :                 if (s == sess) {
     916             :                         return count;
     917             :                 }
     918             :         }
     919         804 :         gf_list_add(entry->sessions, sess);
     920         804 :         return count + 1;
     921             : }
     922             : 
     923          45 : void gf_cache_set_end_range(DownloadedCacheEntry entry, u64 range_end)
     924             : {
     925          45 :         if (entry) {
     926          40 :                 entry->previousRangeContentLength = entry->contentLength;
     927          40 :                 entry->range_end = range_end;
     928          40 :                 entry->continue_file = GF_TRUE;
     929             :         }
     930          45 : }
     931             : 
     932         804 : Bool gf_cache_is_in_progress(const DownloadedCacheEntry entry)
     933             : {
     934         804 :         if (!entry) return GF_FALSE;
     935         804 :         if (entry->writeFilePtr) return GF_TRUE;
     936         804 :         if (entry->mem_storage && entry->written_in_cache && entry->contentLength && (entry->written_in_cache<entry->contentLength))
     937             :                 return GF_TRUE;
     938         804 :         return GF_FALSE;
     939             : }
     940             : 
     941          43 : Bool gf_cache_set_mime(const DownloadedCacheEntry entry, const char *mime)
     942             : {
     943          43 :         if (!entry || !entry->memory_stored) return GF_FALSE;
     944          43 :         if (entry->mimeType) gf_free(entry->mimeType);
     945          43 :         entry->mimeType = gf_strdup(mime);
     946          43 :         return GF_TRUE;
     947             : }
     948             : 
     949          79 : Bool gf_cache_set_range(const DownloadedCacheEntry entry, u64 size, u64 start_range, u64 end_range)
     950             : {
     951          79 :         if (!entry || !entry->memory_stored) return GF_FALSE;
     952          79 :         entry->range_start = start_range;
     953          79 :         entry->range_end = end_range;
     954          79 :         entry->contentLength = (u32) size;
     955          79 :         entry->continue_file = GF_FALSE;
     956          79 :         return GF_TRUE;
     957             : }
     958             : 
     959          40 : Bool gf_cache_set_headers(const DownloadedCacheEntry entry, const char *headers)
     960             : {
     961          40 :         if (!entry || !entry->memory_stored) return GF_FALSE;
     962          40 :         if (entry->forced_headers) gf_free(entry->forced_headers);
     963          40 :         entry->forced_headers = headers ? gf_strdup(headers) : NULL;
     964          40 :         return GF_TRUE;
     965             : }
     966             : 
     967          51 : char *gf_cache_get_forced_headers(const DownloadedCacheEntry entry)
     968             : {
     969          51 :         if (!entry) return NULL;
     970          42 :         return entry->forced_headers;
     971             : }
     972          43 : void gf_cache_set_downtime(const DownloadedCacheEntry entry, u32 download_time_ms)
     973             : {
     974          43 :         if (entry) entry->downtime = download_time_ms;
     975          43 : }
     976          40 : u32 gf_cache_get_downtime(const DownloadedCacheEntry entry)
     977             : {
     978          40 :         if (!entry) return 0;
     979          31 :         return entry->downtime;
     980             : }
     981       20892 : Bool gf_cache_is_done(const DownloadedCacheEntry entry)
     982             : {
     983             :     Bool res = GF_TRUE;
     984       20892 :     if (entry && entry->external_blob) {
     985       20869 :         gf_mx_p(entry->external_blob->mx);
     986       20869 :         res = (entry->external_blob->flags & GF_BLOB_IN_TRANSFER) ? GF_FALSE : GF_TRUE;
     987       20869 :         gf_mx_v(entry->external_blob->mx);
     988          23 :     } else if (entry) {
     989          19 :         res = (entry->cache_blob.flags & GF_BLOB_IN_TRANSFER) ? GF_FALSE : GF_TRUE;
     990             :     }
     991       20892 :     return res;
     992             : }
     993       20857 : const u8 *gf_cache_get_content(const DownloadedCacheEntry entry, u32 *size)
     994             : {
     995       20857 :     if (!entry) return NULL;
     996       20857 :     if (entry->external_blob) {
     997             :         u8 *data;
     998       20857 :        GF_Err  e = gf_blob_get(entry->cache_filename, &data, size, NULL);
     999       20857 :         if (e) return NULL;
    1000       20857 :         return data;
    1001             :     }
    1002           0 :     *size = entry->cache_blob.size;
    1003           0 :     return entry->cache_blob.data;
    1004             : }
    1005       20857 : void gf_cache_release_content(const DownloadedCacheEntry entry)
    1006             : {
    1007       20857 :     if (!entry) return;
    1008       20857 :     if (!entry->external_blob) return;
    1009       20857 :     gf_blob_release(entry->cache_filename);
    1010             : }
    1011          31 : Bool gf_cache_is_deleted(const DownloadedCacheEntry entry)
    1012             : {
    1013          31 :     if (!entry) return GF_TRUE;
    1014          31 :     if (entry->flags == DELETED) return GF_TRUE;
    1015          31 :     return GF_FALSE;
    1016             : }
    1017             : 
    1018          43 : Bool gf_cache_set_content(const DownloadedCacheEntry entry, GF_Blob *blob, Bool copy, GF_Mutex *mx)
    1019             : {
    1020          43 :         if (!entry || !entry->memory_stored) return GF_FALSE;
    1021             : 
    1022          43 :     if (!blob) {
    1023          11 :         entry->flags = DELETED;
    1024          11 :         return GF_TRUE;
    1025             :     }
    1026          32 :     if (blob->mx)
    1027          24 :         gf_mx_p(blob->mx);
    1028             :         
    1029          32 :     if (!copy) {
    1030          14 :         if (entry->mem_allocated) gf_free(entry->mem_storage);
    1031          14 :                 entry->mem_storage = (u8 *) blob->data;
    1032          14 :         if (!entry->written_in_cache)
    1033          14 :             sprintf(entry->cache_filename, "gmem://%p", blob);
    1034          14 :                 entry->written_in_cache = blob->size;
    1035          14 :                 entry->mem_allocated = 0;
    1036          14 :                 entry->cache_blob.data = NULL;
    1037          14 :                 entry->cache_blob.size = 0;
    1038          14 :         entry->external_blob = blob;
    1039          14 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Storing %d bytes to memory from external module\n", blob->size));
    1040             :     } else {
    1041          18 :                 if (!entry->cache_blob.mx)
    1042           0 :                         entry->cache_blob.mx = mx;
    1043          18 :                 gf_mx_p(entry->cache_blob.mx);
    1044             : 
    1045          18 :         if (blob->size >= entry->mem_allocated) {
    1046             :             u32 new_size;
    1047          11 :             new_size = MAX(entry->mem_allocated*2, blob->size+1);
    1048          11 :             entry->mem_storage = (u8*)gf_realloc(entry->mem_allocated ? entry->mem_storage : NULL, (new_size+2));
    1049          11 :             entry->mem_allocated = new_size;
    1050          11 :             entry->cache_blob.data = entry->mem_storage;
    1051          11 :             entry->cache_blob.size = entry->contentLength;
    1052          11 :             if (!entry->written_in_cache)
    1053          11 :                 sprintf(entry->cache_filename, "gmem://%p", &entry->cache_blob);
    1054          11 :             GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Reallocating memory cache to %d bytes\n", new_size));
    1055             :         }
    1056          18 :         memcpy(entry->mem_storage, blob->data, blob->size);
    1057          18 :         entry->mem_storage[blob->size] = 0;
    1058          18 :         entry->cache_blob.size = entry->written_in_cache = blob->size;
    1059          18 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Storing %d bytes to cache memory\n", blob->size));
    1060             : 
    1061          18 :                 gf_mx_v(entry->cache_blob.mx);
    1062             : 
    1063          18 :                 entry->cache_blob.flags = blob->flags;
    1064             :     }
    1065          32 :         if (blob->flags & GF_BLOB_IN_TRANSFER)
    1066           8 :                 entry->contentLength = 0;
    1067             :         else
    1068          24 :                 entry->contentLength = blob->size;
    1069             : 
    1070          32 :     if (blob->mx)
    1071          24 :         gf_mx_v(blob->mx);
    1072             : 
    1073             :     return GF_TRUE;
    1074             : }
    1075             : 
    1076             : #endif

Generated by: LCOV version 1.13