net.dart 2.02 KB
Newer Older
1 2 3 4 5 6
// Copyright 2015 The Chromium Authors. 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';

7
import '../base/context.dart';
8
import '../globals.dart';
9
import 'common.dart';
10
import 'io.dart';
11 12

const int kNetworkProblemExitCode = 50;
13

14 15
typedef HttpClient HttpClientFactory();

16 17
/// Download a file from the given URL and return the bytes.
Future<List<int>> fetchUrl(Uri url) async {
18 19 20 21 22 23 24 25 26 27 28 29 30
  int attempts = 0;
  int duration = 1;
  while (true) {
    attempts += 1;
    final List<int> result = await _attempt(url);
    if (result != null)
      return result;
    printStatus('Download failed -- attempting retry $attempts in $duration second${ duration == 1 ? "" : "s"}...');
    await new Future<Null>.delayed(new Duration(seconds: duration));
    if (duration < 64)
      duration *= 2;
  }
}
31

32 33 34 35 36 37 38 39
Future<List<int>> _attempt(Uri url) async {
  printTrace('Downloading: $url');
  HttpClient httpClient;
  if (context[HttpClientFactory] != null) {
    httpClient = context[HttpClientFactory]();
  } else {
    httpClient = new HttpClient();
  }
40 41
  final HttpClientRequest request = await httpClient.getUrl(url);
  final HttpClientResponse response = await request.close();
42
  if (response.statusCode != 200) {
43 44 45 46 47 48 49 50 51 52 53
    if (response.statusCode > 0 && response.statusCode < 500) {
      throwToolExit(
        'Download failed.\n'
        'URL: $url\n'
        'Error: ${response.statusCode} ${response.reasonPhrase}',
        exitCode: kNetworkProblemExitCode,
      );
    }
    // 5xx errors are server errors and we can try again
    printTrace('Download error: ${response.statusCode} ${response.reasonPhrase}');
    return null;
54
  }
55
  printTrace('Received response from server, collecting bytes...');
56
  try {
57
    final BytesBuilder responseBody = new BytesBuilder(copy: false);
58
    await for (List<int> chunk in response)
59
      responseBody.add(chunk);
60
    return responseBody.takeBytes();
61 62 63
  } on IOException catch (error) {
    printTrace('Download error: $error');
    return null;
64
  }
65
}