2.0.0
This commit is contained in:
parent
9ff915a105
commit
8291b3b280
7 changed files with 71 additions and 36 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
# 2.0.0
|
||||||
|
* Updates for Angel 2. Big thanks to @denkuy!
|
||||||
|
|
||||||
# 1.1.1
|
# 1.1.1
|
||||||
Removed reference to `io`; now works with HTTP/2.
|
* Removed reference to `io`; now works with HTTP/2. Thanks to @daniel-v!
|
||||||
Thanks to @daniel-v!
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode: true
|
strong-mode:
|
||||||
|
implicit-casts: false
|
|
@ -2,14 +2,14 @@ import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_framework/http.dart';
|
import 'package:angel_framework/http.dart';
|
||||||
import 'package:angel_proxy/angel_proxy.dart';
|
import 'package:angel_proxy/angel_proxy.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/io_client.dart' as http;
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
final Duration timeout = new Duration(seconds: 5);
|
final Duration timeout = new Duration(seconds: 5);
|
||||||
|
|
||||||
main() async {
|
main() async {
|
||||||
var app = new Angel();
|
var app = new Angel();
|
||||||
var client = new http.Client();
|
var client = new http.IOClient();
|
||||||
|
|
||||||
// Forward any /api requests to pub.
|
// Forward any /api requests to pub.
|
||||||
// By default, if the host throws a 404, the request will fall through to the next handler.
|
// By default, if the host throws a 404, the request will fall through to the next handler.
|
||||||
|
@ -37,7 +37,8 @@ main() async {
|
||||||
app.all('*', dartlangProxy.handleRequest);
|
app.all('*', dartlangProxy.handleRequest);
|
||||||
|
|
||||||
// In case we can't connect to dartlang.org, show an error.
|
// In case we can't connect to dartlang.org, show an error.
|
||||||
app.fallback((req, res) => res.write('Couldn\'t connect to Pub or dartlang.'));
|
app.fallback(
|
||||||
|
(req, res) => res.write('Couldn\'t connect to Pub or dartlang.'));
|
||||||
|
|
||||||
app.logger = new Logger('angel')
|
app.logger = new Logger('angel')
|
||||||
..onRecord.listen(
|
..onRecord.listen(
|
||||||
|
@ -48,7 +49,9 @@ main() async {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
var server = await AngelHttp(app).startServer(InternetAddress.loopbackIPv4, 8080);
|
var server =
|
||||||
|
await AngelHttp(app).startServer(InternetAddress.loopbackIPv4, 8080);
|
||||||
print('Listening at http://${server.address.address}:${server.port}');
|
print('Listening at http://${server.address.address}:${server.port}');
|
||||||
print('Check this out! http://${server.address.address}:${server.port}/pub/packages/angel_framework');
|
print(
|
||||||
|
'Check this out! http://${server.address.address}:${server.port}/pub/packages/angel_framework');
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
|
||||||
class Proxy {
|
class Proxy {
|
||||||
String _prefix;
|
String _prefix;
|
||||||
|
|
||||||
final http.Client httpClient;
|
final http.BaseClient httpClient;
|
||||||
|
|
||||||
/// If `true` (default), then the plug-in will ignore failures to connect to the proxy, and allow other handlers to run.
|
/// If `true` (default), then the plug-in will ignore failures to connect to the proxy, and allow other handlers to run.
|
||||||
final bool recoverFromDead;
|
final bool recoverFromDead;
|
||||||
|
@ -34,8 +34,10 @@ class Proxy {
|
||||||
this.recoverFrom404: true,
|
this.recoverFrom404: true,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
}) {
|
}) {
|
||||||
if (this.recoverFromDead == null) throw ArgumentError.notNull("recoverFromDead");
|
if (this.recoverFromDead == null)
|
||||||
if (this.recoverFrom404 == null) throw ArgumentError.notNull("recoverFrom404");
|
throw ArgumentError.notNull("recoverFromDead");
|
||||||
|
if (this.recoverFrom404 == null)
|
||||||
|
throw ArgumentError.notNull("recoverFrom404");
|
||||||
|
|
||||||
_prefix = publicPath?.replaceAll(_straySlashes, '') ?? '';
|
_prefix = publicPath?.replaceAll(_straySlashes, '') ?? '';
|
||||||
}
|
}
|
||||||
|
@ -56,7 +58,8 @@ class Proxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Proxies a request to the given path on the remote server.
|
/// Proxies a request to the given path on the remote server.
|
||||||
Future<bool> servePath(String path, RequestContext req, ResponseContext res) async {
|
Future<bool> servePath(
|
||||||
|
String path, RequestContext req, ResponseContext res) async {
|
||||||
http.StreamedResponse rs;
|
http.StreamedResponse rs;
|
||||||
|
|
||||||
final mapping = '$mapTo/$path'.replaceAll(_straySlashes, '');
|
final mapping = '$mapTo/$path'.replaceAll(_straySlashes, '');
|
||||||
|
@ -74,7 +77,8 @@ class Proxy {
|
||||||
'host': port == null ? host : '$host:$port',
|
'host': port == null ? host : '$host:$port',
|
||||||
'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': req.headers.host ?? req.headers.value('host') ?? 'none',
|
'x-forwarded-host':
|
||||||
|
req.headers.host ?? req.headers.value('host') ?? 'none',
|
||||||
'x-forwarded-proto': protocol,
|
'x-forwarded-proto': protocol,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,9 +86,10 @@ class Proxy {
|
||||||
headers[name] = values.join(',');
|
headers[name] = values.join(',');
|
||||||
});
|
});
|
||||||
|
|
||||||
headers[HttpHeaders.cookieHeader] = req.cookies.map<String>((c) => '${c.name}=${c.value}').join('; ');
|
headers[HttpHeaders.cookieHeader] =
|
||||||
|
req.cookies.map<String>((c) => '${c.name}=${c.value}').join('; ');
|
||||||
|
|
||||||
var body;
|
List<int> body;
|
||||||
|
|
||||||
if (req.method != 'GET' && req.app.keepRawRequestBuffers == true) {
|
if (req.method != 'GET' && req.app.keepRawRequestBuffers == true) {
|
||||||
body = (await req.parse()).originalBuffer;
|
body = (await req.parse()).originalBuffer;
|
||||||
|
@ -110,7 +115,8 @@ class Proxy {
|
||||||
e,
|
e,
|
||||||
stackTrace: st,
|
stackTrace: st,
|
||||||
statusCode: 504,
|
statusCode: 504,
|
||||||
message: 'Connection to remote host "$host" timed out after ${timeout.inMilliseconds}ms.',
|
message:
|
||||||
|
'Connection to remote host "$host" timed out after ${timeout.inMilliseconds}ms.',
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (recoverFromDead) return true;
|
if (recoverFromDead) return true;
|
||||||
|
@ -146,9 +152,12 @@ class Proxy {
|
||||||
rs.headers[HttpHeaders.transferEncodingHeader]?.isNotEmpty == true;
|
rs.headers[HttpHeaders.transferEncodingHeader]?.isNotEmpty == true;
|
||||||
|
|
||||||
var proxiedHeaders = new Map<String, String>.from(rs.headers)
|
var proxiedHeaders = new Map<String, String>.from(rs.headers)
|
||||||
..remove(HttpHeaders.contentEncodingHeader) // drop, http.Client has decoded
|
..remove(
|
||||||
..remove(HttpHeaders.transferEncodingHeader) // drop, http.Client has decoded
|
HttpHeaders.contentEncodingHeader) // drop, http.Client has decoded
|
||||||
..[HttpHeaders.contentLengthHeader] = "${isContentLengthUnknown ? '-1' : rs.contentLength}";
|
..remove(
|
||||||
|
HttpHeaders.transferEncodingHeader) // drop, http.Client has decoded
|
||||||
|
..[HttpHeaders.contentLengthHeader] =
|
||||||
|
"${isContentLengthUnknown ? '-1' : rs.contentLength}";
|
||||||
|
|
||||||
res
|
res
|
||||||
..contentType = mediaType
|
..contentType = mediaType
|
||||||
|
|
10
pubspec.yaml
10
pubspec.yaml
|
@ -1,15 +1,15 @@
|
||||||
name: angel_proxy
|
name: angel_proxy
|
||||||
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: 1.1.1
|
version: 2.0.0
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/proxy
|
homepage: https://github.com/angel-dart/proxy
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.0.0 <3.0.0"
|
sdk: ">=2.0.0 <3.0.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: ^2.0.0-alpha # The core server library.
|
angel_framework: ^2.0.0-alpha
|
||||||
http: ^0.11.3
|
http: ^0.12.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: 2.0.0-alpha
|
angel_test: ^2.0.0-alpha
|
||||||
|
logging:
|
||||||
test: ^1.0.0
|
test: ^1.0.0
|
||||||
|
|
||||||
|
|
|
@ -3,21 +3,21 @@ import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_framework/http.dart';
|
import 'package:angel_framework/http.dart';
|
||||||
import 'package:angel_proxy/angel_proxy.dart';
|
import 'package:angel_proxy/angel_proxy.dart';
|
||||||
import 'package:http/http.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';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
Angel app;
|
Angel app;
|
||||||
http.Client client = new http.Client();
|
var client = new http.IOClient();
|
||||||
HttpServer server, testServer;
|
HttpServer server, testServer;
|
||||||
String url;
|
String url;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
app = new Angel()..keepRawRequestBuffers = true;
|
app = new Angel()..keepRawRequestBuffers = true;
|
||||||
var appHttp = AngelHttp(app);
|
var appHttp = AngelHttp(app);
|
||||||
var httpClient = new http.Client();
|
var httpClient = new http.IOClient();
|
||||||
|
|
||||||
testServer = await startTestServer();
|
testServer = await startTestServer();
|
||||||
|
|
||||||
|
@ -86,8 +86,9 @@ main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('original buffer', () async {
|
test('original buffer', () async {
|
||||||
var response = await client
|
var response = await client.post('$url/proxy/body',
|
||||||
.post('$url/proxy/body', body: json.encode({'foo': 'bar'}), headers: {'content-type': 'application/json'});
|
body: json.encode({'foo': 'bar'}),
|
||||||
|
headers: {'content-type': 'application/json'});
|
||||||
print('Response: ${response.body}');
|
print('Response: ${response.body}');
|
||||||
expect(response.body, isNotEmpty);
|
expect(response.body, isNotEmpty);
|
||||||
expect(response.body, isNot('intercept empty'));
|
expect(response.body, isNot('intercept empty'));
|
||||||
|
|
|
@ -4,7 +4,8 @@ import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_framework/http.dart';
|
import 'package:angel_framework/http.dart';
|
||||||
import 'package:angel_proxy/angel_proxy.dart';
|
import 'package:angel_proxy/angel_proxy.dart';
|
||||||
import 'package:angel_test/angel_test.dart';
|
import 'package:angel_test/angel_test.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/io_client.dart' as http;
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:mock_request/mock_request.dart';
|
import 'package:mock_request/mock_request.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ main() {
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
testApp = new Angel();
|
testApp = new Angel();
|
||||||
testApp.get('/foo', (req, res) async {
|
testApp.get('/foo', (req, res) async {
|
||||||
|
res.useBuffer();
|
||||||
res.write('pub serve');
|
res.write('pub serve');
|
||||||
});
|
});
|
||||||
testApp.get('/empty', (req, res) => res.close());
|
testApp.get('/empty', (req, res) => res.close());
|
||||||
|
@ -29,9 +31,13 @@ main() {
|
||||||
var server = await AngelHttp(testApp).startServer();
|
var server = await AngelHttp(testApp).startServer();
|
||||||
|
|
||||||
app = new Angel();
|
app = new Angel();
|
||||||
|
app.fallback((req, res) {
|
||||||
|
res.useBuffer();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
app.get('/bar', (req, res) => res.write('normal'));
|
app.get('/bar', (req, res) => res.write('normal'));
|
||||||
|
|
||||||
var httpClient = new http.Client();
|
var httpClient = new http.IOClient();
|
||||||
|
|
||||||
layer = new Proxy(
|
layer = new Proxy(
|
||||||
httpClient,
|
httpClient,
|
||||||
|
@ -39,15 +45,25 @@ main() {
|
||||||
port: server.port,
|
port: server.port,
|
||||||
publicPath: '/proxy',
|
publicPath: '/proxy',
|
||||||
);
|
);
|
||||||
app.all("*", layer.handleRequest);
|
|
||||||
|
|
||||||
app.responseFinalizers.add((req, ResponseContext res) async {
|
app.fallback(layer.handleRequest);
|
||||||
print('Normal. Buf: ' + new String.fromCharCodes(res.buffer.toBytes()) + ', headers: ${res.headers}');
|
|
||||||
|
app.responseFinalizers.add((req, res) async {
|
||||||
|
print('Normal. Buf: ' +
|
||||||
|
new String.fromCharCodes(res.buffer.toBytes()) +
|
||||||
|
', 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 = new Logger('proxy')
|
||||||
|
..onRecord.listen((rec) {
|
||||||
|
print(rec);
|
||||||
|
if (rec.error != null) print(rec.error);
|
||||||
|
if (rec.stackTrace != null) print(rec.stackTrace);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
|
@ -62,8 +78,11 @@ main() {
|
||||||
var rq = new MockHttpRequest('GET', Uri.parse('/proxy/foo'))..close();
|
var rq = new MockHttpRequest('GET', Uri.parse('/proxy/foo'))..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, rqc, rsc);
|
await app.executeHandler(layer.handleRequest, rqc, rsc);
|
||||||
var response = await rq.response.transform(gzip.decoder).transform(utf8.decoder).join();
|
var response = await rq.response
|
||||||
|
//.transform(gzip.decoder)
|
||||||
|
.transform(utf8.decoder)
|
||||||
|
.join();
|
||||||
expect(response, 'pub serve');
|
expect(response, 'pub serve');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue