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
|