1.2.5
This commit is contained in:
parent
2ac66a4877
commit
d30edcdef6
5 changed files with 108 additions and 14 deletions
|
@ -1,3 +1,10 @@
|
|||
# 1.2.5
|
||||
* Fixed a bug where `onlyInProduction` was not properly adhered to.
|
||||
* Fixed another bug where `Accept-Encoding` was not properly adhered to.
|
||||
* Setting `maxAge` to `null` will now prevent a `CachingVirtualDirectory` from sending an `Expires` header.
|
||||
* Pre-built assets can now be mass-deleted with `VirtualDirectory.cleanFromDisk()`.
|
||||
Resolves [#22](https://github.com/angel-dart/static/issues/22).
|
||||
|
||||
# 1.2.4+1
|
||||
Fixed a bug where `Accept-Encoding` was not properly adhered to.
|
||||
|
||||
|
|
|
@ -62,6 +62,8 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
final bool useWeakEtags;
|
||||
|
||||
/// The `max-age` for `Cache-Control`.
|
||||
///
|
||||
/// Set this to `null` to leave no `Expires` header on responses.
|
||||
final int maxAge;
|
||||
|
||||
CachingVirtualDirectory(
|
||||
|
@ -91,7 +93,7 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
@override
|
||||
Future<bool> serveFile(
|
||||
File file, FileStat stat, RequestContext req, ResponseContext res) {
|
||||
if (onlyInProduction == true && req.app.isProduction == true) {
|
||||
if (onlyInProduction == true && req.app.isProduction != true) {
|
||||
return super.serveFile(file, stat, req, res);
|
||||
}
|
||||
|
||||
|
@ -154,7 +156,8 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
generateEtag(buf, weak: useWeakEtags != false, hash: hash);
|
||||
res.headers
|
||||
..[HttpHeaders.ETAG] = etag
|
||||
..[HttpHeaders.CONTENT_TYPE] = lookupMimeType(file.path) ?? 'application/octet-stream';
|
||||
..[HttpHeaders.CONTENT_TYPE] =
|
||||
lookupMimeType(file.path) ?? 'application/octet-stream';
|
||||
setCachedHeaders(stat.modified, req, res);
|
||||
|
||||
if (useWeakEtags == false) {
|
||||
|
@ -174,18 +177,21 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
void setCachedHeaders(
|
||||
DateTime modified, RequestContext req, ResponseContext res) {
|
||||
var privacy = accessLevelToString(accessLevel ?? CacheAccessLevel.PUBLIC);
|
||||
var expiry = new DateTime.now().add(new Duration(seconds: maxAge ?? 0));
|
||||
|
||||
res.headers
|
||||
..[HttpHeaders.CACHE_CONTROL] = '$privacy, max-age=${maxAge ?? 0}'
|
||||
..[HttpHeaders.EXPIRES] = formatDateForHttp(expiry)
|
||||
..[HttpHeaders.LAST_MODIFIED] = formatDateForHttp(modified);
|
||||
|
||||
if (maxAge != null) {
|
||||
var expiry = new DateTime.now().add(new Duration(seconds: maxAge ?? 0));
|
||||
res.headers[HttpHeaders.EXPIRES] = formatDateForHttp(expiry);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> serveAsset(
|
||||
FileInfo fileInfo, RequestContext req, ResponseContext res) {
|
||||
if (onlyInProduction == true && req.app.isProduction == true) {
|
||||
if (onlyInProduction == true && req.app.isProduction != true) {
|
||||
return super.serveAsset(fileInfo, req, res);
|
||||
}
|
||||
|
||||
|
|
|
@ -284,8 +284,17 @@ class VirtualDirectory implements AngelPlugin {
|
|||
? file.openRead().transform(GZIP.encoder)
|
||||
: file.openRead();
|
||||
await stream.pipe(res.io);
|
||||
} else
|
||||
await res.sendFile(file);
|
||||
} else {
|
||||
if (_acceptsGzip(req)) {
|
||||
res.io.headers
|
||||
..set(HttpHeaders.CONTENT_TYPE,
|
||||
lookupMimeType(file.path) ?? 'application/octet-stream')
|
||||
..set(HttpHeaders.CONTENT_ENCODING, 'gzip');
|
||||
await file.openRead().transform(GZIP.encoder).forEach(res.buffer.add);
|
||||
res.end();
|
||||
} else
|
||||
await res.sendFile(file);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -313,7 +322,11 @@ class VirtualDirectory implements AngelPlugin {
|
|||
: file.content;
|
||||
await stream.pipe(res.io);
|
||||
} else {
|
||||
await file.content.forEach(res.buffer.add);
|
||||
if (_acceptsGzip(req)) {
|
||||
res.io.headers.set(HttpHeaders.CONTENT_ENCODING, 'gzip');
|
||||
await file.content.transform(GZIP.encoder).forEach(res.buffer.add);
|
||||
} else
|
||||
await file.content.forEach(res.buffer.add);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -330,8 +343,8 @@ class VirtualDirectory implements AngelPlugin {
|
|||
String originalName = file.filename;
|
||||
for (var transformer in _transformers) {
|
||||
if (++iterations >= 100) {
|
||||
print(
|
||||
'VirtualDirectory has tried 100 times to compile ${file.filename}. Perhaps one of your transformers is not changing the output file\'s extension.');
|
||||
print('VirtualDirectory has tried 100 times to compile ${file
|
||||
.filename}. Perhaps one of your transformers is not changing the output file\'s extension.');
|
||||
throw new AngelHttpException(new StackOverflowError(),
|
||||
statusCode: 500);
|
||||
} else if (iterations < 100) iterations++;
|
||||
|
@ -363,8 +376,8 @@ class VirtualDirectory implements AngelPlugin {
|
|||
var compiled = await compileAsset(asset);
|
||||
if (compiled == null)
|
||||
p.finish(
|
||||
message:
|
||||
'"${entity.absolute.path}" did not require compilation; skipping it.');
|
||||
message: '"${entity.absolute
|
||||
.path}" did not require compilation; skipping it.');
|
||||
else {
|
||||
var outFile = new File(compiled.filename);
|
||||
if (!await outFile.exists()) await outFile.create(recursive: true);
|
||||
|
@ -386,4 +399,47 @@ class VirtualDirectory implements AngelPlugin {
|
|||
|
||||
print('Build of assets in "${source.absolute.path}" complete.');
|
||||
}
|
||||
|
||||
/// Deletes any pre-built assets.
|
||||
Future cleanFromDisk() async {
|
||||
var l = new cli.Logger.standard();
|
||||
print('Cleaning assets in "${source.absolute.path}"...');
|
||||
|
||||
await for (var entity in source.list(recursive: true)) {
|
||||
if (entity is File) {
|
||||
var p = l.progress('Checking "${entity.absolute.path}"');
|
||||
|
||||
try {
|
||||
var asset = new FileInfo.fromFile(entity);
|
||||
var compiled = await compileAsset(asset);
|
||||
if (compiled == null)
|
||||
p.finish(
|
||||
message: '"${entity.absolute
|
||||
.path}" did not require compilation; skipping it.');
|
||||
else {
|
||||
var outFile = new File(compiled.filename);
|
||||
if (await outFile.exists()) {
|
||||
await outFile.delete();
|
||||
p.finish(
|
||||
message: 'Deleted "${compiled
|
||||
.filename}", which was the output of "${entity.absolute
|
||||
.path}".',
|
||||
showTiming: true);
|
||||
} else {
|
||||
p.finish(
|
||||
message:
|
||||
'Output "${compiled.filename}" of "${entity.absolute.path}" does not exist.');
|
||||
}
|
||||
}
|
||||
} on AngelHttpException {
|
||||
// Ignore 500
|
||||
} catch (e, st) {
|
||||
p.finish(message: 'Failed to delete "${entity.absolute.path}".');
|
||||
stderr..writeln(e)..writeln(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print('Purge of assets in "${source.absolute.path}" complete.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ environment:
|
|||
sdk: ">=1.19.0"
|
||||
homepage: https://github.com/angel-dart/static
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
version: 1.2.4+1
|
||||
version: 1.2.5
|
||||
dependencies:
|
||||
angel_framework: ^1.0.0-dev
|
||||
cli_util: ^0.1.1
|
||||
|
|
|
@ -12,7 +12,7 @@ main() {
|
|||
Client client = new Client();
|
||||
|
||||
setUp(() async {
|
||||
app = new Angel(debug: true);
|
||||
app = new Angel();
|
||||
|
||||
await app.configure(new VirtualDirectory(
|
||||
debug: true,
|
||||
|
@ -23,6 +23,7 @@ main() {
|
|||
await app.configure(new VirtualDirectory(
|
||||
debug: true,
|
||||
source: testDir,
|
||||
streamToIO: true,
|
||||
indexFileNames: ['index.php', 'index.txt']));
|
||||
|
||||
app.after.add('Fallback');
|
||||
|
@ -72,4 +73,28 @@ main() {
|
|||
});
|
||||
expect(response.body, equals("index!"));
|
||||
});
|
||||
|
||||
test('can gzip: just gzip', () async {
|
||||
var response = await client
|
||||
.get("$url/sample.txt", headers: {HttpHeaders.ACCEPT_ENCODING: 'gzip'});
|
||||
expect(response.body, equals("Hello world"));
|
||||
expect(response.headers[HttpHeaders.CONTENT_TYPE], contains("text/plain"));
|
||||
expect(response.headers[HttpHeaders.CONTENT_ENCODING], 'gzip');
|
||||
});
|
||||
|
||||
test('can gzip: wildcard', () async {
|
||||
var response = await client
|
||||
.get("$url/sample.txt", headers: {HttpHeaders.ACCEPT_ENCODING: 'foo, *'});
|
||||
expect(response.body, equals("Hello world"));
|
||||
expect(response.headers[HttpHeaders.CONTENT_TYPE], contains("text/plain"));
|
||||
expect(response.headers[HttpHeaders.CONTENT_ENCODING], 'gzip');
|
||||
});
|
||||
|
||||
test('can gzip: gzip and friends', () async {
|
||||
var response = await client
|
||||
.get("$url/sample.txt", headers: {HttpHeaders.ACCEPT_ENCODING: 'gzip, deflate, br'});
|
||||
expect(response.body, equals("Hello world"));
|
||||
expect(response.headers[HttpHeaders.CONTENT_TYPE], contains("text/plain"));
|
||||
expect(response.headers[HttpHeaders.CONTENT_ENCODING], 'gzip');
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue