Allow `1000` as a WebSocket close code (#1211)

Fixes https://github.com/dart-lang/http/issues/1203
diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md
index 090475c..bbbcb68 100644
--- a/pkgs/cupertino_http/CHANGELOG.md
+++ b/pkgs/cupertino_http/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.5.1-wip
+
+* Allow `1000` as a `code` argument in `CupertinoWebSocket.close`.
+
 ## 1.5.0
 
 * Add integration to the
diff --git a/pkgs/cupertino_http/lib/src/cupertino_web_socket.dart b/pkgs/cupertino_http/lib/src/cupertino_web_socket.dart
index 564c0ba..43095ff 100644
--- a/pkgs/cupertino_http/lib/src/cupertino_web_socket.dart
+++ b/pkgs/cupertino_http/lib/src/cupertino_web_socket.dart
@@ -185,8 +185,9 @@
       throw WebSocketConnectionClosed();
     }
 
-    if (code != null) {
-      RangeError.checkValueInInterval(code, 3000, 4999, 'code');
+    if (code != null && code != 1000 && !(code >= 3000 && code <= 4999)) {
+      throw ArgumentError('Invalid argument: $code, close code must be 1000 or '
+          'in the range 3000-4999');
     }
     if (reason != null && utf8.encode(reason).length > 123) {
       throw ArgumentError.value(reason, 'reason',
diff --git a/pkgs/cupertino_http/pubspec.yaml b/pkgs/cupertino_http/pubspec.yaml
index f24fd50..44a1d97 100644
--- a/pkgs/cupertino_http/pubspec.yaml
+++ b/pkgs/cupertino_http/pubspec.yaml
@@ -1,5 +1,5 @@
 name: cupertino_http
-version: 1.5.0
+version: 1.5.1-wip
 description: >-
   A macOS/iOS Flutter plugin that provides access to the Foundation URL
   Loading System.
diff --git a/pkgs/web_socket/CHANGELOG.md b/pkgs/web_socket/CHANGELOG.md
index 9f6bbdb..f97d71b 100644
--- a/pkgs/web_socket/CHANGELOG.md
+++ b/pkgs/web_socket/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.5
+
+- Allow `1000` as a close code.
+
 ## 0.1.4
 
 - Add a `fakes` function that returns a pair of `WebSocket`s useful in
diff --git a/pkgs/web_socket/lib/src/utils.dart b/pkgs/web_socket/lib/src/utils.dart
index 06a290f..7331840 100644
--- a/pkgs/web_socket/lib/src/utils.dart
+++ b/pkgs/web_socket/lib/src/utils.dart
@@ -6,8 +6,9 @@
 
 /// Throw if the given close code is not valid.
 void checkCloseCode(int? code) {
-  if (code != null) {
-    RangeError.checkValueInInterval(code, 3000, 4999, 'code');
+  if (code != null && code != 1000 && !(code >= 3000 && code <= 4999)) {
+    throw ArgumentError('Invalid argument: $code, close code must be 1000 or '
+        'in the range 3000-4999');
   }
 }
 
diff --git a/pkgs/web_socket/lib/src/web_socket.dart b/pkgs/web_socket/lib/src/web_socket.dart
index 560a5eb..5e9d7cc 100644
--- a/pkgs/web_socket/lib/src/web_socket.dart
+++ b/pkgs/web_socket/lib/src/web_socket.dart
@@ -150,7 +150,7 @@
   /// [code] is set then the peer will see a 1005 status code. If no [reason]
   /// is set then the peer will not receive a reason string.
   ///
-  /// Throws a [RangeError] if [code] is not in the range 3000-4999.
+  /// Throws an [ArgumentError] if [code] is not 1000 or in the range 3000-4999.
   ///
   /// Throws an [ArgumentError] if [reason] is longer than 123 bytes when
   /// encoded as UTF-8
diff --git a/pkgs/web_socket/pubspec.yaml b/pkgs/web_socket/pubspec.yaml
index 1a04f8a..fdc7a78 100644
--- a/pkgs/web_socket/pubspec.yaml
+++ b/pkgs/web_socket/pubspec.yaml
@@ -3,7 +3,7 @@
   Any easy-to-use library for communicating with WebSockets
   that has multiple implementations.
 repository: https://github.com/dart-lang/http/tree/master/pkgs/web_socket
-version: 0.1.4
+version: 0.1.5
 
 environment:
   sdk: ^3.3.0
diff --git a/pkgs/web_socket/test/fake_web_socket_test.dart b/pkgs/web_socket/test/fake_web_socket_test.dart
index d8fd559..3cef748 100644
--- a/pkgs/web_socket/test/fake_web_socket_test.dart
+++ b/pkgs/web_socket/test/fake_web_socket_test.dart
@@ -16,7 +16,7 @@
         case BinaryDataReceived(:final data):
           to.sendBytes(data);
         case CloseReceived(:var code, :final reason):
-          if (code != null && (code < 3000 || code > 4999)) {
+          if (code != null && code != 1000 && (code < 3000 || code > 4999)) {
             code = null;
           }
           to.close(code, reason);
diff --git a/pkgs/web_socket_conformance_tests/lib/src/close_local_tests.dart b/pkgs/web_socket_conformance_tests/lib/src/close_local_tests.dart
index 5cf8e73..cf39f95 100644
--- a/pkgs/web_socket_conformance_tests/lib/src/close_local_tests.dart
+++ b/pkgs/web_socket_conformance_tests/lib/src/close_local_tests.dart
@@ -55,9 +55,22 @@
       httpServerChannel.sink.add(null);
     });
 
-    test('reserved close code', () async {
+    test('reserved close code: 1004', () async {
       final channel = await channelFactory(uri);
-      await expectLater(() => channel.close(1004), throwsA(isA<RangeError>()));
+      await expectLater(
+          () => channel.close(1004), throwsA(isA<ArgumentError>()));
+    });
+
+    test('reserved close code: 2999', () async {
+      final channel = await channelFactory(uri);
+      await expectLater(
+          () => channel.close(2999), throwsA(isA<ArgumentError>()));
+    });
+
+    test('reserved close code: 5000', () async {
+      final channel = await channelFactory(uri);
+      await expectLater(
+          () => channel.close(5000), throwsA(isA<ArgumentError>()));
     });
 
     test('too long close reason', () async {
@@ -78,6 +91,18 @@
       expect(await channel.events.isEmpty, true);
     });
 
+    test('close with 1000', () async {
+      final channel = await channelFactory(uri);
+
+      await channel.close(1000);
+      final closeCode = await httpServerQueue.next as int?;
+      final closeReason = await httpServerQueue.next as String?;
+
+      expect(closeCode, 1000);
+      expect(closeReason, '');
+      expect(await channel.events.isEmpty, true);
+    });
+
     test('with code 3000', () async {
       final channel = await channelFactory(uri);