2.0.1
This commit is contained in:
parent
4f642cec90
commit
9f63ef57d9
10 changed files with 64 additions and 38 deletions
|
@ -1,3 +1,8 @@
|
|||
# 2.0.1
|
||||
* Remove use of `sendFile`.
|
||||
* Add a `p.isWithin` check to ensure that paths do not escape the `source` directory.
|
||||
* Handle `HEAD` requests.
|
||||
|
||||
# 2.0.0
|
||||
* Upgrade dependencies to Angel 2 + file@5.
|
||||
* Replace `useStream` with `useBuffer`.
|
||||
|
|
|
@ -18,6 +18,7 @@ Keep in mind that `angel_static` uses `package:file` instead of `dart:io`.
|
|||
|
||||
```dart
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_static/angel_static.dart';
|
||||
import 'package:file/local.dart';
|
||||
|
||||
|
@ -32,10 +33,10 @@ main() async {
|
|||
var vDir = new CachingVirtualDirectory(app, fs, source: new Directory('./public'));
|
||||
|
||||
// Mount the VirtualDirectory's request handler
|
||||
app.use(vDir.handleRequest);
|
||||
app.fallback(vDir.handleRequest);
|
||||
|
||||
// Start your server!!!
|
||||
await app.startServer();
|
||||
await new AngelHttp(app).startServer();
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -49,10 +50,10 @@ the user is requesting that file. This can be very useful for SPA's.
|
|||
var vDir = new CachingVirtualDirectory(...);
|
||||
|
||||
// Mount it
|
||||
app.use(vDir.handleRequest);
|
||||
app.fallback(vDir.handleRequest);
|
||||
|
||||
// Fallback to index.html on 404
|
||||
app.use(vDir.pushState('index.html'));
|
||||
app.fallback(vDir.pushState('index.html'));
|
||||
```
|
||||
|
||||
# Options
|
||||
|
|
|
@ -1,17 +1,33 @@
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_static/angel_static.dart';
|
||||
import 'package:file/local.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var http = new AngelHttp(app);
|
||||
var fs = const LocalFileSystem();
|
||||
var vDir = new VirtualDirectory(
|
||||
app,
|
||||
fs,
|
||||
allowDirectoryListing: true,
|
||||
source: fs.directory(fs.currentDirectory),
|
||||
);
|
||||
var vDir = new CachingVirtualDirectory(app, fs,
|
||||
allowDirectoryListing: true,
|
||||
source: fs.currentDirectory,
|
||||
maxAge: const Duration(days: 24).inSeconds);
|
||||
|
||||
app.mimeTypeResolver
|
||||
..addExtension('', 'text/plain')
|
||||
..addExtension('dart', 'text/dart')
|
||||
..addExtension('lock', 'text/plain')
|
||||
..addExtension('markdown', 'text/plain')
|
||||
..addExtension('md', 'text/plain')
|
||||
..addExtension('yaml', 'text/plain');
|
||||
|
||||
app.logger = new Logger('example')
|
||||
..onRecord.listen((rec) {
|
||||
print(rec);
|
||||
if (rec.error != null) print(rec.error);
|
||||
if (rec.stackTrace != null) print(rec.stackTrace);
|
||||
});
|
||||
|
||||
app.fallback(vDir.handleRequest);
|
||||
|
||||
var server = await http.startServer('127.0.0.1', 3000);
|
||||
|
|
|
@ -3,8 +3,6 @@ import 'dart:convert';
|
|||
import 'dart:io' show HttpDate;
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:file/file.dart';
|
||||
//import 'package:intl/intl.dart';
|
||||
import 'package:mime/mime.dart';
|
||||
import 'virtual_directory.dart';
|
||||
|
||||
/// Generates a weak ETag from the given buffer.
|
||||
|
@ -85,21 +83,21 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
return super.serveFile(file, stat, req, res);
|
||||
} else {
|
||||
if (useEtags == true) {
|
||||
var etags = req.headers['if-none-match'];
|
||||
var etagsToMatchAgainst = req.headers['if-none-match'];
|
||||
|
||||
if (etags?.isNotEmpty == true) {
|
||||
if (etagsToMatchAgainst?.isNotEmpty == true) {
|
||||
bool hasBeenModified = false;
|
||||
|
||||
for (var etag in etags) {
|
||||
for (var etag in etagsToMatchAgainst) {
|
||||
if (etag == '*')
|
||||
hasBeenModified = true;
|
||||
else {
|
||||
hasBeenModified = _etags.containsKey(file.absolute.path) &&
|
||||
_etags[file.absolute.path] == etag;
|
||||
hasBeenModified = !_etags.containsKey(file.absolute.path) ||
|
||||
_etags[file.absolute.path] != etag;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBeenModified) {
|
||||
if (!hasBeenModified) {
|
||||
res.statusCode = 304;
|
||||
setCachedHeaders(stat.modified, req, res);
|
||||
return new Future.value(false);
|
||||
|
@ -128,11 +126,11 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
|
||||
return file.readAsBytes().then((buf) {
|
||||
var etag = _etags[file.absolute.path] = weakEtag(buf);
|
||||
res.statusCode = 200;
|
||||
//res.statusCode = 200;
|
||||
res.headers
|
||||
..['ETag'] = etag
|
||||
..['content-type'] =
|
||||
lookupMimeType(file.path) ?? 'application/octet-stream';
|
||||
..['content-type'] = res.app.mimeTypeResolver.lookup(file.path) ??
|
||||
'application/octet-stream';
|
||||
setCachedHeaders(stat.modified, req, res);
|
||||
res.add(buf);
|
||||
return false;
|
||||
|
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:mime/mime.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
final RegExp _param = new RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?');
|
||||
|
@ -70,7 +69,8 @@ class VirtualDirectory {
|
|||
|
||||
/// Responds to incoming HTTP requests.
|
||||
Future<bool> handleRequest(RequestContext req, ResponseContext res) {
|
||||
if (req.method != 'GET') return new Future<bool>.value(true);
|
||||
if (req.method != 'GET' && req.method != 'HEAD')
|
||||
return new Future<bool>.value(true);
|
||||
var path = req.path.replaceAll(_straySlashes, '');
|
||||
|
||||
if (_prefix?.isNotEmpty == true && !path.startsWith(_prefix))
|
||||
|
@ -114,6 +114,11 @@ class VirtualDirectory {
|
|||
path = path.replaceAll(_straySlashes, '');
|
||||
|
||||
var absolute = source.absolute.uri.resolve(path).toFilePath();
|
||||
var parent = source.absolute.uri.toFilePath();
|
||||
|
||||
if (!p.isWithin(parent, absolute) && !p.equals(parent, absolute))
|
||||
return true;
|
||||
|
||||
var stat = await fileSystem.stat(absolute);
|
||||
return await serveStat(absolute, path, stat, req, res);
|
||||
}
|
||||
|
@ -140,11 +145,13 @@ class VirtualDirectory {
|
|||
final index =
|
||||
fileSystem.file(directory.absolute.uri.resolve(indexFileName));
|
||||
if (await index.exists()) {
|
||||
if (req.method == 'HEAD') return false;
|
||||
return await serveFile(index, stat, req, res);
|
||||
}
|
||||
}
|
||||
|
||||
if (allowDirectoryListing == true) {
|
||||
if (req.method == 'HEAD') return false;
|
||||
res.contentType = new MediaType('text', 'html');
|
||||
res
|
||||
..write('<!DOCTYPE html>')
|
||||
|
@ -216,7 +223,7 @@ class VirtualDirectory {
|
|||
/// Writes the contents of a file to a response.
|
||||
Future<bool> serveFile(
|
||||
File file, FileStat stat, RequestContext req, ResponseContext res) async {
|
||||
res.statusCode = 200;
|
||||
if (req.method == 'HEAD') return false;
|
||||
|
||||
if (callback != null) {
|
||||
var r = callback(file, req, res);
|
||||
|
@ -225,17 +232,13 @@ class VirtualDirectory {
|
|||
//if (r != null && r != true) return r;
|
||||
}
|
||||
|
||||
var type = lookupMimeType(file.path) ?? 'application/octet-stream';
|
||||
var type =
|
||||
app.mimeTypeResolver.lookup(file.path) ?? 'application/octet-stream';
|
||||
_ensureContentTypeAllowed(type, req);
|
||||
res.contentType = new MediaType.parse(type);
|
||||
|
||||
if (useBuffer == true) {
|
||||
res.useBuffer();
|
||||
await res.sendFile(file);
|
||||
} else {
|
||||
await res.streamFile(file);
|
||||
}
|
||||
|
||||
if (useBuffer == true) res.useBuffer();
|
||||
await res.streamFile(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,15 @@ environment:
|
|||
sdk: ">=1.8.0 <3.0.0"
|
||||
homepage: https://github.com/angel-dart/static
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
version: 2.0.0
|
||||
version: 2.0.1
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
file: ^5.0.0
|
||||
http_parser: ^3.0.0
|
||||
mime: ^0.9.3
|
||||
path: ^1.4.2
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0-alpha
|
||||
http: ^0.11.3
|
||||
http:
|
||||
logging: ^0.11.0
|
||||
matcher: ^0.12.0
|
||||
mustache4dart: ^3.0.0-dev.0.0
|
||||
test: ^1.0.0
|
||||
|
|
2
test/HELLO.md
Normal file
2
test/HELLO.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# hello
|
||||
world!
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_static/angel_static.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
|
@ -41,7 +42,7 @@ main() {
|
|||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (http.httpServer != null) await http.httpServer.close(force: true);
|
||||
if (http.server != null) await http.server.close(force: true);
|
||||
});
|
||||
|
||||
test('can serve files, with correct Content-Type', () async {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_static/angel_static.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io' show HttpDate;
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_static/angel_static.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/local.dart';
|
||||
|
@ -42,7 +43,7 @@ main() {
|
|||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (http.httpServer != null) await http.httpServer.close(force: true);
|
||||
if (http.server != null) await http.server.close(force: true);
|
||||
});
|
||||
|
||||
test('sets etag, cache-control, expires, last-modified', () async {
|
||||
|
|
Loading…
Reference in a new issue