Unverified Commit 7f64e2ae authored by Lau Ching Jun's avatar Lau Ching Jun Committed by GitHub

Catch errors in ProxiedDevice to make sure we don't crash on errors. (#101332)

parent 815cac47
...@@ -519,21 +519,31 @@ class ProxiedPortForwarder extends DevicePortForwarder { ...@@ -519,21 +519,31 @@ class ProxiedPortForwarder extends DevicePortForwarder {
// Do nothing here. // Do nothing here.
})); }));
socket.listen((Uint8List data) { socket.listen((Uint8List data) {
connection.sendRequest('proxy.write', <String, Object>{ unawaited(connection.sendRequest('proxy.write', <String, Object>{
'id': id, 'id': id,
}, data); }, data).catchError((Object error, StackTrace stackTrace) {
// Log the error, but proceed normally. Network failure should not
// crash the tool. If this is critical, the place where the connection
// is being used would crash.
_logger.printWarning('Write to remote proxy error: $error');
_logger.printTrace('Write to remote proxy error: $error, stack trace: $stackTrace');
}));
}); });
_connectedSockets.add(socket); _connectedSockets.add(socket);
unawaited(socket.done.then((dynamic value) { unawaited(socket.done.catchError((Object error, StackTrace stackTrace) {
connection.sendRequest('proxy.disconnect', <String, Object>{ // Do nothing here. Everything will be handled in the `then` block below.
'id': id, return false;
}); }).whenComplete(() {
_connectedSockets.remove(socket); // Send a proxy disconnect event just in case.
}).onError((Object? error, StackTrace stackTrace) { unawaited(connection.sendRequest('proxy.disconnect', <String, Object>{
connection.sendRequest('proxy.disconnect', <String, Object>{
'id': id, 'id': id,
}); }).catchError((Object error, StackTrace stackTrace) {
// Ignore the error here. There might be a race condition when the
// remote end also disconnects. In any case, this request is just to
// notify the remote end to disconnect and we should not crash when
// there is an error here.
}));
_connectedSockets.remove(socket); _connectedSockets.remove(socket);
})); }));
}, onError: (Object error, StackTrace stackTrace) { }, onError: (Object error, StackTrace stackTrace) {
......
...@@ -137,6 +137,71 @@ void main() { ...@@ -137,6 +137,71 @@ void main() {
'hostPort': 350, 'hostPort': 350,
}); });
}); });
group('socket done', () {
late Stream<DaemonMessage> broadcastOutput;
late FakeSocket fakeSocket;
const String id = 'random_id';
setUp(() async {
final FakeServerSocket fakeServerSocket = FakeServerSocket(400);
final ProxiedPortForwarder portForwarder = ProxiedPortForwarder(
clientDaemonConnection,
deviceId: 'device_id',
logger: bufferLogger,
createSocketServer: (Logger logger, int? hostPort) async =>
fakeServerSocket,
);
broadcastOutput = serverDaemonConnection.incomingCommands.asBroadcastStream();
unawaited(portForwarder.forward(300));
// Consumes the message.
DaemonMessage message = await broadcastOutput.first;
serverDaemonConnection.sendResponse(message.data['id']!, <String, Object?>{'hostPort': 350});
fakeSocket = FakeSocket();
fakeServerSocket.controller.add(fakeSocket);
// Consumes the message.
message = await broadcastOutput.first;
serverDaemonConnection.sendResponse(message.data['id']!, id);
// Pump the event queue so that the socket future error handler has a
// chance to be listened to.
await pumpEventQueue();
});
testWithoutContext('without error, should calls proxy.disconnect', () async {
// It will try to disconnect the remote port when socket is done.
fakeSocket.doneCompleter.complete(true);
final DaemonMessage message = await broadcastOutput.first;
expect(message.data['id'], isNotNull);
expect(message.data['method'], 'proxy.disconnect');
expect(message.data['params'], <String, Object?>{
'id': 'random_id',
});
});
testWithoutContext('with error, should also calls proxy.disconnect', () async {
fakeSocket.doneCompleter.complete(true);
final DaemonMessage message = await broadcastOutput.first;
expect(message.data['id'], isNotNull);
expect(message.data['method'], 'proxy.disconnect');
expect(message.data['params'], <String, Object?>{
'id': 'random_id',
});
// Send an error response and make sure that it won't crash the client.
serverDaemonConnection.sendErrorResponse(message.data['id']!, 'some error', StackTrace.current);
// Wait the event queue and make sure that it doesn't crash.
await pumpEventQueue();
});
});
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment