improve flutter tool error message for download problems (#6238)

diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart
index 771398c..233836a 100644
--- a/packages/flutter_tools/lib/executable.dart
+++ b/packages/flutter_tools/lib/executable.dart
@@ -8,6 +8,7 @@
 import 'package:args/command_runner.dart';
 import 'package:stack_trace/stack_trace.dart';
 
+import 'src/base/common.dart';
 import 'src/base/context.dart';
 import 'src/base/logger.dart';
 import 'src/base/process.dart';
@@ -102,6 +103,16 @@
       );
       // Argument error exit code.
       _exit(64);
+    } else if (error is ToolExit) {
+      stderr.writeln(error.message);
+      if (verbose) {
+        stderr.writeln();
+        stderr.writeln(chain.terse.toString());
+        stderr.writeln();
+      }
+      stderr.writeln('If this problem persists, please report the problem at');
+      stderr.writeln('https://github.com/flutter/flutter/issues/new');
+      _exit(error.exitCode ?? 65);
     } else if (error is ProcessExit) {
       // We've caught an exit code.
       _exit(error.exitCode);
diff --git a/packages/flutter_tools/lib/src/base/common.dart b/packages/flutter_tools/lib/src/base/common.dart
index 2725d23..b9fef20 100644
--- a/packages/flutter_tools/lib/src/base/common.dart
+++ b/packages/flutter_tools/lib/src/base/common.dart
@@ -5,3 +5,17 @@
 const int kDefaultObservatoryPort = 8100;
 const int kDefaultDiagnosticPort  = 8101;
 const int kDefaultDrivePort       = 8183;
+
+/// Specialized exception for expected situations
+/// where the tool should exit with a clear message to the user
+/// and no stack trace unless the --verbose option is specified.
+/// For example: network errors
+class ToolExit implements Exception {
+  ToolExit(this.message, { this.exitCode });
+
+  final String message;
+  final int exitCode;
+
+  @override
+  String toString() => "Exception: $message";
+}
diff --git a/packages/flutter_tools/lib/src/base/net.dart b/packages/flutter_tools/lib/src/base/net.dart
index 6eb69b6..66459fd 100644
--- a/packages/flutter_tools/lib/src/base/net.dart
+++ b/packages/flutter_tools/lib/src/base/net.dart
@@ -6,6 +6,9 @@
 import 'dart:io';
 
 import '../globals.dart';
+import 'common.dart';
+
+const int kNetworkProblemExitCode = 50;
 
 /// Download a file from the given URL and return the bytes.
 Future<List<int>> fetchUrl(Uri url) async {
@@ -16,8 +19,13 @@
   HttpClientResponse response = await request.close();
 
   printTrace('Received response statusCode=${response.statusCode}');
-  if (response.statusCode != 200)
-    throw new Exception(response.reasonPhrase);
+  if (response.statusCode != 200) {
+    throw new ToolExit(
+      'Download failed: $url\n'
+          '  because (${response.statusCode}) ${response.reasonPhrase}',
+      exitCode: kNetworkProblemExitCode,
+    );
+  }
 
   BytesBuilder responseBody = new BytesBuilder(copy: false);
   await for (List<int> chunk in response)