Migrated static

This commit is contained in:
thomashii@dukefirehawk.com 2021-05-01 11:53:04 +08:00
parent 3b2fc97da1
commit 3f30f8a56e
10 changed files with 90 additions and 75 deletions

View file

@ -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"

View file

@ -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}');
}

View file

@ -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);
//}
}
}

View file

@ -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);

View file

@ -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

View file

@ -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 {

View file

@ -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);

View file

@ -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 {

View file

@ -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

View file

@ -8,7 +8,7 @@ import 'package:test/test.dart';
void main() {
Angel app;
MemoryFileSystem fileSystem;
TestClient client;
late TestClient client;
setUp(() async {
fileSystem = MemoryFileSystem();