diff --git a/example/main.dart b/example/main.dart new file mode 100644 index 00000000..f40642ee --- /dev/null +++ b/example/main.dart @@ -0,0 +1,35 @@ +import 'package:angel_cache/angel_cache.dart'; +import 'package:angel_framework/angel_framework.dart'; +import 'package:glob/glob.dart'; + +main() async { + var app = new Angel(); + + // Cache a glob + var cache = new ResponseCache() + ..patterns.addAll([ + new Glob('/*.txt'), + ]); + + // Handle `if-modified-since` header, and also send cached content + app.use(cache.handleRequest); + + // A simple handler that returns a different result every time. + app.get('/date.txt', + (ResponseContext res) => res.write(new DateTime.now().toIso8601String())); + + // Support purging the cache. + app.addRoute('PURGE', '*', (RequestContext req) { + if (req.ip != '127.0.0.1') throw new AngelHttpException.forbidden(); + + cache.purge(req.uri.path); + print('Purged ${req.uri.path}'); + }); + + // The response finalizer that actually saves the content + app.responseFinalizers.add(cache.responseFinalizer); + + var http = new AngelHttp(app); + var server = await http.startServer('127.0.0.1', 3000); + print('Listening at http://${server.address.address}:${server.port}'); +} diff --git a/lib/src/cache.dart b/lib/src/cache.dart index 9fd7df9b..5688a84a 100644 --- a/lib/src/cache.dart +++ b/lib/src/cache.dart @@ -44,9 +44,15 @@ class ResponseCache { if (pattern.allMatches(req.uri.path).isNotEmpty && _cache.containsKey(req.uri.path)) { var response = _cache[req.uri.path]; - //print('${response.timestamp} vs ${modifiedSince}'); + //print('timestamp ${response.timestamp} vs since ${modifiedSince}'); + + if (response.timestamp.compareTo(modifiedSince) <= 0) { + if (timeout != null) { + // If the cache timeout has been met, don't send the cached response. + if (new DateTime.now().toUtc().difference(response.timestamp) >= + timeout) return true; + } - if (response.timestamp.compareTo(modifiedSince) < 0) { res.statusCode = 304; return false; } @@ -63,24 +69,28 @@ class ResponseCache { if (req.method != 'GET' && req.method != 'HEAD') return true; // Check if there is a cache entry. - for (var pattern in patterns) { - if (pattern.allMatches(req.uri.path).isNotEmpty) { - var now = new DateTime.now().toUtc(); + // + // If `if-modified-since` is present, this check has already been performed. + if (req.headers.value('if-modified-since') == null) { + for (var pattern in patterns) { + if (pattern.allMatches(req.uri.path).isNotEmpty) { + var now = new DateTime.now().toUtc(); - if (_cache.containsKey(req.uri.path)) { - var response = _cache[req.uri.path]; + if (_cache.containsKey(req.uri.path)) { + var response = _cache[req.uri.path]; - if (timeout != null) { - // If the cache timeout has been met, don't send the cached response. - if (now.difference(response.timestamp) >= timeout) return true; + if (timeout != null) { + // If the cache timeout has been met, don't send the cached response. + if (now.difference(response.timestamp) >= timeout) return true; + } + + _setCachedHeaders(response.timestamp, req, res); + res + ..headers.addAll(response.headers) + ..buffer.add(response.body) + ..end(); + return false; } - - _setCachedHeaders(response.timestamp, req, res); - res - ..headers.addAll(response.headers) - ..buffer.add(response.body) - ..end(); - return false; } } } diff --git a/test/cache_test.dart b/test/cache_test.dart index 4ec6c603..3bda6e66 100644 --- a/test/cache_test.dart +++ b/test/cache_test.dart @@ -74,7 +74,7 @@ main() async { test('invalidate', () async { await client.sendUnstreamed( - 'PURGE', '/date.txt', {'x-http-method-override': 'PURGE'}); + 'PURGE', '/date.txt', {}); var response = await client.get('/date.txt'); print('Response after invalidation: ${response.body}'); expect(response.body, isNot(response1.body));