Migrated static
This commit is contained in:
parent
3b2fc97da1
commit
3f30f8a56e
10 changed files with 90 additions and 75 deletions
|
@ -27,8 +27,10 @@
|
|||
* Added html_builder and migrated to 2.0.0 (1/1 tests passed)
|
||||
* Migrated hot to 4.0.0 (0/0 tests passed)
|
||||
* Added range_header and migrated to 3.0.0 (12/12 tests passed)
|
||||
* Updated static to 3.0.0 (in progress)
|
||||
* Update basic-sdk-2.12.x boilerplate (in progress)
|
||||
* Updated static to 4.0.0 (in progress)
|
||||
* Update basic-sdk-2.12.x_nnbd boilerplate (in progress)
|
||||
* Updated angel_serialize to 5.0.0 (in progress)
|
||||
* Updated angel_serialize_generator to 5.0.0 (in progress)
|
||||
|
||||
# 3.0.0 (Non NNBD)
|
||||
* Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0"
|
||||
|
|
|
@ -35,6 +35,6 @@ void main(List<String> args) async {
|
|||
app.fallback((req, res) => throw AngelHttpException.notFound());
|
||||
|
||||
var server = await http.startServer('127.0.0.1', 3000);
|
||||
print('Serving from ${vDir.source.path}');
|
||||
print('Serving from ${vDir.source!.path}');
|
||||
print('Listening at http://${server.address.address}:${server.port}');
|
||||
}
|
||||
|
|
|
@ -39,17 +39,17 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
|
||||
CachingVirtualDirectory(Angel app, FileSystem fileSystem,
|
||||
{this.accessLevel = CacheAccessLevel.PUBLIC,
|
||||
Directory source,
|
||||
bool debug,
|
||||
Iterable<String> indexFileNames,
|
||||
Directory? source,
|
||||
bool? debug,
|
||||
Iterable<String>? indexFileNames,
|
||||
this.maxAge = 0,
|
||||
this.noCache = false,
|
||||
this.onlyInProduction = false,
|
||||
this.useEtags = true,
|
||||
bool allowDirectoryListing,
|
||||
bool? allowDirectoryListing,
|
||||
bool useBuffer = false,
|
||||
String publicPath,
|
||||
Function(File file, RequestContext req, ResponseContext res) callback})
|
||||
String? publicPath,
|
||||
Function(File file, RequestContext req, ResponseContext res)? callback})
|
||||
: super(app, fileSystem,
|
||||
source: source,
|
||||
indexFileNames: indexFileNames ?? ['index.html'],
|
||||
|
@ -63,26 +63,26 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
File file, FileStat stat, RequestContext req, ResponseContext res) {
|
||||
res.headers['accept-ranges'] = 'bytes';
|
||||
|
||||
if (onlyInProduction == true && req.app.environment.isProduction != true) {
|
||||
if (onlyInProduction == true && req.app!.environment.isProduction != true) {
|
||||
return super.serveFile(file, stat, req, res);
|
||||
}
|
||||
|
||||
var shouldNotCache = noCache == true;
|
||||
|
||||
if (!shouldNotCache) {
|
||||
shouldNotCache = req.headers.value('cache-control') == 'no-cache' ||
|
||||
req.headers.value('pragma') == 'no-cache';
|
||||
shouldNotCache = req.headers!.value('cache-control') == 'no-cache' ||
|
||||
req.headers!.value('pragma') == 'no-cache';
|
||||
}
|
||||
|
||||
if (shouldNotCache) {
|
||||
res.headers['cache-control'] = 'private, max-age=0, no-cache';
|
||||
return super.serveFile(file, stat, req, res);
|
||||
} else {
|
||||
var ifModified = req.headers.ifModifiedSince;
|
||||
var ifModified = req.headers!.ifModifiedSince;
|
||||
var ifRange = false;
|
||||
|
||||
try {
|
||||
ifModified = HttpDate.parse(req.headers.value('if-range'));
|
||||
ifModified = HttpDate.parse(req.headers!.value('if-range')!);
|
||||
ifRange = true;
|
||||
} catch (_) {
|
||||
// Fail silently...
|
||||
|
@ -97,7 +97,7 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
setCachedHeaders(stat.modified, req, res);
|
||||
|
||||
if (useEtags && _etags.containsKey(file.absolute.path)) {
|
||||
res.headers['ETag'] = _etags[file.absolute.path];
|
||||
res.headers['ETag'] = _etags[file.absolute.path]!;
|
||||
}
|
||||
|
||||
if (ifRange) {
|
||||
|
@ -120,18 +120,18 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
// If-modified didn't work; try etags
|
||||
|
||||
if (useEtags == true) {
|
||||
var etagsToMatchAgainst = req.headers['if-none-match'];
|
||||
var etagsToMatchAgainst = req.headers!['if-none-match'];
|
||||
ifRange = false;
|
||||
|
||||
if (etagsToMatchAgainst?.isNotEmpty != true) {
|
||||
etagsToMatchAgainst = req.headers['if-range'];
|
||||
etagsToMatchAgainst = req.headers!['if-range'];
|
||||
ifRange = etagsToMatchAgainst?.isNotEmpty == true;
|
||||
}
|
||||
|
||||
if (etagsToMatchAgainst?.isNotEmpty == true) {
|
||||
var hasBeenModified = false;
|
||||
|
||||
for (var etag in etagsToMatchAgainst) {
|
||||
for (var etag in etagsToMatchAgainst!) {
|
||||
if (etag == '*') {
|
||||
hasBeenModified = true;
|
||||
} else {
|
||||
|
@ -166,16 +166,16 @@ class CachingVirtualDirectory extends VirtualDirectory {
|
|||
|
||||
void setCachedHeaders(
|
||||
DateTime modified, RequestContext req, ResponseContext res) {
|
||||
var privacy = accessLevelToString(accessLevel ?? CacheAccessLevel.PUBLIC);
|
||||
var privacy = accessLevelToString(accessLevel);
|
||||
|
||||
res.headers
|
||||
..['cache-control'] = '$privacy, max-age=${maxAge ?? 0}'
|
||||
..['cache-control'] = '$privacy, max-age=$maxAge'
|
||||
..['last-modified'] = HttpDate.format(modified);
|
||||
|
||||
if (maxAge != null) {
|
||||
var expiry = DateTime.now().add(Duration(seconds: maxAge ?? 0));
|
||||
res.headers['expires'] = HttpDate.format(expiry);
|
||||
}
|
||||
//if (maxAge != null) {
|
||||
var expiry = DateTime.now().add(Duration(seconds: maxAge));
|
||||
res.headers['expires'] = HttpDate.format(expiry);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,14 +28,14 @@ String _pathify(String path) {
|
|||
|
||||
/// A static server plug-in.
|
||||
class VirtualDirectory {
|
||||
String _prefix;
|
||||
Directory _source;
|
||||
String? _prefix;
|
||||
Directory? _source;
|
||||
|
||||
/// The directory to serve files from.
|
||||
Directory get source => _source;
|
||||
Directory? get source => _source;
|
||||
|
||||
/// An optional callback to run before serving files.
|
||||
final Function(File file, RequestContext req, ResponseContext res) callback;
|
||||
final Function(File file, RequestContext req, ResponseContext res)? callback;
|
||||
|
||||
final Angel app;
|
||||
final FileSystem fileSystem;
|
||||
|
@ -47,7 +47,7 @@ class VirtualDirectory {
|
|||
final String publicPath;
|
||||
|
||||
/// If `true` (default: `false`), then if a directory does not contain any of the specific [indexFileNames], a default directory listing will be served.
|
||||
final bool allowDirectoryListing;
|
||||
final bool? allowDirectoryListing;
|
||||
|
||||
/// If `true` (default: `true`), then files will be opened as streams and piped into the request.
|
||||
///
|
||||
|
@ -55,7 +55,7 @@ class VirtualDirectory {
|
|||
final bool useBuffer;
|
||||
|
||||
VirtualDirectory(this.app, this.fileSystem,
|
||||
{Directory source,
|
||||
{Directory? source,
|
||||
this.indexFileNames = const ['index.html'],
|
||||
this.publicPath = '/',
|
||||
this.callback,
|
||||
|
@ -75,9 +75,9 @@ class VirtualDirectory {
|
|||
if (req.method != 'GET' && req.method != 'HEAD') {
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
var path = req.uri.path.replaceAll(_straySlashes, '');
|
||||
var path = req.uri!.path.replaceAll(_straySlashes, '');
|
||||
|
||||
if (_prefix?.isNotEmpty == true && !path.startsWith(_prefix)) {
|
||||
if (_prefix?.isNotEmpty == true && !path.startsWith(_prefix!)) {
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ class VirtualDirectory {
|
|||
/// You can also limit this functionality to specific values of the `Accept` header, ex. `text/html`.
|
||||
/// If [accepts] is `null`, OR at least one of the content types in [accepts] is present,
|
||||
/// the view will be served.
|
||||
RequestHandler pushState(String path, {Iterable accepts}) {
|
||||
RequestHandler pushState(String path, {Iterable? accepts}) {
|
||||
var vPath = path.replaceAll(_straySlashes, '');
|
||||
if (_prefix?.isNotEmpty == true) vPath = '$_prefix/$vPath';
|
||||
|
||||
|
@ -98,7 +98,7 @@ class VirtualDirectory {
|
|||
if (path == vPath) return Future<bool>.value(true);
|
||||
|
||||
if (accepts?.isNotEmpty == true) {
|
||||
if (!accepts.any((x) => req.accepts(x, strict: true))) {
|
||||
if (!accepts!.any((x) => req.accepts(x, strict: true))) {
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
}
|
||||
|
@ -110,17 +110,17 @@ class VirtualDirectory {
|
|||
/// Writes the file at the given virtual [path] to a response.
|
||||
Future<bool> servePath(
|
||||
String path, RequestContext req, ResponseContext res) async {
|
||||
if (_prefix.isNotEmpty) {
|
||||
if (_prefix!.isNotEmpty) {
|
||||
// Only replace the *first* incidence
|
||||
// Resolve: https://github.com/angel-dart/angel/issues/41
|
||||
path = path.replaceFirst(RegExp('^' + _pathify(_prefix)), '');
|
||||
path = path.replaceFirst(RegExp('^' + _pathify(_prefix!)), '');
|
||||
}
|
||||
|
||||
if (path.isEmpty) path = '.';
|
||||
path = path.replaceAll(_straySlashes, '');
|
||||
|
||||
var absolute = source.absolute.uri.resolve(path).toFilePath();
|
||||
var parent = source.absolute.uri.toFilePath();
|
||||
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;
|
||||
|
@ -199,8 +199,8 @@ class VirtualDirectory {
|
|||
});
|
||||
|
||||
for (var entity in entities) {
|
||||
String stub;
|
||||
String type;
|
||||
String? stub;
|
||||
String? type;
|
||||
|
||||
if (entity is File) {
|
||||
type = '[File]';
|
||||
|
@ -217,10 +217,19 @@ class VirtualDirectory {
|
|||
}
|
||||
var href = stub;
|
||||
|
||||
if (relative.isNotEmpty) href = '/' + relative + '/' + stub;
|
||||
if (relative.isNotEmpty) {
|
||||
stub ??= '';
|
||||
href = '/' + relative + '/' + stub;
|
||||
}
|
||||
|
||||
if (entity is Directory) href += '/';
|
||||
href = Uri.encodeFull(href);
|
||||
if (entity is Directory) {
|
||||
if (href == null) {
|
||||
href = '/';
|
||||
} else {
|
||||
href += '/';
|
||||
}
|
||||
}
|
||||
href = Uri.encodeFull(href!);
|
||||
|
||||
res.write('<li><a href="$href">$type $stub</a></li>');
|
||||
}
|
||||
|
@ -233,11 +242,11 @@ class VirtualDirectory {
|
|||
}
|
||||
|
||||
void _ensureContentTypeAllowed(String mimeType, RequestContext req) {
|
||||
var value = req.headers.value('accept');
|
||||
var value = req.headers!.value('accept');
|
||||
var acceptable = value == null ||
|
||||
value?.isNotEmpty != true ||
|
||||
(mimeType?.isNotEmpty == true && value?.contains(mimeType) == true) ||
|
||||
value?.contains('*/*') == true;
|
||||
value.isNotEmpty != true ||
|
||||
(mimeType.isNotEmpty == true && value.contains(mimeType) == true) ||
|
||||
value.contains('*/*') == true;
|
||||
if (!acceptable) {
|
||||
throw AngelHttpException(
|
||||
UnsupportedError(
|
||||
|
@ -253,8 +262,9 @@ class VirtualDirectory {
|
|||
res.headers['accept-ranges'] = 'bytes';
|
||||
|
||||
if (callback != null) {
|
||||
return await req.app.executeHandler(
|
||||
(RequestContext req, ResponseContext res) => callback(file, req, res),
|
||||
return await req.app!.executeHandler(
|
||||
(RequestContext req, ResponseContext res) =>
|
||||
callback!(file, req, res),
|
||||
req,
|
||||
res);
|
||||
}
|
||||
|
@ -267,10 +277,10 @@ class VirtualDirectory {
|
|||
res.contentType = MediaType.parse(type);
|
||||
if (useBuffer == true) res.useBuffer();
|
||||
|
||||
if (req.headers.value('range')?.startsWith('bytes=') != true) {
|
||||
if (req.headers!.value('range')?.startsWith('bytes=') != true) {
|
||||
await res.streamFile(file);
|
||||
} else {
|
||||
var header = RangeHeader.parse(req.headers.value('range'));
|
||||
var header = RangeHeader.parse(req.headers!.value('range')!);
|
||||
var items = RangeHeader.foldItems(header.items);
|
||||
var totalFileSize = await file.length();
|
||||
header = RangeHeader(items);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
name: angel_static
|
||||
description: Static server middleware for Angel. Also capable of serving Range responses.
|
||||
version: 3.0.0
|
||||
version: 4.0.0
|
||||
environment:
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
homepage: https://github.com/angel-dart/static
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
publish_to: none
|
||||
|
@ -12,21 +12,26 @@ dependencies:
|
|||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x_nnbd
|
||||
path: packages/framework
|
||||
range_header:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x_nnbd
|
||||
path: packages/range_header
|
||||
convert: ^3.0.0
|
||||
crypto: ^3.0.0
|
||||
crypto: ^3.0.1
|
||||
file: ^6.1.0
|
||||
http_parser: ^4.0.0
|
||||
path: ^1.4.2
|
||||
range_header: ^2.0.0
|
||||
path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
angel_test:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x_nnbd
|
||||
path: packages/test
|
||||
http:
|
||||
logging: ^1.0.0
|
||||
matcher: ^0.12.0
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.15.7
|
||||
http: ^0.13.2
|
||||
logging: ^1.0.1
|
||||
matcher: ^0.12.10
|
||||
pedantic: ^1.11.0
|
||||
test: ^1.17.3
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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';
|
||||
import 'package:http/http.dart' show Client;
|
||||
import 'package:logging/logging.dart';
|
||||
|
@ -9,9 +8,9 @@ import 'package:test/test.dart';
|
|||
|
||||
void main() {
|
||||
Angel app;
|
||||
AngelHttp http;
|
||||
late AngelHttp http;
|
||||
var testDir = const LocalFileSystem().directory('test');
|
||||
String url;
|
||||
late String url;
|
||||
var client = Client();
|
||||
|
||||
setUp(() async {
|
||||
|
@ -42,7 +41,7 @@ void main() {
|
|||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (http.server != null) await http.server.close(force: true);
|
||||
if (http.server != null) await http.server!.close(force: true);
|
||||
});
|
||||
|
||||
test('can serve files, with correct Content-Type', () async {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
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';
|
||||
|
||||
main() async {
|
||||
void main() async {
|
||||
Angel app;
|
||||
AngelHttp http;
|
||||
Directory testDir = const LocalFileSystem().directory('test');
|
||||
var testDir = const LocalFileSystem().directory('test');
|
||||
app = Angel();
|
||||
http = AngelHttp(app);
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ import 'package:test/test.dart';
|
|||
|
||||
void main() {
|
||||
Angel app;
|
||||
AngelHttp http;
|
||||
late AngelHttp http;
|
||||
var testDir = const LocalFileSystem().directory('test');
|
||||
String url;
|
||||
late String url;
|
||||
var client = Client();
|
||||
|
||||
setUp(() async {
|
||||
|
@ -42,7 +42,7 @@ void main() {
|
|||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (http.server != null) await http.server.close(force: true);
|
||||
if (http.server != null) await http.server!.close(force: true);
|
||||
});
|
||||
|
||||
test('sets etag, cache-control, expires, last-modified', () async {
|
||||
|
|
|
@ -9,9 +9,9 @@ import 'package:test/test.dart';
|
|||
final Directory swaggerUiDistDir =
|
||||
const LocalFileSystem().directory('test/node_modules/swagger-ui-dist');
|
||||
|
||||
main() async {
|
||||
TestClient client;
|
||||
String swaggerUiCssContents, swaggerTestJsContents;
|
||||
void main() async {
|
||||
late TestClient client;
|
||||
late String swaggerUiCssContents, swaggerTestJsContents;
|
||||
|
||||
setUp(() async {
|
||||
// Load file contents
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:test/test.dart';
|
|||
void main() {
|
||||
Angel app;
|
||||
MemoryFileSystem fileSystem;
|
||||
TestClient client;
|
||||
late TestClient client;
|
||||
|
||||
setUp(() async {
|
||||
fileSystem = MemoryFileSystem();
|
||||
|
|
Loading…
Reference in a new issue