latest shelf and add new lints (#29)
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index c3808a4..727e59e 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -62,7 +62,7 @@
# Run tests on a matrix consisting of two dimensions:
# 1. OS: ubuntu-latest, (macos-latest, windows-latest)
- # 2. release channel: 2.0.0
+ # 2. release channel: 2.1.0
test-legacy-sdk:
needs: analyze
runs-on: ${{ matrix.os }}
@@ -71,7 +71,7 @@
matrix:
# Add macos-latest and/or windows-latest if relevant for this package.
os: [ubuntu-latest]
- sdk: [2.0.0]
+ sdk: [2.1.0]
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v0.3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a33e02..0c7bf85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
-## 0.2.4-dev
+## 0.2.4
+* Support the latest shelf release (`1.x.x`).
+* Require at least Dart 2.1
* Allow omitting `protocols` argument even if the `onConnection` callback takes
a second argument.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 0711aca..d183bf1 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,43 +1,80 @@
include: package:pedantic/analysis_options.yaml
+
analyzer:
strong-mode:
implicit-casts: false
+
linter:
rules:
- - avoid_empty_else
- - avoid_init_to_null
- - avoid_null_checks_in_equality_operators
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_catching_errors
+ - avoid_classes_with_only_static_members
+ - avoid_function_literals_in_foreach_calls
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_renaming_method_parameters
+ - avoid_returning_null
+ - avoid_returning_null_for_future
+ - avoid_returning_null_for_void
+ - avoid_returning_this
+ - avoid_single_cascade_in_expression_statements
- avoid_unused_constructor_parameters
+ - avoid_void_async
- await_only_futures
- 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_runtimeType_toString
- non_constant_identifier_names
+ - only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- - prefer_equal_for_default_values
- - prefer_final_fields
- - prefer_generic_function_type_aliases
- - prefer_is_not_empty
- - slash_for_doc_comments
+ - prefer_asserts_in_initializer_lists
+ - prefer_const_constructors
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - prefer_function_declarations_over_variables
+ - prefer_initializing_formals
+ - prefer_inlined_adds
+ - prefer_interpolation_to_compose_strings
+ - prefer_is_not_operator
+ - prefer_null_aware_operators
+ - prefer_relative_imports
+ - prefer_typing_uninitialized_variables
+ - prefer_void_to_null
+ - provide_deprecation_message
+ - sort_pub_dependencies
- test_types_in_equals
- throw_in_finally
- - type_init_formals
+ - type_annotate_public_apis
+ - unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- - unnecessary_const
- - unnecessary_new
- - unrelated_type_equality_checks
- - valid_regexps
+ - unnecessary_getters_setters
+ - unnecessary_lambdas
+ - unnecessary_null_aware_assignments
+ - unnecessary_overrides
+ - unnecessary_parenthesis
+ - unnecessary_statements
+ - unnecessary_string_interpolations
+ - use_is_even_rather_than_modulo
+ - use_string_buffers
+ - void_checks
diff --git a/lib/shelf_web_socket.dart b/lib/shelf_web_socket.dart
index c9cbc19..061200e 100644
--- a/lib/shelf_web_socket.dart
+++ b/lib/shelf_web_socket.dart
@@ -7,7 +7,6 @@
import 'src/web_socket_handler.dart';
-typedef _BinaryFunction = void Function(Null, Null);
/// Creates a Shelf handler that upgrades HTTP requests to WebSocket
/// connections.
@@ -45,8 +44,8 @@
{Iterable<String> protocols,
Iterable<String> allowedOrigins,
Duration pingInterval}) {
- if (onConnection is! _BinaryFunction) {
- var innerOnConnection = onConnection;
+ if (onConnection is! void Function(Null, Null)) {
+ final innerOnConnection = onConnection;
onConnection = (webSocket, _) => innerOnConnection(webSocket);
}
diff --git a/lib/src/web_socket_handler.dart b/lib/src/web_socket_handler.dart
index 6f3620b..c18c221 100644
--- a/lib/src/web_socket_handler.dart
+++ b/lib/src/web_socket_handler.dart
@@ -28,17 +28,17 @@
Response handle(Request request) {
if (request.method != 'GET') return _notFound();
- var connection = request.headers['Connection'];
+ final connection = request.headers['Connection'];
if (connection == null) return _notFound();
- var tokens =
+ final tokens =
connection.toLowerCase().split(',').map((token) => token.trim());
if (!tokens.contains('upgrade')) return _notFound();
- var upgrade = request.headers['Upgrade'];
+ final upgrade = request.headers['Upgrade'];
if (upgrade == null) return _notFound();
if (upgrade.toLowerCase() != 'websocket') return _notFound();
- var version = request.headers['Sec-WebSocket-Version'];
+ final version = request.headers['Sec-WebSocket-Version'];
if (version == null) {
return _badRequest('missing Sec-WebSocket-Version header.');
} else if (version != '13') {
@@ -50,7 +50,7 @@
'"${request.protocolVersion}".');
}
- var key = request.headers['Sec-WebSocket-Key'];
+ final key = request.headers['Sec-WebSocket-Key'];
if (key == null) return _badRequest('missing Sec-WebSocket-Key header.');
if (!request.canHijack) {
@@ -61,20 +61,20 @@
// The Origin header is always set by browser connections. By filtering out
// unexpected origins, we ensure that malicious JavaScript is unable to fake
// a WebSocket handshake.
- var origin = request.headers['Origin'];
+ final origin = request.headers['Origin'];
if (origin != null &&
_allowedOrigins != null &&
!_allowedOrigins.contains(origin.toLowerCase())) {
return _forbidden('invalid origin "$origin".');
}
- var protocol = _chooseProtocol(request);
+ final protocol = _chooseProtocol(request);
request.hijack((channel) {
- var sink = utf8.encoder.startChunkedConversion(channel.sink);
- sink.add('HTTP/1.1 101 Switching Protocols\r\n'
- 'Upgrade: websocket\r\n'
- 'Connection: Upgrade\r\n'
- 'Sec-WebSocket-Accept: ${WebSocketChannel.signKey(key)}\r\n');
+ final sink = utf8.encoder.startChunkedConversion(channel.sink)
+ ..add('HTTP/1.1 101 Switching Protocols\r\n'
+ 'Upgrade: websocket\r\n'
+ 'Connection: Upgrade\r\n'
+ 'Sec-WebSocket-Accept: ${WebSocketChannel.signKey(key)}\r\n');
if (protocol != null) sink.add('Sec-WebSocket-Protocol: $protocol\r\n');
sink.add('\r\n');
@@ -92,7 +92,7 @@
///
/// If no matching protocol can be found, returns `null`.
String _chooseProtocol(Request request) {
- var requestProtocols = request.headers['Sec-WebSocket-Protocol'];
+ final requestProtocols = request.headers['Sec-WebSocket-Protocol'];
if (requestProtocols == null) return null;
if (_protocols == null) return null;
for (var requestProtocol in requestProtocols.split(',')) {
diff --git a/pubspec.yaml b/pubspec.yaml
index e3c285a..e5bf0c4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,18 +1,19 @@
name: shelf_web_socket
-version: 0.2.4-dev
+version: 0.2.4
description: >-
A shelf handler that wires up a listener for every connection.
homepage: https://github.com/dart-lang/shelf_web_socket
environment:
- sdk: ">=2.0.0 <3.0.0"
+ sdk: ">=2.1.0 <3.0.0"
dependencies:
- shelf: ^0.7.0
- web_socket_channel: ^1.0.0
+ shelf: '>=0.7.0 <2.0.0'
stream_channel: ">1.4.0 <3.0.0"
+ web_socket_channel: ^1.0.0
dev_dependencies:
http: ">=0.10.0 <0.13.0"
- test: ^1.0.0
+ pedantic: ^1.4.0
+ test: ^1.6.0
diff --git a/test/web_socket_test.dart b/test/web_socket_test.dart
index e77cad9..ed62ac4 100644
--- a/test/web_socket_test.dart
+++ b/test/web_socket_test.dart
@@ -18,7 +18,7 @@
void main() {
test('can communicate with a dart:io WebSocket client', () async {
- var server = await shelf_io.serve(webSocketHandler((webSocket) {
+ final server = await shelf_io.serve(webSocketHandler((webSocket) {
webSocket.sink.add('hello!');
webSocket.stream.first.then((request) {
expect(request, equals('ping'));
@@ -28,7 +28,8 @@
}), 'localhost', 0);
try {
- var webSocket = await WebSocket.connect('ws://localhost:${server.port}');
+ final webSocket =
+ await WebSocket.connect('ws://localhost:${server.port}');
var n = 0;
await webSocket.listen((message) {
if (n == 0) {
@@ -49,7 +50,7 @@
});
test('negotiates the sub-protocol', () async {
- var server = await shelf_io.serve(
+ final server = await shelf_io.serve(
webSocketHandler((webSocket, protocol) {
expect(protocol, equals('two'));
webSocket.sink.close();
@@ -58,7 +59,7 @@
0);
try {
- var webSocket = await WebSocket.connect('ws://localhost:${server.port}',
+ final webSocket = await WebSocket.connect('ws://localhost:${server.port}',
protocols: ['one', 'two', 'three']);
expect(webSocket.protocol, equals('two'));
return webSocket.close();
@@ -68,12 +69,12 @@
});
test('handles protocol header without allowed protocols', () async {
- var server = await shelf_io.serve(webSocketHandler((webSocket) {
+ final server = await shelf_io.serve(webSocketHandler((webSocket) {
webSocket.sink.close();
}), 'localhost', 0);
try {
- var webSocket = await WebSocket.connect('ws://localhost:${server.port}',
+ final webSocket = await WebSocket.connect('ws://localhost:${server.port}',
protocols: ['one', 'two', 'three']);
expect(webSocket.protocol, isNull);
return webSocket.close();
@@ -83,13 +84,13 @@
});
test('allows two argument callbacks without protocols', () async {
- var server = await shelf_io.serve(webSocketHandler((webSocket, protocol) {
+ final server = await shelf_io.serve(webSocketHandler((webSocket, protocol) {
expect(protocol, isNull);
webSocket.sink.close();
}), 'localhost', 0);
try {
- var webSocket = await WebSocket.connect('ws://localhost:${server.port}',
+ final webSocket = await WebSocket.connect('ws://localhost:${server.port}',
protocols: ['one', 'two', 'three']);
expect(webSocket.protocol, isNull);
return webSocket.close();
@@ -114,13 +115,13 @@
tearDown(() => server.close());
test('allows access with an allowed origin', () {
- var headers = _handshakeHeaders;
+ final headers = _handshakeHeaders;
headers['Origin'] = 'pub.dartlang.org';
expect(http.get(url, headers: headers), hasStatus(101));
});
test('forbids access with a non-allowed origin', () {
- var headers = _handshakeHeaders;
+ final headers = _handshakeHeaders;
headers['Origin'] = 'dartlang.org';
expect(http.get(url, headers: headers), hasStatus(403));
});
@@ -130,13 +131,13 @@
});
test('ignores the case of the client origin', () {
- var headers = _handshakeHeaders;
+ final headers = _handshakeHeaders;
headers['Origin'] = 'PuB.DaRtLaNg.OrG';
expect(http.get(url, headers: headers), hasStatus(101));
});
test('ignores the case of the server origin', () {
- var headers = _handshakeHeaders;
+ final headers = _handshakeHeaders;
headers['Origin'] = 'google.com';
expect(http.get(url, headers: headers), hasStatus(101));
});
@@ -144,12 +145,12 @@
// Regression test for issue 21894.
test('allows a Connection header with multiple values', () async {
- var server = await shelf_io.serve(webSocketHandler((webSocket) {
+ final server = await shelf_io.serve(webSocketHandler((webSocket) {
webSocket.sink.close();
}), 'localhost', 0);
- var url = Uri.http('localhost:${server.port}', '');
- var headers = _handshakeHeaders;
+ final url = Uri.http('localhost:${server.port}', '');
+ final headers = _handshakeHeaders;
headers['Connection'] = 'Other-Token, Upgrade';
expect(http.get(url, headers: headers).whenComplete(server.close),
hasStatus(101));
@@ -172,39 +173,36 @@
});
test('404s for non-Upgrade requests', () {
- var headers = _handshakeHeaders;
- headers.remove('Connection');
+ final headers = _handshakeHeaders..remove('Connection');
expect(http.get(url, headers: headers), hasStatus(404));
});
test('404s for non-websocket upgrade requests', () {
- var headers = _handshakeHeaders;
+ final headers = _handshakeHeaders;
headers['Upgrade'] = 'fblthp';
expect(http.get(url, headers: headers), hasStatus(404));
});
test('400s for a missing Sec-WebSocket-Version', () {
- var headers = _handshakeHeaders;
- headers.remove('Sec-WebSocket-Version');
+ final headers = _handshakeHeaders..remove('Sec-WebSocket-Version');
expect(http.get(url, headers: headers), hasStatus(400));
});
test('404s for an unknown Sec-WebSocket-Version', () {
- var headers = _handshakeHeaders;
+ final headers = _handshakeHeaders;
headers['Sec-WebSocket-Version'] = '15';
expect(http.get(url, headers: headers), hasStatus(404));
});
test('400s for a missing Sec-WebSocket-Key', () {
- var headers = _handshakeHeaders;
- headers.remove('Sec-WebSocket-Key');
+ final headers = _handshakeHeaders..remove('Sec-WebSocket-Key');
expect(http.get(url, headers: headers), hasStatus(400));
});
});
}
Matcher hasStatus(int status) => completion(predicate((response) {
- expect(response, TypeMatcher<http.Response>());
+ expect(response, isA<http.Response>());
expect(response.statusCode, equals(status));
return true;
}));