Skip to content

Commit b6ebc7f

Browse files
committed
New configuration durationOnMaxAgeZero
If a server sends "Cache-Control: max-age=0" this might be a misconfiguration on the server; in this case we should ignore it (the behaviour up to now). It might also mean, that the content potentially already expired; for this case this commit provides a new configuration parameter so you reinterpret the duration how long this downloaded file should stay valid.
1 parent 54904e4 commit b6ebc7f

File tree

7 files changed

+57
-11
lines changed

7 files changed

+57
-11
lines changed

flutter_cache_manager/README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ you call this method with other height/width parameters.
6060
When your files are stored on Firebase Storage you can use [flutter_cache_manager_firebase](https://pub.dev/packages/flutter_cache_manager_firebase).
6161

6262
## Customize
63-
The cache manager is customizable by creating a new CacheManager. It is very important to not create more than 1
63+
The cache manager is customizable by creating a new CacheManager. It is very important to not create more than one
6464
CacheManager instance with the same key as these bite each other. In the example down here the manager is created as a
6565
Singleton, but you could also use for example Provider to Provide a CacheManager on the top level of your app.
6666
Below is an example with other settings for the maximum age of files, maximum number of objects
@@ -85,6 +85,7 @@ class CustomCacheManager {
8585
- [How are the cache files stored?](#how-are-the-cache-files-stored)
8686
- [When are the cached files updated?](#when-are-the-cached-files-updated)
8787
- [When are cached files removed?](#when-are-cached-files-removed)
88+
- [Why are cached files kept even though the server sends max-age=0?](#why-are-cached-files-kept-even-though-the-server-sends-max-age0)
8889

8990

9091
### How are the cache files stored?
@@ -113,6 +114,20 @@ The cache knows when files have been used latest. When cleaning the cache (which
113114
deletes files when there are too many, ordered by last use, and when files just haven't been used for longer than
114115
the stale period.
115116

117+
### Why are cached files kept even though the server sends max-age=0?
118+
119+
The case when a web server responds with `Cache-Control: max-age=0` is kind of an edge case.
120+
It could either mean, that the content expires really fast (then `Cache-Control: no-cache` might
121+
be a better response) or it could be that the server has some misconfiguration in place.
122+
123+
There where some confusions among users of this library because of the second case (see also
124+
[this issue](https://github.com/Baseflow/flutter_cache_manager/issues/283) so as a default
125+
behaviour this library ignores `max-age=0` and instead sets the validity of the downloaded file
126+
to `Duration(days: 7)`.
127+
128+
If you want to treat `max-age=0` the same as `no-cache` (or something less rigid like 30 seconds), then
129+
set the `Config` parameter `durationOnMaxAgeZero` to `Duration(seconds: 0)` or `30` or whatever you
130+
think is appropriate.
116131

117132
## Breaking changes in v2
118133
- There is no longer a need to extend on BaseCacheManager, you can directly call the constructor. The BaseCacheManager

flutter_cache_manager/lib/src/config/_config_io.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@ class Config implements def.Config {
77
Config(
88
this.cacheKey, {
99
Duration? stalePeriod,
10+
Duration? durationOnMaxAgeZero,
1011
int? maxNrOfCacheObjects,
1112
CacheInfoRepository? repo,
1213
FileSystem? fileSystem,
1314
FileService? fileService,
1415
}) : stalePeriod = stalePeriod ?? const Duration(days: 30),
16+
durationOnMaxAgeZero = durationOnMaxAgeZero ?? const Duration(days: 7),
1517
maxNrOfCacheObjects = maxNrOfCacheObjects ?? 200,
1618
repo = repo ?? _createRepo(cacheKey),
1719
fileSystem = fileSystem ?? IOFileSystem(cacheKey),
18-
fileService = fileService ?? HttpFileService();
20+
fileService = fileService ??
21+
HttpFileService(
22+
durationOnMaxAgeZero: durationOnMaxAgeZero ??
23+
Duration(days: 7),
24+
);
1925

2026
@override
2127
final CacheInfoRepository repo;
@@ -29,6 +35,9 @@ class Config implements def.Config {
2935
@override
3036
final Duration stalePeriod;
3137

38+
@override
39+
final Duration durationOnMaxAgeZero;
40+
3241
@override
3342
final int maxNrOfCacheObjects;
3443

flutter_cache_manager/lib/src/config/_config_unsupported.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class Config implements def.Config {
1111
//ignore: avoid_unused_constructor_parameters
1212
Duration? stalePeriod,
1313
//ignore: avoid_unused_constructor_parameters
14+
Duration? durationOnMaxAgeZero,
15+
//ignore: avoid_unused_constructor_parameters
1416
int? maxNrOfCacheObjects,
1517
//ignore: avoid_unused_constructor_parameters
1618
CacheInfoRepository? repo,
@@ -34,6 +36,9 @@ class Config implements def.Config {
3436
@override
3537
Duration get stalePeriod => throw UnimplementedError();
3638

39+
@override
40+
Duration get durationOnMaxAgeZero => throw UnimplementedError();
41+
3742
@override
3843
int get maxNrOfCacheObjects => throw UnimplementedError();
3944

flutter_cache_manager/lib/src/config/_config_web.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ class Config implements def.Config {
88
Config(
99
this.cacheKey, {
1010
Duration? stalePeriod,
11+
Duration? durationOnMaxAgeZero,
1112
int? maxNrOfCacheObjects,
1213
CacheInfoRepository? repo,
1314
FileSystem? fileSystem,
1415
FileService? fileService,
1516
}) : stalePeriod = stalePeriod ?? const Duration(days: 30),
17+
durationOnMaxAgeZero = durationOnMaxAgeZero ?? const Duration(days: 7),
1618
maxNrOfCacheObjects = maxNrOfCacheObjects ?? 200,
1719
repo = repo ?? NonStoringObjectProvider(),
1820
fileSystem = fileSystem ?? MemoryCacheSystem(),
19-
fileService = fileService ?? HttpFileService();
21+
fileService = fileService ??
22+
HttpFileService(
23+
durationOnMaxAgeZero: durationOnMaxAgeZero ??
24+
Duration(days: 7),
25+
);
2026

2127
@override
2228
final CacheInfoRepository repo;
@@ -30,6 +36,9 @@ class Config implements def.Config {
3036
@override
3137
final Duration stalePeriod;
3238

39+
@override
40+
final Duration durationOnMaxAgeZero;
41+
3342
@override
3443
final int maxNrOfCacheObjects;
3544

flutter_cache_manager/lib/src/config/config.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ abstract class Config {
1010
/// [stalePeriod] is the time duration in which a cache object is
1111
/// considered 'stale'. When a file is cached but not being used for a
1212
/// certain time the file will be deleted.
13+
/// [durationOnMaxAgeZero] is the time duration a fetched API response is
14+
/// considered up-to-date if the server responds with "max-age=0"
1315
/// [maxNrOfCacheObjects] defines how large the cache is allowed to be. If
1416
/// there are more files the files that haven't been used for the longest
1517
/// time will be removed.
@@ -23,6 +25,7 @@ abstract class Config {
2325
factory Config(
2426
String cacheKey, {
2527
Duration stalePeriod,
28+
Duration durationOnMaxAgeZero,
2629
int maxNrOfCacheObjects,
2730
CacheInfoRepository repo,
2831
FileSystem fileSystem,
@@ -33,6 +36,8 @@ abstract class Config {
3336

3437
Duration get stalePeriod;
3538

39+
Duration get durationOnMaxAgeZero;
40+
3641
int get maxNrOfCacheObjects;
3742

3843
CacheInfoRepository get repo;

flutter_cache_manager/lib/src/web/file_service.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ abstract class FileService {
2323
/// [WebHelper]. One can easily adapt it to use dio or any other http client.
2424
class HttpFileService extends FileService {
2525
final http.Client _httpClient;
26+
final Duration _durationOnMaxAgeZero;
2627

27-
HttpFileService({http.Client? httpClient})
28-
: _httpClient = httpClient ?? http.Client();
28+
HttpFileService({http.Client? httpClient, Duration? durationOnMaxAgeZero})
29+
: _httpClient = httpClient ?? http.Client(),
30+
_durationOnMaxAgeZero = durationOnMaxAgeZero ?? Duration(days: 7);
2931

3032
@override
3133
Future<FileServiceResponse> get(String url,
@@ -36,7 +38,7 @@ class HttpFileService extends FileService {
3638
}
3739
final httpResponse = await _httpClient.send(req);
3840

39-
return HttpGetResponse(httpResponse);
41+
return HttpGetResponse(httpResponse, _durationOnMaxAgeZero);
4042
}
4143
}
4244

@@ -64,12 +66,14 @@ abstract class FileServiceResponse {
6466

6567
/// Basic implementation of a [FileServiceResponse] for http requests.
6668
class HttpGetResponse implements FileServiceResponse {
67-
HttpGetResponse(this._response);
69+
HttpGetResponse(this._response, this._durationOnMaxAgeZero);
6870

6971
final DateTime _receivedTime = clock.now();
7072

7173
final http.StreamedResponse _response;
7274

75+
final Duration _durationOnMaxAgeZero;
76+
7377
@override
7478
int get statusCode => _response.statusCode;
7579

@@ -86,7 +90,7 @@ class HttpGetResponse implements FileServiceResponse {
8690
@override
8791
DateTime get validTill {
8892
// Without a cache-control header we keep the file for a week
89-
var ageDuration = const Duration(days: 7);
93+
var ageDuration = _durationOnMaxAgeZero;
9094
final controlHeader = _header(HttpHeaders.cacheControlHeader);
9195
if (controlHeader != null) {
9296
final controlSettings = controlHeader.split(',');

flutter_cache_manager/lib/src/web/web_helper.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ const statusCodesNewFile = [HttpStatus.ok, HttpStatus.accepted];
1818
const statusCodesFileNotChanged = [HttpStatus.notModified];
1919

2020
class WebHelper {
21-
WebHelper(this._store, FileService? fileFetcher)
22-
: _memCache = {},
23-
fileFetcher = fileFetcher ?? HttpFileService();
21+
WebHelper(this._store, this.fileFetcher)
22+
: _memCache = {};
2423

2524
final CacheStore _store;
2625
@visibleForTesting

0 commit comments

Comments
 (0)