diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index 79a33a7298..bcaa2e368d 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -179,7 +179,7 @@ class WebAssetServer implements AssetReader { static Future start( ChromiumLauncher? chromiumLauncher, String hostname, - int? port, + int port, UrlTunneller? urlTunneller, bool useSseForDebugProxy, bool useSseForDebugBackend, @@ -203,7 +203,7 @@ class WebAssetServer implements AssetReader { const int kMaxRetries = 4; for (int i = 0; i <= kMaxRetries; i++) { try { - httpServer = await HttpServer.bind(address, port ?? await globals.os.findFreePort()); + httpServer = await HttpServer.bind(address, port); break; } on SocketException catch (e, s) { if (i >= kMaxRetries) { @@ -638,7 +638,7 @@ class WebDevFS implements DevFS { /// server. WebDevFS({ required this.hostname, - required int? port, + required int port, required this.packagesFilePath, required this.urlTunneller, required this.useSseForDebugProxy, @@ -671,7 +671,7 @@ class WebDevFS implements DevFS { final ChromiumLauncher? chromiumLauncher; final bool nullAssertions; final bool nativeNullAssertions; - final int? _port; + final int _port; final NullSafetyMode nullSafetyMode; late WebAssetServer webAssetServer; diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index 035fe08862..f7bb791061 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -28,6 +28,7 @@ import '../dart/language_version.dart'; import '../devfs.dart'; import '../device.dart'; import '../flutter_plugins.dart'; +import '../globals.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../resident_devtools_handler.dart'; @@ -254,15 +255,38 @@ class ResidentWebRunner extends ResidentRunner { try { return await asyncGuard(() async { + Future getPort() async { + if (debuggingOptions.port == null) { + return globals.os.findFreePort(); + } + + final int? port = int.tryParse(debuggingOptions.port ?? ''); + + if (port == null) { + logger.printError(''' +Received a non-integer value for port: ${debuggingOptions.port} +A randomly-chosen available port will be used instead. +'''); + return globals.os.findFreePort(); + } + + if (port < 0 || port > 65535) { + throwToolExit(''' +Invalid port: ${debuggingOptions.port} +Please provide a valid TCP port (an integer between 0 and 65535, inclusive). + '''); + } + + return port; + } + final ExpressionCompiler? expressionCompiler = debuggingOptions.webEnableExpressionEvaluation ? WebExpressionCompiler(device!.generator!, fileSystem: _fileSystem) : null; device!.devFS = WebDevFS( hostname: debuggingOptions.hostname ?? 'localhost', - port: debuggingOptions.port != null - ? int.tryParse(debuggingOptions.port!) - : null, + port: await getPort(), packagesFilePath: packagesFilePath, urlTunneller: _urlTunneller, useSseForDebugProxy: debuggingOptions.webUseSseForDebugProxy, diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index f601a3b48c..acd6c09d86 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -1311,6 +1311,23 @@ flutter: FileSystem: () => fileSystem, ProcessManager: () => processManager, }); + + testUsingContext('throws when port is an integer outside the valid TCP range', () async { + final BufferLogger logger = BufferLogger.test(); + + DebuggingOptions debuggingOptions = DebuggingOptions.enabled(BuildInfo.debug, port: '65536'); + ResidentRunner residentWebRunner = + setUpResidentRunner(flutterDevice, logger: logger, debuggingOptions: debuggingOptions); + await expectToolExitLater(residentWebRunner.run(), matches('Invalid port: 65536.*')); + + debuggingOptions = DebuggingOptions.enabled(BuildInfo.debug, port: '-1'); + residentWebRunner = + setUpResidentRunner(flutterDevice, logger: logger, debuggingOptions: debuggingOptions); + await expectToolExitLater(residentWebRunner.run(), matches('Invalid port: -1.*')); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }); } ResidentRunner setUpResidentRunner(