Published proxy and file_service

This commit is contained in:
thomashii 2021-06-10 16:47:05 +08:00
parent e25b67d41f
commit 70c4882727
21 changed files with 177 additions and 138 deletions

View file

@ -2,7 +2,7 @@ name: angel3_auth
description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more. description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more.
version: 4.0.4 version: 4.0.4
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/auth homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/auth
publish_to: none #publish_to: none
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.12.0 <3.0.0'
dependencies: dependencies:

View file

@ -0,0 +1,12 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,3 +1,9 @@
# 4.0.0
* Migrated to support Dart SDK 2.12.x NNBD
# 3.0.0
* Migrated to work with Dart SDK 2.12.x Non NNBD
# 2.0.1 # 2.0.1
* Pass everything through `_jsonifyToSD` when returning responses. * Pass everything through `_jsonifyToSD` when returning responses.

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017 The Angel Framework Copyright (c) 2021 dukefirehawk.com
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,6 +1,9 @@
# file_service # angel3_file_service
[![Pub](https://img.shields.io/pub/v/angel_file_service.svg)](https://pub.dartlang.org/packages/angel_file_service) [![version](https://img.shields.io/badge/pub-v4.0.0-brightgreen)](https://pub.dartlang.org/packages/angel3_file_service)
[![build status](https://travis-ci.org/angel-dart/file_service.svg)](https://travis-ci.org/angel-dart/file_service) [![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/file_service/LICENSE)
Angel service that persists data to a file on disk, stored as a JSON list. It uses a simple Angel service that persists data to a file on disk, stored as a JSON list. It uses a simple
mutex to prevent race conditions, and caches contents in memory until changes mutex to prevent race conditions, and caches contents in memory until changes

View file

@ -1,3 +1,4 @@
include: package:pedantic/analysis_options.yaml
analyzer: analyzer:
strong-mode: strong-mode:
implicit-casts: false implicit-casts: false

View file

@ -1,5 +1,5 @@
import 'package:angel_file_service/angel_file_service.dart'; import 'package:angel3_file_service/angel3_file_service.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
configureServer(Angel app) async { configureServer(Angel app) async {

View file

@ -1,18 +1,18 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:pool/pool.dart'; import 'package:pool/pool.dart';
/// Persists in-memory changes to a file on disk. /// Persists in-memory changes to a file on disk.
class JsonFileService extends Service<String, Map<String, dynamic>> { class JsonFileService extends Service<String, Map<String, dynamic>> {
FileStat _lastStat; FileStat? _lastStat;
final Pool _mutex = new Pool(1); final Pool _mutex = new Pool(1);
MapService _store; late MapService _store;
final File file; final File file;
JsonFileService(this.file, JsonFileService(this.file,
{bool allowRemoveAll: false, bool allowQuery: true, MapService store}) { {bool allowRemoveAll: false, bool allowQuery: true, MapService? store}) {
_store = store ?? _store = store ??
new MapService( new MapService(
allowRemoveAll: allowRemoveAll == true, allowRemoveAll: allowRemoveAll == true,
@ -32,7 +32,7 @@ class JsonFileService extends Service<String, Map<String, dynamic>> {
if (_lastStat == null || if (_lastStat == null ||
stat.modified.millisecondsSinceEpoch > stat.modified.millisecondsSinceEpoch >
_lastStat.modified.millisecondsSinceEpoch) { _lastStat!.modified.millisecondsSinceEpoch) {
_lastStat = stat; _lastStat = stat;
var contents = await file.readAsString(); var contents = await file.readAsString();
@ -59,18 +59,18 @@ class JsonFileService extends Service<String, Map<String, dynamic>> {
@override @override
Future<List<Map<String, dynamic>>> index( Future<List<Map<String, dynamic>>> index(
[Map<String, dynamic> params]) async => [Map<String, dynamic>? params]) async =>
_load() _load()
.then((_) => _store.index(params)) .then((_) => _store.index(params))
.then((it) => it.map(_jsonifyToSD).toList()); .then((it) => it.map(_jsonifyToSD).toList());
@override @override
Future<Map<String, dynamic>> read(id, [Map<String, dynamic> params]) => Future<Map<String, dynamic>> read(id, [Map<String, dynamic>? params]) =>
_load().then((_) => _store.read(id, params)).then(_jsonifyToSD); _load().then((_) => _store.read(id, params)).then(_jsonifyToSD);
@override @override
Future<Map<String, dynamic>> create(data, Future<Map<String, dynamic>> create(data,
[Map<String, dynamic> params]) async { [Map<String, dynamic>? params]) async {
await _load(); await _load();
var created = await _store.create(data, params).then(_jsonifyToSD); var created = await _store.create(data, params).then(_jsonifyToSD);
await _save(); await _save();
@ -78,7 +78,8 @@ class JsonFileService extends Service<String, Map<String, dynamic>> {
} }
@override @override
Future<Map<String, dynamic>> remove(id, [Map<String, dynamic> params]) async { Future<Map<String, dynamic>> remove(id,
[Map<String, dynamic>? params]) async {
await _load(); await _load();
var r = await _store.remove(id, params).then(_jsonifyToSD); var r = await _store.remove(id, params).then(_jsonifyToSD);
await _save(); await _save();
@ -87,7 +88,7 @@ class JsonFileService extends Service<String, Map<String, dynamic>> {
@override @override
Future<Map<String, dynamic>> update(id, data, Future<Map<String, dynamic>> update(id, data,
[Map<String, dynamic> params]) async { [Map<String, dynamic>? params]) async {
await _load(); await _load();
var r = await _store.update(id, data, params).then(_jsonifyToSD); var r = await _store.update(id, data, params).then(_jsonifyToSD);
await _save(); await _save();
@ -96,7 +97,7 @@ class JsonFileService extends Service<String, Map<String, dynamic>> {
@override @override
Future<Map<String, dynamic>> modify(id, data, Future<Map<String, dynamic>> modify(id, data,
[Map<String, dynamic> params]) async { [Map<String, dynamic>? params]) async {
await _load(); await _load();
var r = await _store.update(id, data, params).then(_jsonifyToSD); var r = await _store.update(id, data, params).then(_jsonifyToSD);
await _save(); await _save();

View file

@ -1,18 +1,13 @@
name: angel_file_service name: angel3_file_service
version: 3.0.0 version: 4.0.0
description: Angel service that persists data to a file on disk. description: Angel service that persists data to a file on disk.
author: Tobe O <thosakwe@gmail.com> homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/file_service
homepage: https://github.com/angel-dart/file_service
publish_to: none
environment: environment:
sdk: ">=2.10.0 <3.0.0" sdk: '>=2.12.0 <3.0.0'
dependencies: dependencies:
angel_framework: angel3_framework: ^4.0.0
git: file: ^6.1.1
url: https://github.com/dukefirehawk/angel.git pool: ^1.5.0
ref: sdk-2.12.x
path: packages/framework
file: ^6.1.0
pool: ^1.0.0
dev_dependencies: dev_dependencies:
test: ^1.16.5 test: ^1.17.7
pedantic: ^1.11.0

View file

@ -1,12 +1,12 @@
import 'package:angel_file_service/angel_file_service.dart'; import 'package:angel3_file_service/angel3_file_service.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
main() { void main() {
MemoryFileSystem fs; MemoryFileSystem fs;
File dbFile; File dbFile;
JsonFileService service; late JsonFileService service;
setUp(() async { setUp(() async {
fs = new MemoryFileSystem(); fs = new MemoryFileSystem();

12
packages/proxy/AUTHORS.md Normal file
View file

@ -0,0 +1,12 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,3 +1,9 @@
# 4.0.0
* Migrated to support Dart SDK 2.12.x NNBD
# 3.0.0
* Migrated to work with Dart SDK 2.12.x Non NNBD
# 2.2.0 # 2.2.0
* Use `http.Client` instead of `http.BaseClient`, and make it an * Use `http.Client` instead of `http.BaseClient`, and make it an
optional parameter. optional parameter.

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2016 The Angel Framework Copyright (c) 2021 dukefirehawk.com
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,15 +1,18 @@
# proxy # angel3_proxy
[![Pub](https://img.shields.io/pub/v/angel_proxy.svg)](https://pub.dartlang.org/packages/angel_proxy) [![version](https://img.shields.io/badge/pub-v4.0.0-brightgreen)](https://pub.dartlang.org/packages/angel3_proxy)
[![build status](https://travis-ci.org/angel-dart/proxy.svg)](https://travis-ci.org/angel-dart/proxy) [![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/proxy/LICENSE)
Angel middleware to forward requests to another server (i.e. `webdev serve`). Angel middleware to forward requests to another server (i.e. `webdev serve`).
Also supports WebSockets. Also supports WebSockets.
```dart ```dart
import 'package:angel_proxy/angel_proxy.dart'; import 'package:angel3_proxy/angel3_proxy.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
main() async { void main() async {
// Forward requests instead of serving statically. // Forward requests instead of serving statically.
// You can also pass a URI, instead of a string. // You can also pass a URI, instead of a string.
var proxy1 = Proxy('http://localhost:3000'); var proxy1 = Proxy('http://localhost:3000');

View file

@ -1,12 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel3_framework/http.dart';
import 'package:angel_proxy/angel_proxy.dart'; import 'package:angel3_proxy/angel3_proxy.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
final Duration timeout = Duration(seconds: 5); final Duration timeout = Duration(seconds: 5);
main() async { void main() async {
var app = Angel(); var app = Angel();
// Forward any /api requests to pub. // Forward any /api requests to pub.
@ -16,7 +16,7 @@ main() async {
publicPath: '/pub', publicPath: '/pub',
timeout: timeout, timeout: timeout,
); );
app.all("/pub/*", pubProxy.handleRequest); app.all('/pub/*', pubProxy.handleRequest);
// Surprise! We can also proxy WebSockets. // Surprise! We can also proxy WebSockets.
// //

View file

@ -1,3 +1,3 @@
library angel_proxy; library angel3_proxy;
export 'src/proxy_layer.dart'; export 'src/proxy_layer.dart';

View file

@ -1,8 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:convert'; import 'dart:convert';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel3_framework/http.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
@ -14,7 +14,7 @@ final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
/// ///
/// Supports WebSockets, in addition to regular HTTP requests. /// Supports WebSockets, in addition to regular HTTP requests.
class Proxy { class Proxy {
String _prefix; String? _prefix;
/// The underlying [Client] to use. /// The underlying [Client] to use.
final http.Client httpClient; final http.Client httpClient;
@ -26,29 +26,31 @@ class Proxy {
final String publicPath; final String publicPath;
/// If `null` then no timout is added for requests /// If `null` then no timout is added for requests
final Duration timeout; final Duration? timeout;
Proxy( Proxy(
baseUrl, { baseUrl, {
http.Client httpClient, http.Client? httpClient,
this.publicPath = '/', this.publicPath = '/',
this.recoverFromDead = true, this.recoverFromDead = true,
this.recoverFrom404 = true, this.recoverFrom404 = true,
this.timeout, this.timeout,
}) : this.baseUrl = baseUrl is Uri ? baseUrl : Uri.parse(baseUrl.toString()), }) : baseUrl = baseUrl is Uri ? baseUrl : Uri.parse(baseUrl.toString()),
this.httpClient = httpClient ?? http.Client() { httpClient = httpClient ?? http.Client() {
if (!this.baseUrl.hasScheme || !this.baseUrl.hasAuthority) { if (!this.baseUrl.hasScheme || !this.baseUrl.hasAuthority) {
throw ArgumentError( throw ArgumentError(
'Invalid `baseUrl`. URI must have both a scheme and authority.'); 'Invalid `baseUrl`. URI must have both a scheme and authority.');
} }
if (this.recoverFromDead == null) { /*
throw ArgumentError.notNull("recoverFromDead"); if (recoverFromDead == null) {
throw ArgumentError.notNull('recoverFromDead');
} }
if (this.recoverFrom404 == null) { if (recoverFrom404 == null) {
throw ArgumentError.notNull("recoverFrom404"); throw ArgumentError.notNull('recoverFrom404');
} }
*/
_prefix = publicPath?.replaceAll(_straySlashes, '') ?? ''; _prefix = publicPath.replaceAll(_straySlashes, '');
} }
void close() => httpClient.close(); void close() => httpClient.close();
@ -58,7 +60,7 @@ class Proxy {
/// You can also limit this functionality to specific values of the `Accept` header, ex. `text/html`. /// 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, /// If [accepts] is `null`, OR at least one of the content types in [accepts] is present,
/// the view will be served. /// the view will be served.
RequestHandler pushState(String path, {Iterable accepts}) { RequestHandler pushState(String path, {Iterable? accepts}) {
var vPath = path.replaceAll(_straySlashes, ''); var vPath = path.replaceAll(_straySlashes, '');
if (_prefix?.isNotEmpty == true) vPath = '$_prefix/$vPath'; if (_prefix?.isNotEmpty == true) vPath = '$_prefix/$vPath';
@ -67,7 +69,7 @@ class Proxy {
if (path == vPath) return Future<bool>.value(true); if (path == vPath) return Future<bool>.value(true);
if (accepts?.isNotEmpty == 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); return Future<bool>.value(true);
} }
} }
@ -80,8 +82,8 @@ class Proxy {
Future<bool> handleRequest(RequestContext req, ResponseContext res) { Future<bool> handleRequest(RequestContext req, ResponseContext res) {
var path = req.path.replaceAll(_straySlashes, ''); var path = req.path.replaceAll(_straySlashes, '');
if (_prefix.isNotEmpty) { if (_prefix!.isNotEmpty) {
if (!p.isWithin(_prefix, path) && !p.equals(_prefix, path)) { if (!p.isWithin(_prefix!, path) && !p.equals(_prefix!, path)) {
return Future<bool>.value(true); return Future<bool>.value(true);
} }
@ -100,12 +102,12 @@ class Proxy {
try { try {
if (req is HttpRequestContext && if (req is HttpRequestContext &&
WebSocketTransformer.isUpgradeRequest(req.rawRequest)) { WebSocketTransformer.isUpgradeRequest(req.rawRequest!)) {
res.detach(); res.detach();
uri = uri.replace(scheme: uri.scheme == 'https' ? 'wss' : 'ws'); uri = uri.replace(scheme: uri.scheme == 'https' ? 'wss' : 'ws');
try { try {
var local = await WebSocketTransformer.upgrade(req.rawRequest); var local = await WebSocketTransformer.upgrade(req.rawRequest!);
var remote = await WebSocket.connect(uri.toString()); var remote = await WebSocket.connect(uri.toString());
scheduleMicrotask(() => local.pipe(remote)); scheduleMicrotask(() => local.pipe(remote));
@ -121,23 +123,23 @@ class Proxy {
var headers = <String, String>{ var headers = <String, String>{
'host': uri.authority, 'host': uri.authority,
'x-forwarded-for': req.remoteAddress.address, 'x-forwarded-for': req.remoteAddress.address,
'x-forwarded-port': req.uri.port.toString(), 'x-forwarded-port': req.uri!.port.toString(),
'x-forwarded-host': 'x-forwarded-host':
req.headers.host ?? req.headers.value('host') ?? 'none', req.headers!.host ?? req.headers!.value('host') ?? 'none',
'x-forwarded-proto': uri.scheme, 'x-forwarded-proto': uri.scheme,
}; };
req.headers.forEach((name, values) { req.headers!.forEach((name, values) {
headers[name] = values.join(','); headers[name] = values.join(',');
}); });
headers[HttpHeaders.cookieHeader] = headers[HttpHeaders.cookieHeader] =
req.cookies.map<String>((c) => '${c.name}=${c.value}').join('; '); req.cookies.map<String>((c) => '${c.name}=${c.value}').join('; ');
List<int> body; List<int>? body;
if (!req.hasParsedBody) { if (!req.hasParsedBody) {
body = await req.body body = await req.body!
.fold<BytesBuilder>(BytesBuilder(), (bb, buf) => bb..add(buf)) .fold<BytesBuilder>(BytesBuilder(), (bb, buf) => bb..add(buf))
.then((bb) => bb.takeBytes()); .then((bb) => bb.takeBytes());
} }
@ -153,7 +155,7 @@ class Proxy {
} }
var future = accessRemote(); var future = accessRemote();
if (timeout != null) future = future.timeout(timeout); if (timeout != null) future = future.timeout(timeout!);
rs = await future; rs = await future;
} on TimeoutException catch (e, st) { } on TimeoutException catch (e, st) {
if (recoverFromDead) return true; if (recoverFromDead) return true;
@ -163,7 +165,7 @@ class Proxy {
stackTrace: st, stackTrace: st,
statusCode: 504, statusCode: 504,
message: message:
'Connection to remote host "$uri" timed out after ${timeout.inMilliseconds}ms.', 'Connection to remote host "$uri" timed out after ${timeout!.inMilliseconds}ms.',
); );
} catch (e) { } catch (e) {
if (recoverFromDead && e is! AngelHttpException) return true; if (recoverFromDead && e is! AngelHttpException) return true;
@ -176,7 +178,7 @@ class Proxy {
MediaType mediaType; MediaType mediaType;
if (rs.headers.containsKey(HttpHeaders.contentTypeHeader)) { if (rs.headers.containsKey(HttpHeaders.contentTypeHeader)) {
try { try {
mediaType = MediaType.parse(rs.headers[HttpHeaders.contentTypeHeader]); mediaType = MediaType.parse(rs.headers[HttpHeaders.contentTypeHeader]!);
} on FormatException catch (e, st) { } on FormatException catch (e, st) {
if (recoverFromDead) return true; if (recoverFromDead) return true;

View file

@ -1,21 +1,18 @@
name: angel_proxy name: angel3_proxy
version: 4.0.0
description: Angel middleware to forward requests to another server (i.e. pub serve). description: Angel middleware to forward requests to another server (i.e. pub serve).
version: 2.2.0 homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/proxy
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/proxy
environment: environment:
sdk: ">=2.10.0 <2.12.0" sdk: '>=2.12.0 <3.0.0'
dependencies: dependencies:
angel_framework: #^2.0.0-alpha angel3_framework: ^4.0.0
path: ../framework http: ^0.13.3
http: ^0.12.0 http_parser: ^4.0.0
http_parser: ^3.0.0 path: ^1.8.0
path: ^1.0.0
dev_dependencies: dev_dependencies:
angel_test: #^2.0.0-alpha angel3_test: ^4.0.0
path: ../test angel3_mock_request: ^2.0.0
logging: logging: ^1.0.1
mock_request: pedantic: ^1.11.0
pedantic: ^1.0.0 test: ^1.17.7
test: ^1.15.7

View file

@ -1,22 +1,23 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel3_framework/http.dart';
import 'package:angel_proxy/angel_proxy.dart'; import 'package:angel3_proxy/angel3_proxy.dart';
import 'package:http/io_client.dart' as http; import 'package:http/io_client.dart' as http;
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'common.dart'; import 'common.dart';
void main() { void main() {
Angel app; Angel? app;
var client = http.IOClient(); var client = http.IOClient();
HttpServer server, testServer; //late HttpServer server;
String url; late HttpServer testServer;
String? url;
setUp(() async { setUp(() async {
app = Angel(); app = Angel();
var appHttp = AngelHttp(app); var appHttp = AngelHttp(app!);
testServer = await startTestServer(); testServer = await startTestServer();
@ -32,15 +33,15 @@ void main() {
print('Proxy 1 on: ${proxy1.baseUrl}'); print('Proxy 1 on: ${proxy1.baseUrl}');
print('Proxy 2 on: ${proxy2.baseUrl}'); print('Proxy 2 on: ${proxy2.baseUrl}');
app.all('/proxy/*', proxy1.handleRequest); app!.all('/proxy/*', proxy1.handleRequest);
app.all('*', proxy2.handleRequest); app!.all('*', proxy2.handleRequest);
app.fallback((req, res) { app!.fallback((req, res) {
print('Intercepting empty from ${req.uri}'); print('Intercepting empty from ${req.uri}');
res.write('intercept empty'); res.write('intercept empty');
}); });
app.logger = Logger('angel'); app!.logger = Logger('angel');
Logger.root.onRecord.listen((rec) { Logger.root.onRecord.listen((rec) {
print(rec); print(rec);
@ -53,32 +54,32 @@ void main() {
}); });
tearDown(() async { tearDown(() async {
await testServer?.close(force: true); await testServer.close(force: true);
await server?.close(force: true); //await server.close(force: true);
app = null; app = null;
url = null; url = null;
}); });
test('publicPath', () async { test('publicPath', () async {
final response = await client.get('$url/proxy/hello'); final response = await client.get(Uri.parse('$url/proxy/hello'));
print('Response: ${response.body}'); print('Response: ${response.body}');
expect(response.body, equals('world')); expect(response.body, equals('world'));
}); });
test('empty', () async { test('empty', () async {
var response = await client.get('$url/proxy/empty'); var response = await client.get(Uri.parse('$url/proxy/empty'));
print('Response: ${response.body}'); print('Response: ${response.body}');
expect(response.body, 'intercept empty'); expect(response.body, 'intercept empty');
}); });
test('mapTo', () async { test('mapTo', () async {
final response = await client.get('$url/bar'); final response = await client.get(Uri.parse('$url/bar'));
print('Response: ${response.body}'); print('Response: ${response.body}');
expect(response.body, equals('baz')); expect(response.body, equals('baz'));
}); });
test('original buffer', () async { test('original buffer', () async {
var response = await client.post('$url/proxy/body', var response = await client.post(Uri.parse('$url/proxy/body'),
body: json.encode({'foo': 'bar'}), body: json.encode({'foo': 'bar'}),
headers: {'content-type': 'application/json'}); headers: {'content-type': 'application/json'});
print('Response: ${response.body}'); print('Response: ${response.body}');

View file

@ -1,8 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel3_framework/http.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
Future<HttpServer> startTestServer() { Future<HttpServer> startTestServer() {
@ -12,7 +12,7 @@ Future<HttpServer> startTestServer() {
app.get('/foo/bar', (req, res) => res.write('baz')); app.get('/foo/bar', (req, res) => res.write('baz'));
app.post('/body', (RequestContext req, res) async { app.post('/body', (RequestContext req, res) async {
var body = await req.parseBody().then((_) => req.bodyAsMap); var body = await req.parseBody().then((_) => req.bodyAsMap);
app.logger.info('Body: $body'); app.logger!.info('Body: $body');
return body; return body;
}); });

View file

@ -1,59 +1,59 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel3_framework/http.dart';
import 'package:angel_proxy/angel_proxy.dart'; import 'package:angel3_proxy/angel3_proxy.dart';
import 'package:angel_test/angel_test.dart'; import 'package:angel3_test/angel3_test.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:mock_request/mock_request.dart'; import 'package:angel3_mock_request/angel3_mock_request.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
main() { void main() {
Angel app, testApp; Angel? app, testApp;
TestClient client; late TestClient client;
Proxy layer; late Proxy layer;
setUp(() async { setUp(() async {
testApp = Angel(); testApp = Angel();
testApp.get('/foo', (req, res) async { testApp!.get('/foo', (req, res) async {
res.useBuffer(); res.useBuffer();
res.write('pub serve'); res.write('pub serve');
}); });
testApp.get('/empty', (req, res) => res.close()); testApp!.get('/empty', (req, res) => res.close());
testApp.responseFinalizers.add((req, res) async { testApp!.responseFinalizers.add((req, res) async {
print('OUTGOING: ' + String.fromCharCodes(res.buffer.toBytes())); print('OUTGOING: ' + String.fromCharCodes(res.buffer!.toBytes()));
}); });
testApp.encoders.addAll({'gzip': gzip.encoder}); testApp!.encoders.addAll({'gzip': gzip.encoder});
var server = await AngelHttp(testApp).startServer(); var server = await AngelHttp(testApp!).startServer();
app = Angel(); app = Angel();
app.fallback((req, res) { app!.fallback((req, res) {
res.useBuffer(); res.useBuffer();
return true; return true;
}); });
app.get('/bar', (req, res) => res.write('normal')); app!.get('/bar', (req, res) => res.write('normal'));
layer = Proxy( layer = Proxy(
Uri(scheme: 'http', host: server.address.address, port: server.port), Uri(scheme: 'http', host: server.address.address, port: server.port),
publicPath: '/proxy', publicPath: '/proxy',
); );
app.fallback(layer.handleRequest); app!.fallback(layer.handleRequest);
app.responseFinalizers.add((req, res) async { app!.responseFinalizers.add((req, res) async {
print('Normal. Buf: ' + print('Normal. Buf: ' +
String.fromCharCodes(res.buffer.toBytes()) + String.fromCharCodes(res.buffer!.toBytes()) +
', headers: ${res.headers}'); ', headers: ${res.headers}');
}); });
app.encoders.addAll({'gzip': gzip.encoder}); app!.encoders.addAll({'gzip': gzip.encoder});
client = await connectTo(app); client = await connectTo(app!);
app.logger = testApp.logger = Logger('proxy') app!.logger = testApp!.logger = Logger('proxy')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
print(rec); print(rec);
if (rec.error != null) print(rec.error); if (rec.error != null) print(rec.error);
@ -63,8 +63,8 @@ main() {
tearDown(() async { tearDown(() async {
await client.close(); await client.close();
await app.close(); await app!.close();
await testApp.close(); await testApp!.close();
app = null; app = null;
testApp = null; testApp = null;
}); });
@ -72,9 +72,9 @@ main() {
test('proxied', () async { test('proxied', () async {
var rq = MockHttpRequest('GET', Uri.parse('/proxy/foo')); var rq = MockHttpRequest('GET', Uri.parse('/proxy/foo'));
await rq.close(); await rq.close();
var rqc = await HttpRequestContext.from(rq, app, '/proxy/foo'); var rqc = await HttpRequestContext.from(rq, app!, '/proxy/foo');
var rsc = HttpResponseContext(rq.response, app); var rsc = HttpResponseContext(rq.response, app);
await app.executeHandler(layer.handleRequest, rqc, rsc); await app!.executeHandler(layer.handleRequest, rqc, rsc);
var response = await rq.response var response = await rq.response
//.transform(gzip.decoder) //.transform(gzip.decoder)
.transform(utf8.decoder) .transform(utf8.decoder)
@ -83,12 +83,12 @@ main() {
}); });
test('empty', () async { test('empty', () async {
var response = await client.get('/proxy/empty'); var response = await client.get(Uri.parse('/proxy/empty'));
expect(response.body, isEmpty); expect(response.body, isEmpty);
}); });
test('normal', () async { test('normal', () async {
var response = await client.get('/bar'); var response = await client.get(Uri.parse('/bar'));
expect(response, hasBody('normal')); expect(response, hasBody('normal'));
}); });
} }