diff --git a/CHANGELOG.md b/CHANGELOG.md index 691074fb..9f6ffc30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # 2.1.0 + - Use `Uri` instead of archaic `host`, `port`, and `mapTo`. Also cleaner + safer + easier. +* Enable WebSocket proxying. + # 2.0.0 - Updates for Angel 2. Big thanks to @denkuy! diff --git a/README.md b/README.md index 5f869573..5d46bdbb 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![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. `webdev serve`). +Also supports WebSockets. ```dart import 'package:angel_proxy/angel_proxy.dart'; @@ -14,22 +15,21 @@ main() async { var client = http.Client(); // Forward requests instead of serving statically - var proxy1 = Proxy(client, 'http://localhost:3000'); - // or split: Proxy(client, 'localhost', port: 8080, protocol: 'http'); + var proxy1 = Proxy(client, Uri.parse('http://localhost:3000')); // handle all methods (GET, POST, ...) - app.all('*', proxy.handleRequest); + app.fallback(proxy.handleRequest); } ``` You can also restrict the proxy to serving only from a specific root: ```dart -Proxy(client, '', publicPath: '/remote'); +Proxy(client, baseUrl, publicPath: '/remote'); ``` -Also, you can map requests to a root path on the remote server +Also, you can map requests to a root path on the remote server: ```dart -Proxy(client, '', mapTo: '/path'); +Proxy(client, baseUrl.replace(path: '/path')); ``` If your app's `keepRawRequestBuffers` is `true`, then request bodies will be forwarded diff --git a/example/main.dart b/example/main.dart index e1382445..7aa38279 100644 --- a/example/main.dart +++ b/example/main.dart @@ -29,8 +29,6 @@ main() async { Uri.parse('http://echo.websocket.org'), publicPath: '/echo', timeout: timeout, - recoverFromDead: false, - recoverFrom404: false, ); app.get('/echo', echoProxy.handleRequest); diff --git a/lib/src/proxy_layer.dart b/lib/src/proxy_layer.dart index 2d955958..43bb6a54 100644 --- a/lib/src/proxy_layer.dart +++ b/lib/src/proxy_layer.dart @@ -32,10 +32,13 @@ class Proxy { this.recoverFrom404: true, this.timeout, }) { + if (!baseUrl.hasScheme || !baseUrl.hasAuthority) + throw new ArgumentError( + 'Invalid `baseUrl`. URI must have both a scheme and authority.'); if (this.recoverFromDead == null) - throw ArgumentError.notNull("recoverFromDead"); + throw new ArgumentError.notNull("recoverFromDead"); if (this.recoverFrom404 == null) - throw ArgumentError.notNull("recoverFrom404"); + throw new ArgumentError.notNull("recoverFrom404"); _prefix = publicPath?.replaceAll(_straySlashes, '') ?? ''; } @@ -64,35 +67,18 @@ class Proxy { 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); + local.pipe(remote); + remote.pipe(local); return false; } catch (e, st) { throw new AngelHttpException(e, @@ -126,7 +112,7 @@ class Proxy { var rq = new http.Request(req.method, uri); rq.headers.addAll(headers); rq.headers['host'] = rq.url.host; - rq.encoding = Utf8Codec(allowMalformed: true); + rq.encoding = new Utf8Codec(allowMalformed: true); if (body != null) rq.bodyBytes = body; @@ -157,7 +143,8 @@ class Proxy { MediaType mediaType; if (rs.headers.containsKey(HttpHeaders.contentTypeHeader)) { try { - mediaType = MediaType.parse(rs.headers[HttpHeaders.contentTypeHeader]); + mediaType = + new MediaType.parse(rs.headers[HttpHeaders.contentTypeHeader]); } on FormatException catch (e, st) { if (recoverFromDead) return true; diff --git a/test/basic_test.dart b/test/basic_test.dart index daeb4190..ca523d88 100644 --- a/test/basic_test.dart +++ b/test/basic_test.dart @@ -23,10 +23,16 @@ main() { var proxy1 = new Proxy( httpClient, - new Uri(host: testServer.address.address, port: testServer.port), + new Uri( + scheme: 'http', + host: testServer.address.address, + port: testServer.port), publicPath: '/proxy', ); + var proxy2 = new Proxy(httpClient, proxy1.baseUrl.replace(path: '/foo')); + print('Proxy 1 on: ${proxy1.baseUrl}'); + print('Proxy 2 on: ${proxy2.baseUrl}'); app.all("/proxy/*", proxy1.handleRequest); app.all("*", proxy2.handleRequest); diff --git a/test/pub_serve_test.dart b/test/pub_serve_test.dart index 238f5459..72f633cc 100644 --- a/test/pub_serve_test.dart +++ b/test/pub_serve_test.dart @@ -41,7 +41,7 @@ main() { layer = new Proxy( httpClient, - new Uri(host: server.address.address, port: server.port), + new Uri(scheme: 'http', host: server.address.address, port: server.port), publicPath: '/proxy', );