From 4316a6b2eda33e2f5140bbcf7d811cf225d2eed1 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 25 May 2021 18:09:01 -0700 Subject: [PATCH] [web] Ensure handleNavigationMessage can receive null arguments. (flutter/engine#26406) --- .../lib/web_ui/lib/src/engine/window.dart | 9 ++++--- .../flutter/lib/web_ui/test/window_test.dart | 27 ++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart index 3d2c1d213a3..5f355a68ca4 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/window.dart @@ -113,7 +113,7 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow { Future handleNavigationMessage(ByteData? data) async { final MethodCall decoded = JSONMethodCodec().decodeMethodCall(data); - final Map arguments = decoded.arguments; + final Map? arguments = decoded.arguments; switch (decoded.method) { case 'selectMultiEntryHistory': await _useMultiEntryBrowserHistory(); @@ -121,13 +121,16 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow { case 'selectSingleEntryHistory': await _useSingleEntryBrowserHistory(); return true; + // the following cases assert that arguments are not null case 'routeUpdated': // deprecated + assert(arguments != null); await _useSingleEntryBrowserHistory(); - browserHistory.setRouteName(arguments['routeName']); + browserHistory.setRouteName(arguments!['routeName']); return true; case 'routeInformationUpdated': + assert(arguments != null); browserHistory.setRouteName( - arguments['location'], + arguments!['location'], state: arguments['state'], ); return true; diff --git a/engine/src/flutter/lib/web_ui/test/window_test.dart b/engine/src/flutter/lib/web_ui/test/window_test.dart index 9dea67f8f60..bb823cf7335 100644 --- a/engine/src/flutter/lib/web_ui/test/window_test.dart +++ b/engine/src/flutter/lib/web_ui/test/window_test.dart @@ -82,7 +82,7 @@ void testMain() { ), useSingle: false); expect(window.browserHistory, isA()); - Future check(String method, Map arguments) async { + Future check(String method, Object? arguments) async { callback = Completer(); window.sendPlatformMessage( 'flutter/navigation', @@ -93,6 +93,10 @@ void testMain() { expect(window.browserHistory, isA()); } + // These may be initialized as `null` + // See https://github.com/flutter/flutter/issues/83158#issuecomment-847483010 + await check('selectSingleEntryHistory', null); // -> single + await check('selectMultiEntryHistory', null); // -> multi await check('selectSingleEntryHistory', {}); // -> single await check('selectMultiEntryHistory', {}); // -> multi await check('routeUpdated', {'routeName': '/bar'}); // -> single @@ -101,6 +105,27 @@ void testMain() { await check('routeInformationUpdated', {'location': '/bar'}); // does not change mode }); + test('handleNavigationMessage throws for route update methods called with null arguments', + () async { + expect(() async { + await window.handleNavigationMessage( + JSONMethodCodec().encodeMethodCall(MethodCall( + 'routeUpdated', + null, // boom + )) + ); + }, throwsAssertionError); + + expect(() async { + await window.handleNavigationMessage( + JSONMethodCodec().encodeMethodCall(MethodCall( + 'routeInformationUpdated', + null, // boom + )) + ); + }, throwsAssertionError); + }); + test('should not throw when using nav1 and nav2 together', () async { await window.debugInitializeHistory(TestUrlStrategy.fromEntry(