1.0.8
This commit is contained in:
parent
5c8f3e28b1
commit
e05d35ee67
7 changed files with 121 additions and 46 deletions
|
@ -5,6 +5,7 @@
|
|||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/test/packages" />
|
||||
|
@ -13,7 +14,6 @@
|
|||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart SDK" level="application" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Multiple Proxies",
|
||||
"type": "dart-cli",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/example/multiple.dart"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
# angel_proxy
|
||||
|
||||
[![version 1.0.7](https://img.shields.io/badge/version-1.0.7-brightgreen.svg)](https://pub.dartlang.org/packages/angel_proxy)
|
||||
[![build status](https://travis-ci.org/angel-dart/proxy.svg)](https://travis-ci.org/angel-dart/proxy)
|
||||
[![Pub](https://img.shields.io/pub/v/angel_proxy.svg)](https://pub.dartlang.org/packages/angel_proxy)[![build status](https://travis-ci.org/angel-dart/proxy.svg)](https://travis-ci.org/angel-dart/proxy)
|
||||
|
||||
Angel middleware to forward requests to another server (i.e. pub serve).
|
||||
|
||||
|
|
38
example/multiple.dart
Normal file
38
example/multiple.dart
Normal file
|
@ -0,0 +1,38 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_diagnostics/angel_diagnostics.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_proxy/angel_proxy.dart';
|
||||
|
||||
final Duration TIMEOUT = new Duration(seconds: 5);
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
|
||||
// Forward any /api requests to pub.
|
||||
// By default, if the host throws a 404, the request will fall through to the next handler.
|
||||
var pubProxy = new ProxyLayer('pub.dartlang.org', 80,
|
||||
publicPath: '/pub', timeout: TIMEOUT);
|
||||
await app.configure(pubProxy);
|
||||
|
||||
// Pub's HTML assumes that the site's styles, etc. are on the absolute path `/static`.
|
||||
// This is not the case here. Let's patch that up:
|
||||
app.get('/static/*', (RequestContext req, res) {
|
||||
return pubProxy.serveFile(req.path, req, res);
|
||||
});
|
||||
|
||||
// Anything else should fall through to dartlang.org.
|
||||
await app.configure(new ProxyLayer('dartlang.org', 80, timeout: TIMEOUT));
|
||||
|
||||
// In case we can't connect to dartlang.org, show an error.
|
||||
app.after.add('Couldn\'t connect to Pub or dartlang.');
|
||||
|
||||
await app.configure(logRequests());
|
||||
|
||||
app.fatalErrorStream.listen((AngelFatalError e) {
|
||||
print(e.error);
|
||||
print(e.stack);
|
||||
});
|
||||
|
||||
var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 8080);
|
||||
print('Listening at http://${server.address.address}:${server.port}');
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
|
||||
|
@ -51,30 +52,31 @@ class ProxyLayer {
|
|||
final String host, mapTo, publicPath;
|
||||
final int port;
|
||||
final String protocol;
|
||||
final Duration timeout;
|
||||
|
||||
ProxyLayer(this.host, this.port,
|
||||
{this.debug: false,
|
||||
this.mapTo: '/',
|
||||
this.publicPath: '/',
|
||||
this.protocol: 'http',
|
||||
this.recoverFromDead: true,
|
||||
this.recoverFrom404: true,
|
||||
this.streamToIO: false,
|
||||
SecurityContext securityContext}) {
|
||||
ProxyLayer(
|
||||
this.host,
|
||||
this.port, {
|
||||
this.debug: false,
|
||||
this.mapTo: '/',
|
||||
this.publicPath: '/',
|
||||
this.protocol: 'http',
|
||||
this.recoverFromDead: true,
|
||||
this.recoverFrom404: true,
|
||||
this.streamToIO: false,
|
||||
this.timeout,
|
||||
SecurityContext securityContext,
|
||||
}) {
|
||||
_client = new HttpClient(context: securityContext);
|
||||
_prefix = publicPath.replaceAll(_straySlashes, '');
|
||||
}
|
||||
|
||||
call(Angel app) async => serve(this.app = app);
|
||||
|
||||
_printDebug(msg) {
|
||||
if (debug == true) print(msg);
|
||||
}
|
||||
|
||||
void close() => _client.close(force: true);
|
||||
|
||||
void serve(Router router) {
|
||||
_printDebug('Public path prefix: "$_prefix"');
|
||||
// _printDebug('Public path prefix: "$_prefix"');
|
||||
|
||||
handler(RequestContext req, ResponseContext res) async {
|
||||
var path = req.path.replaceAll(_straySlashes, '');
|
||||
|
@ -93,34 +95,55 @@ class ProxyLayer {
|
|||
}
|
||||
|
||||
// Create mapping
|
||||
_printDebug('Serving path $_path via proxy');
|
||||
// _printDebug('Serving path $_path via proxy');
|
||||
final mapping = '$mapTo/$_path'.replaceAll(_straySlashes, '');
|
||||
_printDebug('Mapped path $_path to path $mapping on proxy $host:$port');
|
||||
// _printDebug('Mapped path $_path to path $mapping on proxy $host:$port');
|
||||
|
||||
try {
|
||||
final rq = await _client.open(req.method, host, port, mapping);
|
||||
_printDebug('Opened client request');
|
||||
Future<HttpClientResponse> accessRemote() async {
|
||||
var ips = await InternetAddress.lookup(host);
|
||||
if (ips.isEmpty)
|
||||
throw new StateError('Could not resolve remote host "$host".');
|
||||
var address = ips.first.address;
|
||||
final rq = await _client.open(req.method, address, port, mapping);
|
||||
// _printDebug('Opened client request at "$address:$port/$mapping"');
|
||||
|
||||
copyHeaders(req.headers, rq.headers);
|
||||
_printDebug('Copied headers');
|
||||
rq.cookies.addAll(req.cookies ?? []);
|
||||
_printDebug('Added cookies');
|
||||
rq.headers
|
||||
.set('X-Forwarded-For', req.io.connectionInfo.remoteAddress.address);
|
||||
rq.headers
|
||||
..set('X-Forwarded-Port', req.io.connectionInfo.remotePort.toString())
|
||||
..set('X-Forwarded-Host',
|
||||
req.headers.host ?? req.headers.value(HttpHeaders.HOST) ?? 'none')
|
||||
..set('X-Forwarded-Proto', protocol);
|
||||
_printDebug('Added X-Forwarded headers');
|
||||
copyHeaders(req.headers, rq.headers);
|
||||
rq.headers.set(HttpHeaders.HOST, host);
|
||||
// _printDebug('Copied headers');
|
||||
rq.cookies.addAll(req.cookies ?? []);
|
||||
// _printDebug('Added cookies');
|
||||
rq.headers.set(
|
||||
'X-Forwarded-For', req.io.connectionInfo.remoteAddress.address);
|
||||
rq.headers
|
||||
..set('X-Forwarded-Port', req.io.connectionInfo.remotePort.toString())
|
||||
..set('X-Forwarded-Host',
|
||||
req.headers.host ?? req.headers.value(HttpHeaders.HOST) ?? 'none')
|
||||
..set('X-Forwarded-Proto', protocol);
|
||||
// _printDebug('Added X-Forwarded headers');
|
||||
|
||||
if (app.storeOriginalBuffer == true) {
|
||||
await req.parse();
|
||||
if (req.originalBuffer?.isNotEmpty == true) rq.add(req.originalBuffer);
|
||||
if (app.storeOriginalBuffer == true) {
|
||||
await req.parse();
|
||||
if (req.originalBuffer?.isNotEmpty == true)
|
||||
rq.add(req.originalBuffer);
|
||||
}
|
||||
|
||||
await rq.flush();
|
||||
return await rq.close();
|
||||
}
|
||||
|
||||
await rq.flush();
|
||||
rs = await rq.close();
|
||||
var future = accessRemote();
|
||||
if (timeout != null) future = future.timeout(timeout);
|
||||
rs = await future;
|
||||
} on TimeoutException catch (e, st) {
|
||||
if (recoverFromDead != false)
|
||||
return true;
|
||||
else
|
||||
throw new AngelHttpException(e,
|
||||
stackTrace: st,
|
||||
statusCode: HttpStatus.GATEWAY_TIMEOUT,
|
||||
message:
|
||||
'Connection to remote host "$host" timed out after ${timeout.inMilliseconds}ms.');
|
||||
} catch (e) {
|
||||
if (recoverFromDead != false)
|
||||
return true;
|
||||
|
@ -128,8 +151,8 @@ class ProxyLayer {
|
|||
rethrow;
|
||||
}
|
||||
|
||||
_printDebug(
|
||||
'Proxy responded to $mapping with status code ${rs.statusCode}');
|
||||
// _printDebug(
|
||||
// 'Proxy responded to $mapping with status code ${rs.statusCode}');
|
||||
|
||||
if (rs.statusCode == 404 && recoverFrom404 != false) return true;
|
||||
|
||||
|
@ -137,7 +160,7 @@ class ProxyLayer {
|
|||
..statusCode = rs.statusCode
|
||||
..contentType = rs.headers.contentType;
|
||||
|
||||
_printDebug('Proxy response headers:\n${rs.headers}');
|
||||
// _printDebug('Proxy response headers:\n${rs.headers}');
|
||||
|
||||
if (streamToIO == true) {
|
||||
res
|
||||
|
@ -150,7 +173,7 @@ class ProxyLayer {
|
|||
if (rs.headers.contentType != null)
|
||||
res.io.headers.contentType = rs.headers.contentType;
|
||||
|
||||
_printDebug('Outgoing content length: ${res.io.contentLength}');
|
||||
// _printDebug('Outgoing content length: ${res.io.contentLength}');
|
||||
|
||||
if (rs.headers[HttpHeaders.CONTENT_ENCODING]?.contains('gzip') == true) {
|
||||
res.io.headers.set(HttpHeaders.CONTENT_ENCODING, 'gzip');
|
||||
|
|
|
@ -11,7 +11,8 @@ class PubServeLayer extends ProxyLayer {
|
|||
String mapTo: '/',
|
||||
int port: 8080,
|
||||
String protocol: 'http',
|
||||
String publicPath: '/'})
|
||||
String publicPath: '/',
|
||||
Duration timeout})
|
||||
: super(host, port,
|
||||
debug: debug,
|
||||
mapTo: mapTo,
|
||||
|
@ -19,7 +20,8 @@ class PubServeLayer extends ProxyLayer {
|
|||
publicPath: publicPath,
|
||||
recoverFromDead: recoverFromDead != false,
|
||||
recoverFrom404: recoverFrom404 != false,
|
||||
streamToIO: streamToIO != false);
|
||||
streamToIO: streamToIO != false,
|
||||
timeout: timeout);
|
||||
|
||||
@override
|
||||
void serve(Router router) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: angel_proxy
|
||||
description: Angel middleware to forward requests to another server (i.e. pub serve).
|
||||
version: 1.0.7
|
||||
version: 1.0.8
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/proxy
|
||||
environment:
|
||||
|
@ -9,6 +9,8 @@ dependencies:
|
|||
angel_framework: ^1.0.0-dev
|
||||
dev_dependencies:
|
||||
angel_compress: ^1.0.0
|
||||
angel_diagnostics: ^1.0.0
|
||||
angel_test: ^1.0.0
|
||||
http: ^0.11.3
|
||||
test: ^0.12.15
|
||||
test: ^0.12.15
|
||||
|
Loading…
Reference in a new issue