enable null safety (#23)
Also remove lint redundant with latest pedantic – and add a few favorites
Co-authored-by: Nate Bosch <nbosch@google.com>
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index c3808a4..ce7b153 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -20,21 +20,20 @@
strategy:
fail-fast: false
matrix:
- sdk: [dev]
+ sdk: [2.12.0, dev]
steps:
- uses: actions/checkout@v2
- - uses: dart-lang/setup-dart@v0.3
+ - uses: dart-lang/setup-dart@v1.0
with:
sdk: ${{ matrix.sdk }}
- id: install
- name: Install dependencies
run: dart pub get
- - name: Check formatting
- run: dart format --output=none --set-exit-if-changed .
- if: always() && steps.install.outcome == 'success'
- - name: Analyze code
- run: dart analyze --fatal-infos
- if: always() && steps.install.outcome == 'success'
+ - run: dart format --output=none --set-exit-if-changed .
+ if: matrix.sdk == 'dev' && steps.install.outcome == 'success'
+ - run: dart analyze --fatal-infos
+ if: matrix.sdk == 'dev' && steps.install.outcome == 'success'
+ - run: dart analyze
+ if: matrix.sdk != 'dev' && steps.install.output == 'success'
# Run tests on a matrix consisting of two dimensions:
# 1. OS: ubuntu-latest, (macos-latest, windows-latest)
@@ -47,39 +46,13 @@
matrix:
# Add macos-latest and/or windows-latest if relevant for this package.
os: [ubuntu-latest]
- sdk: [dev]
+ sdk: [2.12.0, dev]
steps:
- uses: actions/checkout@v2
- - uses: dart-lang/setup-dart@v0.3
+ - uses: dart-lang/setup-dart@v1.0
with:
sdk: ${{ matrix.sdk }}
- id: install
- name: Install dependencies
run: dart pub get
- - name: Run VM tests
- run: dart test --platform vm
- if: always() && steps.install.outcome == 'success'
-
- # Run tests on a matrix consisting of two dimensions:
- # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
- # 2. release channel: 2.0.0
- test-legacy-sdk:
- needs: analyze
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- # Add macos-latest and/or windows-latest if relevant for this package.
- os: [ubuntu-latest]
- sdk: [2.0.0]
- steps:
- - uses: actions/checkout@v2
- - uses: dart-lang/setup-dart@v0.3
- with:
- sdk: ${{ matrix.sdk }}
- - id: install
- name: Install dependencies
- run: pub get
- - name: Run VM tests
- run: pub run test --platform vm
+ - run: dart test
if: always() && steps.install.outcome == 'success'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 43863e3..8618814 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.0.0
+
+- Require Dart `2.12`.
+- Enable null safety.
+- Removed deprecated `createProxyHandler`.
+
## 0.1.0+7
* Added example.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 57afaff..c9b76ab 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,79 +1,75 @@
include: package:pedantic/analysis_options.yaml
+
analyzer:
strong-mode:
implicit-casts: false
+
linter:
rules:
- - always_declare_return_types
- - annotate_overrides
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_catching_errors
+ - avoid_classes_with_only_static_members
+ - avoid_dynamic_calls
- avoid_empty_else
- avoid_function_literals_in_foreach_calls
- - avoid_init_to_null
- - avoid_null_checks_in_equality_operators
- - avoid_relative_lib_imports
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
- avoid_renaming_method_parameters
- - avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_future
- - avoid_shadowing_type_parameters
- - avoid_types_as_parameter_names
+ - avoid_returning_null_for_void
+ - avoid_returning_this
- avoid_unused_constructor_parameters
- - await_only_futures
+ - avoid_void_async
- camel_case_types
- cancel_subscriptions
+ - cascade_invocations
- comment_references
- constant_identifier_names
- control_flow_in_finally
- directives_ordering
- - empty_catches
- - empty_constructor_bodies
- empty_statements
+ - file_names
- hash_and_equals
- implementation_imports
- invariant_booleans
- iterable_contains_unrelated_type
- - library_names
- - library_prefixes
+ - join_return_with_assignment
+ - lines_longer_than_80_chars
- list_remove_unrelated_type
- literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list
- - no_duplicate_case_values
+ - no_runtimeType_toString
- non_constant_identifier_names
- - null_closures
- - omit_local_variable_types
- only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- - prefer_adjacent_string_concatenation
- - prefer_collection_literals
- - prefer_conditional_assignment
+ - prefer_asserts_in_initializer_lists
- prefer_const_constructors
- - prefer_contains
- - prefer_equal_for_default_values
- - prefer_final_fields
- - prefer_generic_function_type_aliases
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - prefer_function_declarations_over_variables
- prefer_initializing_formals
- - prefer_is_empty
- - prefer_is_not_empty
+ - prefer_interpolation_to_compose_strings
+ - prefer_is_not_operator
+ - prefer_null_aware_operators
+ - prefer_relative_imports
- prefer_typing_uninitialized_variables
- - recursive_getters
- - slash_for_doc_comments
+ - prefer_void_to_null
+ - provide_deprecation_message
+ - sort_pub_dependencies
- test_types_in_equals
- throw_in_finally
- - type_init_formals
- unnecessary_await_in_return
- - unnecessary_brace_in_string_interps
- - unnecessary_const
- - unnecessary_getters_setters
- unnecessary_lambdas
- - unnecessary_new
- unnecessary_null_aware_assignments
+ - unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
- - unnecessary_this
- - unrelated_type_equality_checks
- - use_function_type_syntax_for_parameters
- - use_rethrow_when_possible
- - valid_regexps
+ - unnecessary_string_interpolations
+ - use_string_buffers
+ - void_checks
diff --git a/example/example.dart b/example/example.dart
index 02da1a3..2b1af31 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -5,8 +5,8 @@
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_proxy/shelf_proxy.dart';
-void main() async {
- var server = await shelf_io.serve(
+Future<void> main() async {
+ final server = await shelf_io.serve(
proxyHandler('https://dart.dev'),
'localhost',
8080,
diff --git a/lib/shelf_proxy.dart b/lib/shelf_proxy.dart
index a59623d..0f2d3c7 100644
--- a/lib/shelf_proxy.dart
+++ b/lib/shelf_proxy.dart
@@ -21,7 +21,7 @@
///
/// [proxyName] is used in headers to identify this proxy. It should be a valid
/// HTTP token or a hostname. It defaults to `shelf_proxy`.
-Handler proxyHandler(url, {http.Client client, String proxyName}) {
+Handler proxyHandler(url, {http.Client? client, String? proxyName}) {
Uri uri;
if (url is String) {
uri = Uri.parse(url);
@@ -30,7 +30,7 @@
} else {
throw ArgumentError.value(url, 'url', 'url must be a String or Uri.');
}
- client ??= http.Client();
+ final nonNullClient = client ?? http.Client();
proxyName ??= 'shelf_proxy';
return (serverRequest) async {
@@ -38,11 +38,11 @@
// TODO(nweiz): Handle TRACE requests correctly. See
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.8
- var requestUrl = uri.resolve(serverRequest.url.toString());
- var clientRequest = http.StreamedRequest(serverRequest.method, requestUrl);
- clientRequest.followRedirects = false;
- clientRequest.headers.addAll(serverRequest.headers);
- clientRequest.headers['Host'] = uri.authority;
+ final requestUrl = uri.resolve(serverRequest.url.toString());
+ final clientRequest = http.StreamedRequest(serverRequest.method, requestUrl)
+ ..followRedirects = false
+ ..headers.addAll(serverRequest.headers)
+ ..headers['Host'] = uri.authority;
// Add a Via header. See
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45
@@ -54,7 +54,7 @@
.forEach(clientRequest.sink.add)
.catchError(clientRequest.sink.addError)
.whenComplete(clientRequest.sink.close));
- var clientResponse = await client.send(clientRequest);
+ final clientResponse = await nonNullClient.send(clientRequest);
// Add a Via header. See
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45
_addHeader(clientResponse.headers, 'via', '1.1 $proxyName');
@@ -79,11 +79,11 @@
// than the destination server, if possible.
if (clientResponse.isRedirect &&
clientResponse.headers.containsKey('location')) {
- var location =
- requestUrl.resolve(clientResponse.headers['location']).toString();
+ final location =
+ requestUrl.resolve(clientResponse.headers['location']!).toString();
if (p.url.isWithin(uri.toString(), location)) {
clientResponse.headers['location'] =
- '/' + p.url.relative(location, from: uri.toString());
+ '/${p.url.relative(location, from: uri.toString())}';
} else {
clientResponse.headers['location'] = location;
}
@@ -94,17 +94,10 @@
};
}
-/// Use [proxyHandler] instead.
-@deprecated
-Handler createProxyHandler(Uri rootUri) => proxyHandler(rootUri);
-
// TODO(nweiz): use built-in methods for this when http and shelf support them.
/// Add a header with [name] and [value] to [headers], handling existing headers
/// gracefully.
void _addHeader(Map<String, String> headers, String name, String value) {
- if (headers.containsKey(name)) {
- headers[name] += ', $value';
- } else {
- headers[name] = value;
- }
+ final existing = headers[name];
+ headers[name] = existing == null ? value : '$existing, $value';
}
diff --git a/pubspec.yaml b/pubspec.yaml
index b6be43b..dc9cb6b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,16 +1,16 @@
name: shelf_proxy
-version: 0.1.0+8-dev
+version: 1.0.0
description: A shelf handler for proxying HTTP requests to another server.
-homepage: https://github.com/dart-lang/shelf_proxy
+repository: https://github.com/dart-lang/shelf_proxy
environment:
- sdk: '>=2.0.0 <3.0.0'
+ sdk: '>=2.12.0 <3.0.0'
dependencies:
- http: '>=0.9.0 <0.13.0'
- path: '>=1.0.0 <2.0.0'
+ http: ^0.13.0
+ path: ^1.8.0
pedantic: ^1.0.0
- shelf: '>=0.5.2 <0.8.0'
+ shelf: ^1.0.0
dev_dependencies:
- test: ^1.3.0
+ test: ^1.6.0
diff --git a/test/shelf_proxy_test.dart b/test/shelf_proxy_test.dart
index 588efda..b1ec3fd 100644
--- a/test/shelf_proxy_test.dart
+++ b/test/shelf_proxy_test.dart
@@ -12,10 +12,10 @@
import 'package:test/test.dart';
/// The URI of the server the current proxy server is proxying to.
-Uri targetUri;
+late Uri targetUri;
/// The URI of the current proxy server.
-Uri proxyUri;
+late Uri proxyUri;
void main() {
group('forwarding', () {
@@ -48,30 +48,24 @@
});
test('forwards response status', () async {
- await createProxy((request) {
- return shelf.Response(567);
- });
+ await createProxy((request) => shelf.Response(567));
- var response = await get();
+ final response = await get();
expect(response.statusCode, equals(567));
});
test('forwards response headers', () async {
- await createProxy((request) {
- return shelf.Response.ok(':)',
- headers: {'foo': 'bar', 'accept': '*/*'});
- });
+ await createProxy((request) =>
+ shelf.Response.ok(':)', headers: {'foo': 'bar', 'accept': '*/*'}));
- var response = await get();
+ final response = await get();
expect(response.headers, containsPair('foo', 'bar'));
expect(response.headers, containsPair('accept', '*/*'));
});
test('forwards response body', () async {
- await createProxy((request) {
- return shelf.Response.ok('hello, client');
- });
+ await createProxy((request) => shelf.Response.ok('hello, client'));
expect(await http.read(proxyUri), equals('hello, client'));
});
@@ -109,16 +103,15 @@
test('adds a Via header to the response', () async {
await createProxy((request) => shelf.Response.ok(':)'));
- var response = await get();
+ final response = await get();
expect(response.headers, containsPair('via', '1.1 shelf_proxy'));
});
test("adds to a response's existing Via header", () async {
- await createProxy((request) {
- return shelf.Response.ok(':)', headers: {'via': '1.0 something'});
- });
+ await createProxy((request) =>
+ shelf.Response.ok(':)', headers: {'via': '1.0 something'}));
- var response = await get();
+ final response = await get();
expect(response.headers,
containsPair('via', '1.0 something, 1.1 shelf_proxy'));
});
@@ -126,40 +119,36 @@
group('redirects', () {
test("doesn't modify a Location for a foreign server", () async {
- await createProxy((request) {
- return shelf.Response.found('http://dartlang.org');
- });
+ await createProxy(
+ (request) => shelf.Response.found('http://dartlang.org'));
- var response = await get();
+ final response = await get();
expect(response.headers, containsPair('location', 'http://dartlang.org'));
});
test('relativizes a reachable root-relative Location', () async {
- await createProxy((request) {
- return shelf.Response.found('/foo/bar');
- }, targetPath: '/foo');
+ await createProxy((request) => shelf.Response.found('/foo/bar'),
+ targetPath: '/foo');
- var response = await get();
+ final response = await get();
expect(response.headers, containsPair('location', '/bar'));
});
test('absolutizes an unreachable root-relative Location', () async {
- await createProxy((request) {
- return shelf.Response.found('/baz');
- }, targetPath: '/foo');
+ await createProxy((request) => shelf.Response.found('/baz'),
+ targetPath: '/foo');
- var response = await get();
+ final response = await get();
expect(response.headers,
containsPair('location', targetUri.resolve('/baz').toString()));
});
});
test('removes a transfer-encoding header', () async {
- var handler = mockHandler((request) {
- return http.Response('', 200, headers: {'transfer-encoding': 'chunked'});
- });
+ final handler = mockHandler((request) =>
+ http.Response('', 200, headers: {'transfer-encoding': 'chunked'}));
- var response =
+ final response =
await handler(shelf.Request('GET', Uri.parse('http://localhost/')));
expect(response.headers, isNot(contains('transfer-encoding')));
@@ -167,12 +156,10 @@
test('removes content-length and content-encoding for a gzipped response',
() async {
- var handler = mockHandler((request) {
- return http.Response('', 200,
- headers: {'content-encoding': 'gzip', 'content-length': '1234'});
- });
+ final handler = mockHandler((request) => http.Response('', 200,
+ headers: {'content-encoding': 'gzip', 'content-length': '1234'}));
- var response =
+ final response =
await handler(shelf.Request('GET', Uri.parse('http://localhost/')));
expect(response.headers, isNot(contains('content-encoding')));
@@ -186,15 +173,15 @@
///
/// [targetPath] is the root-relative path on the target server to proxy to. It
/// defaults to `/`.
-Future createProxy(shelf.Handler handler, {String targetPath}) async {
+Future createProxy(shelf.Handler handler, {String? targetPath}) async {
handler = expectAsync1(handler, reason: 'target server handler');
- var targetServer = await shelf_io.serve(handler, 'localhost', 0);
+ final targetServer = await shelf_io.serve(handler, 'localhost', 0);
targetUri = Uri.parse('http://localhost:${targetServer.port}');
if (targetPath != null) targetUri = targetUri.resolve(targetPath);
- var proxyServerHandler =
+ final proxyServerHandler =
expectAsync1(proxyHandler(targetUri), reason: 'proxy server handler');
- var proxyServer = await shelf_io.serve(proxyServerHandler, 'localhost', 0);
+ final proxyServer = await shelf_io.serve(proxyServerHandler, 'localhost', 0);
proxyUri = Uri.parse('http://localhost:${proxyServer.port}');
addTearDown(() {
@@ -207,14 +194,14 @@
/// [callback].
shelf.Handler mockHandler(
FutureOr<http.Response> Function(http.Request) callback) {
- var client = MockClient((request) async => await callback(request));
+ final client = MockClient((request) async => await callback(request));
return proxyHandler('http://dartlang.org', client: client);
}
/// Schedules a GET request with [headers] to the proxy server.
-Future<http.Response> get({Map<String, String> headers}) {
- var uri = proxyUri;
- var request = http.Request('GET', uri);
+Future<http.Response> get({Map<String, String>? headers}) {
+ final uri = proxyUri;
+ final request = http.Request('GET', uri);
if (headers != null) request.headers.addAll(headers);
request.followRedirects = false;
return request.send().then(http.Response.fromStream);