Allow passing through custom http client in IO socket connect (dart-lang/web_socket_channel#259)

diff --git a/pkgs/web_socket_channel/.github/workflows/test-package.yml b/pkgs/web_socket_channel/.github/workflows/test-package.yml
index 1fee291..a25e138 100644
--- a/pkgs/web_socket_channel/.github/workflows/test-package.yml
+++ b/pkgs/web_socket_channel/.github/workflows/test-package.yml
@@ -42,7 +42,7 @@
       fail-fast: false
       matrix:
         os: [ubuntu-latest]
-        sdk: [2.12.0, dev]
+        sdk: [2.15.0, dev]
     steps:
       - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
       - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
diff --git a/pkgs/web_socket_channel/CHANGELOG.md b/pkgs/web_socket_channel/CHANGELOG.md
index 6e0de0c..f8d64f1 100644
--- a/pkgs/web_socket_channel/CHANGELOG.md
+++ b/pkgs/web_socket_channel/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 2.4.0
+
+- Add a `customClient` parameter to the `IOWebSocketChannel.connect` factory,
+  which allows the user to provide a custom `HttpClient` instance to use for the
+  WebSocket connection
+- Bump minimum Dart version to 2.15.0
+
 ## 2.3.0
 
 - Added a Future `ready` property to `WebSocketChannel`, which completes when
diff --git a/pkgs/web_socket_channel/lib/io.dart b/pkgs/web_socket_channel/lib/io.dart
index 15f2f0d..e39bc67 100644
--- a/pkgs/web_socket_channel/lib/io.dart
+++ b/pkgs/web_socket_channel/lib/io.dart
@@ -74,6 +74,7 @@
     Map<String, dynamic>? headers,
     Duration? pingInterval,
     Duration? connectTimeout,
+    HttpClient? customClient,
   }) {
     late IOWebSocketChannel channel;
     final sinkCompleter = WebSocketSinkCompleter();
@@ -81,6 +82,7 @@
       url.toString(),
       headers: headers,
       protocols: protocols,
+      customClient: customClient,
     );
     if (connectTimeout != null) {
       future = future.timeout(connectTimeout);
diff --git a/pkgs/web_socket_channel/pubspec.yaml b/pkgs/web_socket_channel/pubspec.yaml
index 4041d87..71b28e1 100644
--- a/pkgs/web_socket_channel/pubspec.yaml
+++ b/pkgs/web_socket_channel/pubspec.yaml
@@ -1,5 +1,5 @@
 name: web_socket_channel
-version: 2.3.0
+version: 2.4.0
 
 description: >-
   StreamChannel wrappers for WebSockets. Provides a cross-platform
@@ -8,7 +8,7 @@
 repository: https://github.com/dart-lang/web_socket_channel
 
 environment:
-  sdk: ">=2.12.0 <3.0.0"
+  sdk: ">=2.15.0 <3.0.0"
 
 dependencies:
   async: ^2.5.0
diff --git a/pkgs/web_socket_channel/test/io_test.dart b/pkgs/web_socket_channel/test/io_test.dart
index f681ac6..fde1a9f 100644
--- a/pkgs/web_socket_channel/test/io_test.dart
+++ b/pkgs/web_socket_channel/test/io_test.dart
@@ -229,4 +229,22 @@
     expect(channel.ready, throwsA(isA<TimeoutException>()));
     expect(channel.stream.drain(), throwsA(isA<WebSocketChannelException>()));
   });
+
+  test('.custom client is passed through', () async {
+    server = await HttpServer.bind('localhost', 0);
+    addTearDown(server.close);
+    server.transform(StreamTransformer<HttpRequest, HttpRequest>.fromHandlers(
+      handleData: (data, sink) {
+        expect(data.headers['user-agent'], ['custom']);
+        sink.add(data);
+      },
+    )).transform(WebSocketTransformer());
+
+    final channel = IOWebSocketChannel.connect(
+      'ws://localhost:${server.port}',
+      customClient: HttpClient()..userAgent = 'custom',
+    );
+
+    expect(channel.ready, completes);
+  });
 }