null safety (#31)

migrate to null safety
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index 727e59e..21a3c50 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -59,27 +59,3 @@
       - 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.1.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.1.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
-        if: always() && steps.install.outcome == 'success'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0590a59..8db2d16 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.0.0-dev
+
+* Migrate to null safety.
+
 ## 0.2.4+1
 
 * Support the latest `package:web_socket_channel`.
diff --git a/lib/shelf_web_socket.dart b/lib/shelf_web_socket.dart
index 061200e..420b1bf 100644
--- a/lib/shelf_web_socket.dart
+++ b/lib/shelf_web_socket.dart
@@ -7,7 +7,6 @@
 
 import 'src/web_socket_handler.dart';
 
-
 /// Creates a Shelf handler that upgrades HTTP requests to WebSocket
 /// connections.
 ///
@@ -41,9 +40,9 @@
 /// channel instance, enabling round-trip disconnect detection.
 /// See [WebSocketChannel] for more details.
 Handler webSocketHandler(Function onConnection,
-    {Iterable<String> protocols,
-    Iterable<String> allowedOrigins,
-    Duration pingInterval}) {
+    {Iterable<String>? protocols,
+    Iterable<String>? allowedOrigins,
+    Duration? pingInterval}) {
   if (onConnection is! void Function(Null, Null)) {
     final innerOnConnection = onConnection;
     onConnection = (webSocket, _) => innerOnConnection(webSocket);
@@ -52,7 +51,7 @@
   return WebSocketHandler(
     onConnection,
     protocols?.toSet(),
-    allowedOrigins?.map((origin) => origin.toLowerCase())?.toSet(),
+    allowedOrigins?.map((origin) => origin.toLowerCase()).toSet(),
     pingInterval,
   ).handle;
 }
diff --git a/lib/src/web_socket_handler.dart b/lib/src/web_socket_handler.dart
index c18c221..b4657c8 100644
--- a/lib/src/web_socket_handler.dart
+++ b/lib/src/web_socket_handler.dart
@@ -13,13 +13,13 @@
   final Function _onConnection;
 
   /// The set of protocols the user supports, or `null`.
-  final Set<String> _protocols;
+  final Set<String>? _protocols;
 
   /// The set of allowed browser origin connections, or `null`..
-  final Set<String> _allowedOrigins;
+  final Set<String>? _allowedOrigins;
 
   /// The ping interval used for verifying connection, or `null`.
-  final Duration _pingInterval;
+  final Duration? _pingInterval;
 
   WebSocketHandler(this._onConnection, this._protocols, this._allowedOrigins,
       this._pingInterval);
@@ -64,7 +64,7 @@
     final origin = request.headers['Origin'];
     if (origin != null &&
         _allowedOrigins != null &&
-        !_allowedOrigins.contains(origin.toLowerCase())) {
+        !_allowedOrigins!.contains(origin.toLowerCase())) {
       return _forbidden('invalid origin "$origin".');
     }
 
@@ -85,19 +85,19 @@
     // [request.hijack] is guaranteed to throw a [HijackException], so we'll
     // never get here.
     assert(false);
-    return null;
+    throw StateError('unreachable');
   }
 
   /// Selects a subprotocol to use for the given connection.
   ///
   /// If no matching protocol can be found, returns `null`.
-  String _chooseProtocol(Request request) {
+  String? _chooseProtocol(Request request) {
     final requestProtocols = request.headers['Sec-WebSocket-Protocol'];
     if (requestProtocols == null) return null;
     if (_protocols == null) return null;
     for (var requestProtocol in requestProtocols.split(',')) {
       requestProtocol = requestProtocol.trim();
-      if (_protocols.contains(requestProtocol)) return requestProtocol;
+      if (_protocols!.contains(requestProtocol)) return requestProtocol;
     }
     return null;
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index 8f52f76..8211256 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,19 +1,21 @@
 name: shelf_web_socket
-version: 0.2.4+1
+version: 1.0.0-dev
 
 description: >-
   A shelf handler that wires up a listener for every connection.
 repository: https://github.com/dart-lang/shelf_web_socket
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
 
 dependencies:
-  shelf: '>=0.7.0 <2.0.0'
-  stream_channel: ">1.4.0 <3.0.0"
-  web_socket_channel: '>=1.0.0 <3.0.0'
+  shelf: ^1.0.0
+  stream_channel: ^2.1.0
+  web_socket_channel: ^2.0.0
 
 dev_dependencies:
-  http: ">=0.10.0 <0.14.0"
-  pedantic: ^1.4.0
-  test: ^1.6.0
+  http: ^0.13.0
+  pedantic: ^1.10.0
+
+dependency_overrides:
+  test: ^1.16.0
diff --git a/test/web_socket_test.dart b/test/web_socket_test.dart
index ed62ac4..d2b6452 100644
--- a/test/web_socket_test.dart
+++ b/test/web_socket_test.dart
@@ -100,8 +100,8 @@
   });
 
   group('with a set of allowed origins', () {
-    HttpServer server;
-    Uri url;
+    late HttpServer server;
+    late Uri url;
     setUp(() async {
       server = await shelf_io.serve(
           webSocketHandler((webSocket) {
@@ -157,8 +157,8 @@
   });
 
   group('HTTP errors', () {
-    HttpServer server;
-    Uri url;
+    late HttpServer server;
+    late Uri url;
     setUp(() async {
       server = await shelf_io.serve(webSocketHandler((_) {
         fail('should not create a WebSocket');
@@ -201,7 +201,7 @@
   });
 }
 
-Matcher hasStatus(int status) => completion(predicate((response) {
+Matcher hasStatus(int status) => completion(predicate((http.Response response) {
       expect(response, isA<http.Response>());
       expect(response.statusCode, equals(status));
       return true;