port to uri

This commit is contained in:
Tobe O 2018-11-08 19:14:32 -05:00
parent b5707a5db2
commit dbb483b953
6 changed files with 79 additions and 38 deletions

View file

@ -1,5 +1,11 @@
# 2.1.0
- Use `Uri` instead of archaic `host`, `port`, and `mapTo`. Also cleaner + safer + easier.
# 2.0.0
* Updates for Angel 2. Big thanks to @denkuy!
- Updates for Angel 2. Big thanks to @denkuy!
- Use `package:path` for better path resolution.
# 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

@ -15,12 +15,25 @@ main() async {
// By default, if the host throws a 404, the request will fall through to the next handler.
var pubProxy = new Proxy(
client,
'https://pub.dartlang.org',
Uri.parse('https://pub.dartlang.org'),
publicPath: '/pub',
timeout: timeout,
);
app.all("/pub/*", pubProxy.handleRequest);
// Surprise! We can also proxy WebSockets.
//
// Play around with this at http://www.websocket.org/echo.html.
var echoProxy = new Proxy(
client,
Uri.parse('http://echo.websocket.org'),
publicPath: '/echo',
timeout: timeout,
recoverFromDead: false,
recoverFrom404: false,
);
app.get('/echo', echoProxy.handleRequest);
// 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) {
@ -30,7 +43,7 @@ main() async {
// Anything else should fall through to dartlang.org.
var dartlangProxy = new Proxy(
client,
'https://dartlang.org',
Uri.parse('https://dartlang.org'),
timeout: timeout,
recoverFrom404: false,
);

View file

@ -2,8 +2,10 @@ import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:http_parser/http_parser.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as p;
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
@ -16,20 +18,16 @@ class Proxy {
/// 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 recoverFrom404;
final String host, mapTo, publicPath;
final int port;
final String protocol;
final Uri baseUrl;
final String publicPath;
/// If `null` then no timout is added for requests
final Duration timeout;
Proxy(
this.httpClient,
this.host, {
this.port,
this.mapTo: '/',
this.baseUrl, {
this.publicPath: '/',
this.protocol: 'http',
this.recoverFromDead: true,
this.recoverFrom404: true,
this.timeout,
@ -49,9 +47,11 @@ class Proxy {
var path = req.path.replaceAll(_straySlashes, '');
if (_prefix.isNotEmpty) {
if (!path.startsWith(_prefix)) return new Future<bool>.value(true);
if (!p.isWithin(_prefix, path) && !p.equals(_prefix, path)) {
return new Future<bool>.value(true);
}
path = path.replaceFirst(_prefix, '').replaceAll(_straySlashes, '');
path = p.relative(path, from: _prefix);
}
return servePath(path, req, res);
@ -62,24 +62,52 @@ class Proxy {
String path, RequestContext req, ResponseContext res) async {
http.StreamedResponse rs;
final mapping = '$mapTo/$path'.replaceAll(_straySlashes, '');
var uri = baseUrl.replace(path: p.join(baseUrl.path, path));
print('a $uri');
try {
print(req is HttpRequestContext &&
WebSocketTransformer.isUpgradeRequest(req.rawRequest));
if (req is HttpRequestContext &&
WebSocketTransformer.isUpgradeRequest(req.rawRequest)) {
print('ws!!!');
res.detach();
print('detached');
uri = uri.replace(scheme: uri.scheme == 'https' ? 'wss' : 'ws');
print(uri);
try {
var local = await WebSocketTransformer.upgrade(req.rawRequest);
print('local!');
var remote = await WebSocket.connect(uri.toString());
print('remote!');
dynamic Function(dynamic) log(String type) {
return (x) {
print('$type: $x');
return x;
};
}
local.map(log('local->remote')).pipe(remote);
remote.map(log('local->remote')).pipe(local);
return false;
} catch (e, st) {
throw new AngelHttpException(e,
message: 'Could not connect WebSocket', stackTrace: st);
}
}
Future<http.StreamedResponse> accessRemote() async {
var url = port == null ? host : '$host:$port';
url = url.replaceAll(_straySlashes, '');
url = '$url/$mapping';
if (!url.startsWith(protocol)) url = '$protocol://$url';
url = url.replaceAll(_straySlashes, '');
var headers = <String, String>{
'host': port == null ? host : '$host:$port',
'host': uri.authority,
'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-proto': protocol,
'x-forwarded-proto': uri.scheme,
};
req.headers.forEach((name, values) {
@ -95,7 +123,7 @@ class Proxy {
body = (await req.parse()).originalBuffer;
}
var rq = new http.Request(req.method, Uri.parse(url));
var rq = new http.Request(req.method, uri);
rq.headers.addAll(headers);
rq.headers['host'] = rq.url.host;
rq.encoding = Utf8Codec(allowMalformed: true);
@ -116,10 +144,10 @@ class Proxy {
stackTrace: st,
statusCode: 504,
message:
'Connection to remote host "$host" timed out after ${timeout.inMilliseconds}ms.',
'Connection to remote host "$uri" timed out after ${timeout.inMilliseconds}ms.',
);
} catch (e) {
if (recoverFromDead) return true;
if (recoverFromDead && e is! AngelHttpException) return true;
rethrow;
}
@ -137,7 +165,7 @@ class Proxy {
e,
stackTrace: st,
statusCode: 504,
message: 'Host "$host" returned a malformed content-type',
message: 'Host "$uri" returned a malformed content-type',
);
}
} else {

View file

@ -1,6 +1,6 @@
name: angel_proxy
description: Angel middleware to forward requests to another server (i.e. pub serve).
version: 2.0.0
version: 2.1.0
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/proxy
environment:
@ -9,6 +9,7 @@ dependencies:
angel_framework: ^2.0.0-alpha
http: ^0.12.0
http_parser: ^3.0.0
path: ^1.0.0
dev_dependencies:
angel_test: ^2.0.0-alpha
logging:

View file

@ -23,16 +23,10 @@ main() {
var proxy1 = new Proxy(
httpClient,
testServer.address.address,
port: testServer.port,
new Uri(host: testServer.address.address, port: testServer.port),
publicPath: '/proxy',
);
var proxy2 = new Proxy(
httpClient,
testServer.address.address,
port: testServer.port,
mapTo: '/foo',
);
var proxy2 = new Proxy(httpClient, proxy1.baseUrl.replace(path: '/foo'));
app.all("/proxy/*", proxy1.handleRequest);
app.all("*", proxy2.handleRequest);

View file

@ -41,8 +41,7 @@ main() {
layer = new Proxy(
httpClient,
server.address.address,
port: server.port,
new Uri(host: server.address.address, port: server.port),
publicPath: '/proxy',
);