Skip to content

Commit 2917c1c

Browse files
rnewquistcommit-bot@chromium.org
authored andcommitted
[io/http] Add a HTTP Client parameter on WebSocket.connect to allow a custom HTTP Client for web socket connections.
The WebSocket abstract class was changed to allow an optional parameter called customClient that takes in a HTTPClient and passes it to the WebSocket Implementation. The WebSocket implementation takes the customClient, checks if its null, if its not null, it uses the customClient in place of the static HTTPClient that the WebSocket Implementation offers. This custom client does not override the static HTTPClient, so all previous functionality remains the same when the customClient is not present. TEST=testStaticClientUserAgentStaysTheSame() in web_socket_test.dart in standalone_2/standalone TEST=new SecurityConfiguration(secure: true).runTests(); in web_socket_error_test.dart and web_socket_test.dart in standalone_2/standalone Bug: #34284 Closes #46040 #46040 GitOrigin-RevId: 58fed38 Change-Id: I042b1e3fa7a4effed076c0deeec1f86af0dfe26d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/200262 Reviewed-by: Alexander Aprelev <[email protected]> Reviewed-by: Siva Annamalai <[email protected]> Commit-Queue: Alexander Aprelev <[email protected]>
1 parent c612650 commit 2917c1c

File tree

5 files changed

+82
-45
lines changed

5 files changed

+82
-45
lines changed

sdk/lib/_http/websocket.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,10 @@ abstract class WebSocket
375375
{Iterable<String>? protocols,
376376
Map<String, dynamic>? headers,
377377
CompressionOptions compression =
378-
CompressionOptions.compressionDefault}) =>
379-
_WebSocketImpl.connect(url, protocols, headers, compression: compression);
378+
CompressionOptions.compressionDefault,
379+
HttpClient? customClient}) =>
380+
_WebSocketImpl.connect(url, protocols, headers,
381+
compression: compression, customClient: customClient);
380382

381383
@Deprecated('This constructor will be removed in Dart 2.0. Use `implements`'
382384
' instead of `extends` if implementing this abstract class.')

sdk/lib/_http/websocket_impl.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -999,8 +999,8 @@ class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
999999

10001000
static Future<WebSocket> connect(
10011001
String url, Iterable<String>? protocols, Map<String, dynamic>? headers,
1002-
{CompressionOptions compression =
1003-
CompressionOptions.compressionDefault}) {
1002+
{CompressionOptions compression = CompressionOptions.compressionDefault,
1003+
HttpClient? customClient}) {
10041004
Uri uri = Uri.parse(url);
10051005
if (uri.scheme != "ws" && uri.scheme != "wss") {
10061006
throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'");
@@ -1024,7 +1024,7 @@ class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
10241024
path: uri.path,
10251025
query: uri.query,
10261026
fragment: uri.fragment);
1027-
return _httpClient.openUrl("GET", uri).then((request) {
1027+
return (customClient ?? _httpClient).openUrl("GET", uri).then((request) {
10281028
if (uri.userInfo != null && !uri.userInfo.isEmpty) {
10291029
// If the URL contains user information use that for basic
10301030
// authorization.

tests/standalone/io/web_socket_error_test.dart

+3-4
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ class SecurityConfiguration {
4848
: HttpServer.bind(HOST_NAME, 0, backlog: backlog);
4949

5050
Future<WebSocket> createClient(int port) =>
51-
// TODO(whesse): Add a client context argument to WebSocket.connect.
52-
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/');
51+
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/',
52+
customClient: secure ? HttpClient(context: clientContext) : null);
5353

5454
void testForceCloseServerEnd(int totalConnections) {
5555
createServer().then((server) {
@@ -94,7 +94,6 @@ class SecurityConfiguration {
9494
main() {
9595
asyncStart();
9696
new SecurityConfiguration(secure: false).runTests();
97-
// TODO(whesse): WebSocket.connect needs an optional context: parameter
98-
// new SecurityConfiguration(secure: true).runTests();
97+
new SecurityConfiguration(secure: true).runTests();
9998
asyncEnd();
10099
}

tests/standalone/io/web_socket_test.dart

+37-18
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ import "dart:io";
1313
import "dart:typed_data";
1414

1515
import "package:async_helper/async_helper.dart";
16-
import "package:convert/convert.dart";
1716
import "package:crypto/crypto.dart";
1817
import "package:expect/expect.dart";
19-
import "package:path/path.dart";
2018

2119
const WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2220

@@ -44,9 +42,17 @@ class SecurityConfiguration {
4442
? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog)
4543
: HttpServer.bind(HOST_NAME, 0, backlog: backlog);
4644

47-
Future<WebSocket> createClient(int port) =>
48-
// TODO(whesse): Add client context argument to WebSocket.connect
49-
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/');
45+
Future<WebSocket> createClient(int port,
46+
{String? user,
47+
Map<String, Object>? headers,
48+
String? customUserAgent}) =>
49+
WebSocket.connect(
50+
'${secure ? "wss" : "ws"}://${user is Null ? "" : "$user@"}$HOST_NAME:$port/',
51+
headers: headers,
52+
customClient: secure
53+
? (HttpClient(context: clientContext)
54+
..userAgent = customUserAgent)
55+
: null);
5056

5157
checkCloseStatus(webSocket, closeStatus, closeReason) {
5258
Expect.equals(
@@ -304,7 +310,7 @@ class SecurityConfiguration {
304310
asyncEnd();
305311
});
306312

307-
HttpClient client = new HttpClient();
313+
final client = HttpClient(context: secure ? clientContext : null);
308314
client
309315
.postUrl(Uri.parse(
310316
"${secure ? 'https:' : 'http:'}//$HOST_NAME:${server.port}/"))
@@ -401,12 +407,12 @@ class SecurityConfiguration {
401407
var baseWsUrl = '$wsProtocol://$HOST_NAME:${server.port}/';
402408
var httpProtocol = '${secure ? "https" : "http"}';
403409
var baseHttpUrl = '$httpProtocol://$HOST_NAME:${server.port}/';
404-
HttpClient client = new HttpClient();
410+
final client = HttpClient(context: secure ? clientContext : null);
405411

406412
for (int i = 0; i < connections; i++) {
407413
var completer = new Completer();
408414
futures.add(completer.future);
409-
WebSocket.connect('${baseWsUrl}').then((websocket) {
415+
createClient(server.port).then((websocket) {
410416
websocket.listen((_) {
411417
websocket.close();
412418
}, onDone: completer.complete);
@@ -456,9 +462,7 @@ class SecurityConfiguration {
456462
});
457463
});
458464

459-
var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/';
460-
461-
WebSocket.connect(url).then((websocket) {
465+
createClient(server.port).then((websocket) {
462466
return websocket.listen((message) {
463467
Expect.equals("Hello", message);
464468
websocket.close();
@@ -484,12 +488,11 @@ class SecurityConfiguration {
484488
});
485489
});
486490

487-
var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/';
488491
var headers = {
489492
'My-Header': 'my-value',
490493
'My-Header-Multiple': ['my-value-1', 'my-value-2']
491494
};
492-
WebSocket.connect(url, headers: headers).then((websocket) {
495+
createClient(server.port, headers: headers).then((websocket) {
493496
return websocket.listen((message) {
494497
Expect.equals("Hello", message);
495498
websocket.close();
@@ -522,9 +525,7 @@ class SecurityConfiguration {
522525
});
523526
});
524527

525-
var url =
526-
'${secure ? "wss" : "ws"}://$userInfo@$HOST_NAME:${server.port}/';
527-
WebSocket.connect(url).then((websocket) {
528+
createClient(server.port, user: userInfo).then((websocket) {
528529
return websocket.listen((message) {
529530
Expect.equals("Hello", message);
530531
websocket.close();
@@ -554,6 +555,24 @@ class SecurityConfiguration {
554555
});
555556
}
556557

558+
void testStaticClientUserAgentStaysTheSame() {
559+
asyncStart();
560+
createServer().then((server) {
561+
server.transform(new WebSocketTransformer()).listen((webSocket) {
562+
Expect.equals('Custom User Agent', WebSocket.userAgent);
563+
server.close();
564+
webSocket.close();
565+
asyncEnd();
566+
});
567+
// Next line should take no effect on custom user agent value provided
568+
WebSocket.userAgent = 'Custom User Agent';
569+
createClient(server.port, customUserAgent: 'New User Agent')
570+
.then((webSocket) {
571+
webSocket.close();
572+
});
573+
});
574+
}
575+
557576
void runTests() {
558577
testRequestResponseClientCloses(2, null, null, 1);
559578
testRequestResponseClientCloses(2, 3001, null, 2);
@@ -582,11 +601,11 @@ class SecurityConfiguration {
582601
testAdditionalHeaders();
583602
testBasicAuthentication();
584603
testShouldSetUserAgent();
604+
testStaticClientUserAgentStaysTheSame();
585605
}
586606
}
587607

588608
main() {
589609
new SecurityConfiguration(secure: false).runTests();
590-
// TODO(whesse): Make WebSocket.connect() take an optional context: parameter.
591-
// new SecurityConfiguration(secure: true).runTests();
610+
new SecurityConfiguration(secure: true).runTests();
592611
}

tests/standalone_2/io/web_socket_test.dart

+35-18
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ import "dart:io";
1515
import "dart:typed_data";
1616

1717
import "package:async_helper/async_helper.dart";
18-
import "package:convert/convert.dart";
1918
import "package:crypto/crypto.dart";
2019
import "package:expect/expect.dart";
21-
import "package:path/path.dart";
2220

2321
const WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2422

@@ -46,9 +44,15 @@ class SecurityConfiguration {
4644
? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog)
4745
: HttpServer.bind(HOST_NAME, 0, backlog: backlog);
4846

49-
Future<WebSocket> createClient(int port) =>
50-
// TODO(whesse): Add client context argument to WebSocket.connect
51-
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/');
47+
Future<WebSocket> createClient(int port,
48+
{String user, Map<String, Object> headers, String customUserAgent}) =>
49+
WebSocket.connect(
50+
'${secure ? "wss" : "ws"}://${user is Null ? "" : "$user@"}$HOST_NAME:$port/',
51+
headers: headers,
52+
customClient: secure
53+
? (HttpClient(context: clientContext)
54+
..userAgent = customUserAgent)
55+
: null);
5256

5357
checkCloseStatus(webSocket, closeStatus, closeReason) {
5458
Expect.equals(
@@ -306,7 +310,7 @@ class SecurityConfiguration {
306310
asyncEnd();
307311
});
308312

309-
HttpClient client = new HttpClient();
313+
final client = HttpClient(context: secure ? clientContext : null);
310314
client
311315
.postUrl(Uri.parse(
312316
"${secure ? 'https:' : 'http:'}//$HOST_NAME:${server.port}/"))
@@ -403,12 +407,12 @@ class SecurityConfiguration {
403407
var baseWsUrl = '$wsProtocol://$HOST_NAME:${server.port}/';
404408
var httpProtocol = '${secure ? "https" : "http"}';
405409
var baseHttpUrl = '$httpProtocol://$HOST_NAME:${server.port}/';
406-
HttpClient client = new HttpClient();
410+
final client = HttpClient(context: secure ? clientContext : null);
407411

408412
for (int i = 0; i < connections; i++) {
409413
var completer = new Completer();
410414
futures.add(completer.future);
411-
WebSocket.connect('${baseWsUrl}').then((websocket) {
415+
createClient(server.port).then((websocket) {
412416
websocket.listen((_) {
413417
websocket.close();
414418
}, onDone: completer.complete);
@@ -458,9 +462,7 @@ class SecurityConfiguration {
458462
});
459463
});
460464

461-
var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/';
462-
463-
WebSocket.connect(url).then((websocket) {
465+
createClient(server.port).then((websocket) {
464466
return websocket.listen((message) {
465467
Expect.equals("Hello", message);
466468
websocket.close();
@@ -486,12 +488,11 @@ class SecurityConfiguration {
486488
});
487489
});
488490

489-
var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/';
490491
var headers = {
491492
'My-Header': 'my-value',
492493
'My-Header-Multiple': ['my-value-1', 'my-value-2']
493494
};
494-
WebSocket.connect(url, headers: headers).then((websocket) {
495+
createClient(server.port, headers: headers).then((websocket) {
495496
return websocket.listen((message) {
496497
Expect.equals("Hello", message);
497498
websocket.close();
@@ -524,9 +525,7 @@ class SecurityConfiguration {
524525
});
525526
});
526527

527-
var url =
528-
'${secure ? "wss" : "ws"}://$userInfo@$HOST_NAME:${server.port}/';
529-
WebSocket.connect(url).then((websocket) {
528+
createClient(server.port, user: userInfo).then((websocket) {
530529
return websocket.listen((message) {
531530
Expect.equals("Hello", message);
532531
websocket.close();
@@ -556,6 +555,24 @@ class SecurityConfiguration {
556555
});
557556
}
558557

558+
void testStaticClientUserAgentStaysTheSame() {
559+
asyncStart();
560+
createServer().then((server) {
561+
server.transform(new WebSocketTransformer()).listen((webSocket) {
562+
Expect.equals('Custom User Agent', WebSocket.userAgent);
563+
server.close();
564+
webSocket.close();
565+
asyncEnd();
566+
});
567+
// Next line should take no effect on custom user agent value provided
568+
WebSocket.userAgent = 'Custom User Agent';
569+
createClient(server.port, customUserAgent: 'New User Agent')
570+
.then((webSocket) {
571+
webSocket.close();
572+
});
573+
});
574+
}
575+
559576
void runTests() {
560577
testRequestResponseClientCloses(2, null, null, 1);
561578
testRequestResponseClientCloses(2, 3001, null, 2);
@@ -584,11 +601,11 @@ class SecurityConfiguration {
584601
testAdditionalHeaders();
585602
testBasicAuthentication();
586603
testShouldSetUserAgent();
604+
testStaticClientUserAgentStaysTheSame();
587605
}
588606
}
589607

590608
main() {
591609
new SecurityConfiguration(secure: false).runTests();
592-
// TODO(whesse): Make WebSocket.connect() take an optional context: parameter.
593-
// new SecurityConfiguration(secure: true).runTests();
610+
new SecurityConfiguration(secure: true).runTests();
594611
}

0 commit comments

Comments
 (0)