diff --git a/README.md b/README.md index fd31dbaf..5f869573 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![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`). +Angel middleware to forward requests to another server (i.e. `webdev serve`). ```dart import 'package:angel_proxy/angel_proxy.dart'; @@ -11,23 +11,26 @@ import 'package:http/http.dart' as http; main() async { // ... - var client = new http.Client(); - var proxy = new Proxy(app, client, 'http://localhost:3000'); + var client = http.Client(); // Forward requests instead of serving statically - app.use(proxy.handleRequest); + var proxy1 = Proxy(client, 'http://localhost:3000'); + // or split: Proxy(client, 'localhost', port: 8080, protocol: 'http'); + + // handle all methods (GET, POST, ...) + app.all('*', proxy.handleRequest); } ``` You can also restrict the proxy to serving only from a specific root: ```dart -new Proxy(app, client, '', publicPath: '/remote'); +Proxy(client, '', publicPath: '/remote'); ``` Also, you can map requests to a root path on the remote server ```dart -new Proxy(app, client, '', mapTo: '/path'); +Proxy(client, '', mapTo: '/path'); ``` -If your app's `storeOriginalBuffer` is `true`, then request bodies will be forwarded +If your app's `keepRawRequestBuffers` is `true`, then request bodies will be forwarded as well, if they are not empty. This allows things like POST requests to function. diff --git a/example/main.dart b/example/main.dart index 9deaefce..022c0769 100644 --- a/example/main.dart +++ b/example/main.dart @@ -14,7 +14,6 @@ main() async { // 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 Proxy( - app, client, 'https://pub.dartlang.org', publicPath: '/pub', @@ -30,7 +29,6 @@ main() async { // Anything else should fall through to dartlang.org. var dartlangProxy = new Proxy( - app, client, 'https://dartlang.org', timeout: timeout, diff --git a/lib/src/proxy_layer.dart b/lib/src/proxy_layer.dart index aa2922e7..30acd106 100644 --- a/lib/src/proxy_layer.dart +++ b/lib/src/proxy_layer.dart @@ -11,7 +11,6 @@ final MediaType _fallbackMediaType = MediaType('application', 'octet-stream'); class Proxy { String _prefix; - final Angel app; final http.Client httpClient; /// If `true` (default), then the plug-in will ignore failures to connect to the proxy, and allow other handlers to run. @@ -25,7 +24,6 @@ class Proxy { final Duration timeout; Proxy( - this.app, this.httpClient, this.host, { this.port, @@ -69,7 +67,7 @@ class Proxy { url = url.replaceAll(_straySlashes, ''); url = '$url/$mapping'; - if (!url.startsWith('http')) url = 'http://$url'; + if (!url.startsWith(protocol)) url = '$protocol://$url'; url = url.replaceAll(_straySlashes, ''); var headers = { @@ -88,7 +86,7 @@ class Proxy { var body; - if (req.method != 'GET' && app.keepRawRequestBuffers == true) { + if (req.method != 'GET' && req.app.keepRawRequestBuffers == true) { body = (await req.parse()).originalBuffer; } @@ -140,19 +138,24 @@ class Proxy { mediaType = _fallbackMediaType; } - var proxiedHeaders = new Map.from(rs.headers); + /// if [http.Client] does not provide us with a content length + /// OR [http.Client] is about to decode the response (bytecount returned by [http.Response].stream != known length) + /// then we can not provide a value downstream => set to '-1' for 'unspecified length' + var isContentLengthUnknown = rs.contentLength == null || + rs.headers[HttpHeaders.contentEncodingHeader]?.isNotEmpty == true || + rs.headers[HttpHeaders.transferEncodingHeader]?.isNotEmpty == true; + + var proxiedHeaders = new Map.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}"; res ..contentType = mediaType ..statusCode = rs.statusCode ..headers.addAll(proxiedHeaders); - var stream = rs.stream; - - // [upgrading to dart2] Keeping this workaround as a reference. It's not properly typed for dart2 - //if (rs.headers[HttpHeaders.contentEncodingHeader] == 'gzip') stream = stream.transform(gzip.encoder); - - await stream.pipe(res); + await rs.stream.pipe(res); return false; } diff --git a/test/basic_test.dart b/test/basic_test.dart index 943e1368..4cbf826c 100644 --- a/test/basic_test.dart +++ b/test/basic_test.dart @@ -22,14 +22,12 @@ main() { testServer = await startTestServer(); var proxy1 = new Proxy( - app, httpClient, testServer.address.address, port: testServer.port, publicPath: '/proxy', ); var proxy2 = new Proxy( - app, httpClient, testServer.address.address, port: testServer.port, diff --git a/test/pub_serve_test.dart b/test/pub_serve_test.dart index ee0b87c6..a23f5ad3 100644 --- a/test/pub_serve_test.dart +++ b/test/pub_serve_test.dart @@ -34,7 +34,6 @@ main() { var httpClient = new http.Client(); layer = new Proxy( - app, httpClient, server.address.address, port: server.port,