Baseflow / Baseflow/flutter_cached_network_image

The libarary is not respecting the cache-control headers

Open
#768 1 comment 10 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
2.6k
Forks
731
Avg merge
3d 9h
Merged PRs (30d)
1

Description

## 🐛 Bug Report

### Expected behavior
on the server side I'm sending these headers along with the image file:
```
{
'cache-control': 'no-cache,max-age=1',
'etag': hash,
'age': '1',
'content-type': 'image/jpeg'
}
```
so what I expect is that each time I call `CachedNetworkImageProvider` the app would send a get request with an `if-none-match` to check if the ETag of the cached file was changed, but I'm not seeing this request on the server side, note that if I use the `flutter_cache_manager` package directly(through `getSingleFile`) with `Image.memory` then it works as expected, somehow it just breaks when using the `flutter_cached_network_image` package.
### Reproduction steps
- Start a backend server that sends the following cache control HTTP header with '[no-cache](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)' which should force the cache manager to validate the cached file each time it is requested:
```
import 'dart:io';
import 'dart:typed_data';
import "package:path/path.dart" show dirname, join;
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:crypto/crypto.dart' as crypto;
import 'package:shelf_router/shelf_router.dart' as shelf_router;

shelf_router.Router router = shelf_router.Router();
late HttpServer server;
String generateMd5(Uint8List data) {
crypto.Hash md5 = crypto.md5;

crypto.Digest digest = md5.convert(data);
return digest.toString();
}

void main(List args) async {
server = await io.serve(router, InternetAddress.anyIPv4, 8081);
router.get('/avatar/', avatarCallback);
}

avatarCallback(shelf.Request request, String key) async {
print("A request was made");
print(request.headers);
Uint8List avatar =
File(join(dirname(Platform.script.path), 'avatar.png')).readAsBytesSync();
String hash = generateMd5(avatar);
Map responseHeaders = {
'cache-control': 'no-cache,max-age=1',
'etag': hash,
'age': '1',
'content-type': 'image/png'
};
if (request.headers.containsKey('if-none-match')) {
print('found if-none-match');
print('request hash: ${request.headers['if-none-match']}');
print("local hash: ${hash}");
if (request.headers['if-none-match'] == hash) {
return shelf.Response(304, headers: responseHeaders);
}
}
return shelf.Response.ok(avatar, headers: responseHeaders);
}

```
I have added a print statement in a place where it is called each time a request is made to the file .

- below is a an example flutter app to show the problem:

```
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';

BaseCacheManager def = DefaultCacheManager();

void main() async {
WidgetsFlutterBinding.ensureInitialized();

runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: HomePage(),
);
}
}

class HomePage extends StatefulWidget {
HomePage({
Key? key,
}) : super(key: key);

@override
State createState() => _HomePageState();
}

class _HomePageState extends State {
String imageUrl = 'http://192.168.88.32:8081/avatar/0';
List imagesChildren = [];

@override
void initState() {
// TODO: implement initState
super.initState();
}

@override
void dispose() {
// TODO: implement dispose
super.dispose();
}

@override
Widget build(BuildContext context) {
print('rebuilding');
print(imagesChildren.length);
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
TextButton(
onPressed: (() async {
Widget wid;
wid = Image.memory(
await def
.getSingleFile(imageUrl)
.then((value) => value.readAsBytesSync()),
width: 50,
height: 50,
);

setState(() {
imagesChildren.add(wid);
});
}),
child: Text('add using cache manager'),
),
TextButton(
onPressed: (() {
Widget wid;
wid = Image(
width: 50,
height: 50,
image: CachedNetworkImageProvider(imageUrl),
);
setState(() {
imagesChildren.add(wid);
});
}),
child: const Text('add using CachedNetworkImageProvider'),
),
ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [...imagesChildren],
),
],
),
),
),
);
}
}

```

- start the server and the flutter app, notice that when you click ' add using cache manager' multiple times, it works as expected(the app sends a request with the cached file's hash to check if the resource was updated, while if you click on the 'add using CachedNetworkImageProvider' multiple times, it only request the file in the first time, then it always shows the cached file and doesn't check the server for updates.
### Configuration

**Version:** 1.x

**Platform:**
- [ x] :iphone: iOS
- [x ] :robot: Android

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.