This commit is contained in:
Tobe O 2018-11-08 17:13:26 -05:00
parent 9ff915a105
commit 8291b3b280
7 changed files with 71 additions and 36 deletions

View file

@ -1,3 +1,5 @@
# 2.0.0
* Updates for Angel 2. Big thanks to @denkuy!
# 1.1.1
Removed reference to `io`; now works with HTTP/2.
Thanks to @daniel-v!
* Removed reference to `io`; now works with HTTP/2. Thanks to @daniel-v!

View file

@ -1,2 +1,3 @@
analyzer:
strong-mode: true
strong-mode:
implicit-casts: false

View file

@ -2,14 +2,14 @@ import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.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';
final Duration timeout = new Duration(seconds: 5);
main() async {
var app = new Angel();
var client = new http.Client();
var client = new http.IOClient();
// Forward any /api requests to pub.
// 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);
// 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')
..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('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');
}

View file

@ -11,7 +11,7 @@ final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
class Proxy {
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.
final bool recoverFromDead;
@ -34,8 +34,10 @@ class Proxy {
this.recoverFrom404: true,
this.timeout,
}) {
if (this.recoverFromDead == null) throw ArgumentError.notNull("recoverFromDead");
if (this.recoverFrom404 == null) throw ArgumentError.notNull("recoverFrom404");
if (this.recoverFromDead == null)
throw ArgumentError.notNull("recoverFromDead");
if (this.recoverFrom404 == null)
throw ArgumentError.notNull("recoverFrom404");
_prefix = publicPath?.replaceAll(_straySlashes, '') ?? '';
}
@ -56,7 +58,8 @@ class Proxy {
}
/// 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;
final mapping = '$mapTo/$path'.replaceAll(_straySlashes, '');
@ -74,7 +77,8 @@ class Proxy {
'host': port == null ? host : '$host:$port',
'x-forwarded-for': req.remoteAddress.address,
'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,
};
@ -82,9 +86,10 @@ class Proxy {
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) {
body = (await req.parse()).originalBuffer;
@ -110,7 +115,8 @@ class Proxy {
e,
stackTrace: st,
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) {
if (recoverFromDead) return true;
@ -146,9 +152,12 @@ class Proxy {
rs.headers[HttpHeaders.transferEncodingHeader]?.isNotEmpty == true;
var proxiedHeaders = new Map<String, String>.from(rs.headers)
..remove(HttpHeaders.contentEncodingHeader) // drop, http.Client has decoded
..remove(HttpHeaders.transferEncodingHeader) // drop, http.Client has decoded
..[HttpHeaders.contentLengthHeader] = "${isContentLengthUnknown ? '-1' : rs.contentLength}";
..remove(
HttpHeaders.contentEncodingHeader) // drop, http.Client has decoded
..remove(
HttpHeaders.transferEncodingHeader) // drop, http.Client has decoded
..[HttpHeaders.contentLengthHeader] =
"${isContentLengthUnknown ? '-1' : rs.contentLength}";
res
..contentType = mediaType

View file

@ -1,15 +1,15 @@
name: angel_proxy
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>
homepage: https://github.com/angel-dart/proxy
environment:
sdk: ">=2.0.0 <3.0.0"
dependencies:
angel_framework: ^2.0.0-alpha # The core server library.
http: ^0.11.3
angel_framework: ^2.0.0-alpha
http: ^0.12.0
dev_dependencies:
angel_test: 2.0.0-alpha
angel_test: ^2.0.0-alpha
logging:
test: ^1.0.0

View file

@ -3,21 +3,21 @@ import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.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:test/test.dart';
import 'common.dart';
main() {
Angel app;
http.Client client = new http.Client();
var client = new http.IOClient();
HttpServer server, testServer;
String url;
setUp(() async {
app = new Angel()..keepRawRequestBuffers = true;
var appHttp = AngelHttp(app);
var httpClient = new http.Client();
var httpClient = new http.IOClient();
testServer = await startTestServer();
@ -86,8 +86,9 @@ main() {
});
test('original buffer', () async {
var response = await client
.post('$url/proxy/body', body: json.encode({'foo': 'bar'}), headers: {'content-type': 'application/json'});
var response = await client.post('$url/proxy/body',
body: json.encode({'foo': 'bar'}),
headers: {'content-type': 'application/json'});
print('Response: ${response.body}');
expect(response.body, isNotEmpty);
expect(response.body, isNot('intercept empty'));

View file

@ -4,7 +4,8 @@ import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:angel_proxy/angel_proxy.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:test/test.dart';
@ -16,6 +17,7 @@ main() {
setUp(() async {
testApp = new Angel();
testApp.get('/foo', (req, res) async {
res.useBuffer();
res.write('pub serve');
});
testApp.get('/empty', (req, res) => res.close());
@ -29,9 +31,13 @@ main() {
var server = await AngelHttp(testApp).startServer();
app = new Angel();
app.fallback((req, res) {
res.useBuffer();
return true;
});
app.get('/bar', (req, res) => res.write('normal'));
var httpClient = new http.Client();
var httpClient = new http.IOClient();
layer = new Proxy(
httpClient,
@ -39,15 +45,25 @@ main() {
port: server.port,
publicPath: '/proxy',
);
app.all("*", layer.handleRequest);
app.responseFinalizers.add((req, ResponseContext res) async {
print('Normal. Buf: ' + new String.fromCharCodes(res.buffer.toBytes()) + ', headers: ${res.headers}');
app.fallback(layer.handleRequest);
app.responseFinalizers.add((req, res) async {
print('Normal. Buf: ' +
new String.fromCharCodes(res.buffer.toBytes()) +
', headers: ${res.headers}');
});
app.encoders.addAll({'gzip': gzip.encoder});
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 {
@ -62,8 +78,11 @@ main() {
var rq = new MockHttpRequest('GET', Uri.parse('/proxy/foo'))..close();
var rqc = await HttpRequestContext.from(rq, app, '/proxy/foo');
var rsc = HttpResponseContext(rq.response, app);
await app.executeHandler(layer, rqc, rsc);
var response = await rq.response.transform(gzip.decoder).transform(utf8.decoder).join();
await app.executeHandler(layer.handleRequest, rqc, rsc);
var response = await rq.response
//.transform(gzip.decoder)
.transform(utf8.decoder)
.join();
expect(response, 'pub serve');
});