Published proxy and file_service
This commit is contained in:
parent
e25b67d41f
commit
70c4882727
21 changed files with 177 additions and 138 deletions
|
@ -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:
|
||||||
|
|
12
packages/file_service/AUTHORS.md
Normal file
12
packages/file_service/AUTHORS.md
Normal 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.
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode:
|
strong-mode:
|
||||||
implicit-casts: false
|
implicit-casts: false
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
|
@ -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
|
||||||
|
|
|
@ -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
12
packages/proxy/AUTHORS.md
Normal 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.
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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.
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
library angel_proxy;
|
library angel3_proxy;
|
||||||
|
|
||||||
export 'src/proxy_layer.dart';
|
export 'src/proxy_layer.dart';
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
|
@ -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}');
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue