[io/socket] When socket connection fails report stacktrace of the callsite.
Currently stack trace reported on thrown exceptions is null.
TEST=socket_connect_stacktrace_test.dart
Bug: https://github.com/dart-lang/sdk/issues/44994
Change-Id: I188aff197ab519272f63f41387b94458c2f1cec7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202802
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
diff --git a/sdk/lib/_http/http_impl.dart b/sdk/lib/_http/http_impl.dart
index 6c7b768..2078dfa 100644
--- a/sdk/lib/_http/http_impl.dart
+++ b/sdk/lib/_http/http_impl.dart
@@ -2796,8 +2796,8 @@
_HttpProfileData? profileData) {
Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
- Future<_ConnectionInfo> connect(error) {
- if (!proxies.moveNext()) return new Future.error(error);
+ Future<_ConnectionInfo> connect(error, stackTrace) {
+ if (!proxies.moveNext()) return new Future.error(error, stackTrace);
_Proxy proxy = proxies.current;
String host = proxy.isDirect ? uriHost : proxy.host!;
int port = proxy.isDirect ? uriPort : proxy.port!;
@@ -2807,7 +2807,7 @@
.catchError(connect);
}
- return connect(new HttpException("No proxies given"));
+ return connect(new HttpException("No proxies given"), StackTrace.current);
}
_SiteCredentials? _findCredentials(Uri url, [_AuthenticationScheme? scheme]) {
diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart
index 6c3a77a..f04ffbb 100644
--- a/sdk/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/socket_patch.dart
@@ -673,10 +673,13 @@
"Must be a string or native InternetAddress");
}
}
+
+ final stackTrace = StackTrace.current;
+
return new Future.value(host).then<ConnectionTask<_NativeSocket>>((host) {
if (host is _InternetAddress) {
- return tryConnectToResolvedAddresses(
- host, port, source, Stream.value(<_InternetAddress>[host]));
+ return tryConnectToResolvedAddresses(host, port, source,
+ Stream.value(<_InternetAddress>[host]), stackTrace);
}
final hostname = host as String;
final staggeredLookupOverride = bool.fromEnvironment(
@@ -692,7 +695,8 @@
? staggeredLookup(hostname)
: lookupAsStream(hostname);
- return tryConnectToResolvedAddresses(host, port, source, stream);
+ return tryConnectToResolvedAddresses(
+ host, port, source, stream, stackTrace);
});
}
@@ -700,7 +704,8 @@
dynamic host,
int port,
_InternetAddress? source,
- Stream<List<InternetAddress>> addresses) {
+ Stream<List<InternetAddress>> addresses,
+ StackTrace callerStackTrace) {
// Completer for result.
final result = new Completer<_NativeSocket>();
// Error, set if an error occurs.
@@ -780,7 +785,7 @@
assert(error != null);
if (!result.isCompleted) {
// Might be already completed via onCancel
- result.completeError(error);
+ result.completeError(error, callerStackTrace);
}
return;
}
@@ -884,7 +889,7 @@
if (!result.isCompleted) {
error ??= createError(
null, "Connection attempt cancelled, host: ${host}, port: ${port}");
- result.completeError(error);
+ result.completeError(error, callerStackTrace);
}
}
diff --git a/tests/standalone/io/socket_connect_stacktrace_test.dart b/tests/standalone/io/socket_connect_stacktrace_test.dart
new file mode 100644
index 0000000..944bc4f
--- /dev/null
+++ b/tests/standalone/io/socket_connect_stacktrace_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Tests stack trace on socket exceptions.
+
+import "dart:async";
+import "dart:io";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+import 'dart:io';
+
+Future<void> main() async {
+ asyncStart();
+
+ // Test stacktrace when lookup fails
+ try {
+ await WebSocket.connect('ws://localhost.tld:0/ws');
+ } catch (err, stackTrace) {
+ Expect.contains("main ", stackTrace.toString());
+ }
+
+ // Test stacktrace when connection fails
+ try {
+ await WebSocket.connect('ws://localhost:0/ws');
+ } catch (err, stackTrace) {
+ Expect.contains("main ", stackTrace.toString());
+ }
+ asyncEnd();
+}
diff --git a/tests/standalone_2/io/socket_connect_stacktrace_test.dart b/tests/standalone_2/io/socket_connect_stacktrace_test.dart
new file mode 100644
index 0000000..944bc4f
--- /dev/null
+++ b/tests/standalone_2/io/socket_connect_stacktrace_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Tests stack trace on socket exceptions.
+
+import "dart:async";
+import "dart:io";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+import 'dart:io';
+
+Future<void> main() async {
+ asyncStart();
+
+ // Test stacktrace when lookup fails
+ try {
+ await WebSocket.connect('ws://localhost.tld:0/ws');
+ } catch (err, stackTrace) {
+ Expect.contains("main ", stackTrace.toString());
+ }
+
+ // Test stacktrace when connection fails
+ try {
+ await WebSocket.connect('ws://localhost:0/ws');
+ } catch (err, stackTrace) {
+ Expect.contains("main ", stackTrace.toString());
+ }
+ asyncEnd();
+}