1.3.0-alpha
This commit is contained in:
parent
393c4bff02
commit
3f2c29571b
6 changed files with 71 additions and 54 deletions
10
README.md
10
README.md
|
@ -9,25 +9,27 @@ In `pubspec.yaml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_static: ^1.3.0
|
angel_static: ^1.3.0-alpha
|
||||||
```
|
```
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
To serve files from a directory, you need to create a `VirtualDirectory`.
|
To serve files from a directory, you need to create a `VirtualDirectory`.
|
||||||
|
Keep in mind that `angel_static` uses `package:file` instead of `dart:io`.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_static/angel_static.dart';
|
import 'package:angel_static/angel_static.dart';
|
||||||
|
import 'package:file/local.dart';
|
||||||
|
|
||||||
main() async {
|
main() async {
|
||||||
var app = new Angel();
|
var app = new Angel();
|
||||||
|
var fs = const LocalFileSystem();
|
||||||
|
|
||||||
// Normal static server
|
// Normal static server
|
||||||
var vDir = new VirtualDirectory(source: new Directory('./public'));
|
var vDir = new VirtualDirectory(app, fs, source: new Directory('./public'));
|
||||||
|
|
||||||
// Send Cache-Control, ETag, etc. as well
|
// Send Cache-Control, ETag, etc. as well
|
||||||
var vDir = new CachingVirtualDirectory(source: new Directory('./public'));
|
var vDir = new CachingVirtualDirectory(app, fs, source: new Directory('./public'));
|
||||||
|
|
||||||
// Mount the VirtualDirectory's request handler
|
// Mount the VirtualDirectory's request handler
|
||||||
app.use(vDir.handleRequest);
|
app.use(vDir.handleRequest);
|
||||||
|
|
|
@ -128,38 +128,16 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var queue = new StreamQueue(file.openRead());
|
return file.readAsBytes().then((buf) {
|
||||||
|
|
||||||
return new Future<bool>(() async {
|
|
||||||
var buf = new Uint8List(50), hanging = <int>[];
|
|
||||||
int added = 0;
|
|
||||||
|
|
||||||
while (added < 50) {
|
|
||||||
var deficit = 50 - added;
|
|
||||||
var next = await queue.next;
|
|
||||||
|
|
||||||
for (int i = 0; i < deficit; i++) {
|
|
||||||
buf[added + i] = next[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next.length > deficit) {
|
|
||||||
hanging.addAll(next.skip(deficit));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var etag = _etags[file.absolute.path] = weakEtag(buf);
|
var etag = _etags[file.absolute.path] = weakEtag(buf);
|
||||||
|
|
||||||
res.statusCode = 200;
|
res.statusCode = 200;
|
||||||
res.headers
|
res.headers
|
||||||
..['ETag'] = etag
|
..['ETag'] = etag
|
||||||
..['content-type'] =
|
..['content-type'] =
|
||||||
lookupMimeType(file.path) ?? 'application/octet-stream';
|
lookupMimeType(file.path) ?? 'application/octet-stream';
|
||||||
setCachedHeaders(stat.modified, req, res);
|
setCachedHeaders(stat.modified, req, res);
|
||||||
|
|
||||||
res.add(buf);
|
res.add(buf);
|
||||||
res.add(hanging);
|
return false;
|
||||||
|
|
||||||
return queue.rest.pipe(res).then((_) => false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ dependencies:
|
||||||
mime: ^0.9.3
|
mime: ^0.9.3
|
||||||
path: ^1.4.2
|
path: ^1.4.2
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: ^1.0.0
|
angel_test: ^1.1.0-alpha
|
||||||
http: ^0.11.3
|
http: ^0.11.3
|
||||||
mustache4dart: ^1.1.0
|
mustache4dart: ^1.1.0
|
||||||
test: ^0.12.13
|
test: ^0.12.13
|
||||||
|
|
|
@ -75,28 +75,4 @@ main() {
|
||||||
});
|
});
|
||||||
expect(response.body, equals("index!"));
|
expect(response.body, equals("index!"));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can gzip: just gzip', () async {
|
|
||||||
var response = await client
|
|
||||||
.get("$url/sample.txt", headers: {'accept-encoding': 'gzip'});
|
|
||||||
expect(response.body, equals("Hello world"));
|
|
||||||
expect(response.headers['content-type'], contains("text/plain"));
|
|
||||||
expect(response.headers['content-encoding'], 'gzip');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('can gzip: wildcard', () async {
|
|
||||||
var response = await client
|
|
||||||
.get("$url/sample.txt", headers: {'accept-encoding': 'foo, *'});
|
|
||||||
expect(response.body, equals("Hello world"));
|
|
||||||
expect(response.headers['content-type'], contains("text/plain"));
|
|
||||||
expect(response.headers['content-encoding'], 'gzip');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('can gzip: gzip and friends', () async {
|
|
||||||
var response = await client.get("$url/sample.txt",
|
|
||||||
headers: {'accept-encoding': 'gzip, deflate, br'});
|
|
||||||
expect(response.body, equals("Hello world"));
|
|
||||||
expect(response.headers['content-type'], contains("text/plain"));
|
|
||||||
expect(response.headers['content-encoding'], 'gzip');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:angel_static/angel_static.dart';
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:file/local.dart';
|
import 'package:file/local.dart';
|
||||||
import 'package:http/http.dart' show Client;
|
import 'package:http/http.dart' show Client;
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:matcher/matcher.dart';
|
import 'package:matcher/matcher.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
@ -26,6 +27,13 @@ main() {
|
||||||
|
|
||||||
app.dumpTree(showMatchers: true);
|
app.dumpTree(showMatchers: true);
|
||||||
|
|
||||||
|
app.logger = new Logger('angel_static')
|
||||||
|
..onRecord.listen((rec) {
|
||||||
|
print(rec);
|
||||||
|
if (rec.error != null) print(rec.error);
|
||||||
|
if (rec.stackTrace != null) print(rec.stackTrace);
|
||||||
|
});
|
||||||
|
|
||||||
var server = await app.startServer();
|
var server = await app.startServer();
|
||||||
url = "http://${server.address.host}:${server.port}";
|
url = "http://${server.address.host}:${server.port}";
|
||||||
});
|
});
|
||||||
|
@ -43,7 +51,7 @@ main() {
|
||||||
|
|
||||||
expect(response.statusCode, equals(200));
|
expect(response.statusCode, equals(200));
|
||||||
expect(
|
expect(
|
||||||
['ETag', 'cache-control', 'expires', 'last-modified'],
|
['etag', 'cache-control', 'expires', 'last-modified'],
|
||||||
everyElement(predicate(
|
everyElement(predicate(
|
||||||
response.headers.containsKey, 'contained in response headers')));
|
response.headers.containsKey, 'contained in response headers')));
|
||||||
});
|
});
|
||||||
|
|
53
test/push_state_test.dart
Normal file
53
test/push_state_test.dart
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_static/angel_static.dart';
|
||||||
|
import 'package:angel_test/angel_test.dart';
|
||||||
|
import 'package:file/memory.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
Angel app;
|
||||||
|
MemoryFileSystem fileSystem;
|
||||||
|
TestClient client;
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
fileSystem = new MemoryFileSystem();
|
||||||
|
|
||||||
|
var webDir = fileSystem.directory('web');
|
||||||
|
await webDir.create(recursive: true);
|
||||||
|
|
||||||
|
var indexFile = webDir.childFile('index.html');
|
||||||
|
await indexFile.writeAsString('index');
|
||||||
|
|
||||||
|
app = new Angel();
|
||||||
|
|
||||||
|
var vDir = new VirtualDirectory(
|
||||||
|
app,
|
||||||
|
fileSystem,
|
||||||
|
source: webDir,
|
||||||
|
);
|
||||||
|
|
||||||
|
app
|
||||||
|
..use(vDir.handleRequest)
|
||||||
|
..use(vDir.pushState('index.html'))
|
||||||
|
..use('Fallback');
|
||||||
|
|
||||||
|
app.logger = new Logger('push_state')
|
||||||
|
..onRecord.listen(
|
||||||
|
(rec) {
|
||||||
|
print(rec);
|
||||||
|
if (rec.error != null) print(rec.error);
|
||||||
|
if (rec.stackTrace != null) print(rec.stackTrace);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
client = await connectTo(app);
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() => client.close());
|
||||||
|
|
||||||
|
test('serves as fallback', () async {
|
||||||
|
var response = await client.get('/nope');
|
||||||
|
expect(response.body, 'index');
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue