Skip to content

Commit

Permalink
[ package:dds ] Silently handle exceptions raised within RPC request
Browse files Browse the repository at this point in the history
handlers

Fixes flutter/flutter#84113

Change-Id: I416308845c5c7f9a1bb547b6429f1e9d49393583
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212268
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
  • Loading branch information
bkonyi authored and commit-bot@chromium.org committed Sep 1, 2021
1 parent 492d061 commit 3ff5204
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
3 changes: 3 additions & 0 deletions pkg/dds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 2.1.2
- Silently handle exceptions that occur within RPC request handlers.

# 2.1.1
- Fix another possibility of `LateInitializationError` being thrown when trying to
cleanup after an error during initialization.
Expand Down
13 changes: 11 additions & 2 deletions pkg/dds/lib/src/dds_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,17 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService {
}
pipeline = pipeline.addMiddleware(_authCodeMiddleware);
final handler = pipeline.addHandler(_handlers().handler);
// Start the DDS server.
_server = await io.serve(handler, host, port);
// Start the DDS server. Run in an error Zone to ensure that asynchronous
// exceptions encountered during request handling are handled, as exceptions
// thrown during request handling shouldn't take down the entire service.
_server = await runZonedGuarded(
() async => await io.serve(handler, host, port),
(error, stack) {
if (shouldLogRequests) {
print('Asynchronous error: $error\n$stack');
}
},
)!;

final tmpUri = Uri(
scheme: 'http',
Expand Down
2 changes: 1 addition & 1 deletion pkg/dds/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: >-
A library used to spawn the Dart Developer Service, used to communicate with
a Dart VM Service instance.
version: 2.1.1
version: 2.1.2

homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds

Expand Down
54 changes: 54 additions & 0 deletions pkg/dds/test/handles_exceptions_in_shelf_handlers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.

import 'dart:async';
import 'dart:io';

import 'package:dds/dds.dart';
import 'package:dds/src/dds_impl.dart';
import 'package:test/test.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

import 'common/fakes.dart';

Future<HttpServer> startHttpServer() async {
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
server.listen((event) async {
event.response.add([1, 2, 3]);
await event.response.flush();
await server.close(force: true);
});
return server;
}

void main() {
webSocketBuilder = (Uri _) => FakeWebSocketChannel();
peerBuilder = (WebSocketChannel _, dynamic __) async => FakePeer();

test("Handles 'Connection closed before full header was received'", () async {
final httpServer = await startHttpServer();
final dds = await DartDevelopmentService.startDartDevelopmentService(
Uri(scheme: 'http', host: httpServer.address.host, port: httpServer.port),
enableAuthCodes: false,
);
final uri = dds.uri!;

try {
final client = HttpClient();
final request = await client.get(uri.host, uri.port, 'getVM');
await request.close();
fail('Unexpected successful response');
} catch (e) {
expect(
e.toString(),
contains(
'Connection closed before full header was received',
),
);
} finally {
await dds.shutdown();
await dds.done;
}
});
}

0 comments on commit 3ff5204

Please sign in to comment.