blob: 37be1c2e00a93567554e88c2118136099791bbf6 [file] [log] [blame]
// Copyright (c) 2016, 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' show Future, Stream;
import 'dart:convert' show Encoding, latin1, utf8;
import 'dart:io'
show
File,
HttpStatus,
HttpClient,
HttpClientResponse,
HttpClientRequest,
HttpException,
HttpHeaders;
import 'package:typed_data/typed_buffers.dart' show Uint8Buffer;
/// Read the bytes of a URI as a stream of bytes.
Stream<List<int>> readAsStream(Uri uri) async* {
if (uri.scheme == 'file') {
yield* File.fromUri(uri).openRead();
return;
}
if (uri.scheme == 'http' || uri.scheme == 'https') {
var response = await _httpGetBytes(uri);
_throwIfFailed(response, uri);
yield* response;
return;
}
if (uri.scheme == 'data') {
yield uri.data.contentAsBytes();
return;
}
throw UnsupportedError('Unsupported scheme: $uri');
}
/// Read the bytes of a URI as a list of bytes.
Future<List<int>> readAsBytes(Uri uri) async {
if (uri.scheme == 'file') {
return File.fromUri(uri).readAsBytes();
}
if (uri.scheme == 'http' || uri.scheme == 'https') {
var response = await _httpGetBytes(uri);
_throwIfFailed(response, uri);
var length = response.contentLength;
if (length < 0) length = 0;
// Create empty buffer with capacity matching contentLength.
var buffer = Uint8Buffer(length)..length = 0;
await for (var bytes in response) {
buffer.addAll(bytes);
}
return buffer.toList();
}
if (uri.scheme == 'data') {
return uri.data.contentAsBytes();
}
throw UnsupportedError('Unsupported scheme: $uri');
}
/// Read the bytes of a URI as a string.
Future<String> readAsString(Uri uri, Encoding encoding) async {
if (uri.scheme == 'file') {
encoding ??= utf8;
return File.fromUri(uri).readAsString(encoding: encoding);
}
if (uri.scheme == 'http' || uri.scheme == 'https') {
var request = await HttpClient().getUrl(uri);
// Prefer text/plain, text/* if possible, otherwise take whatever is there.
request.headers.set(HttpHeaders.acceptHeader, 'text/plain, text/*, */*');
if (encoding != null) {
request.headers.set(HttpHeaders.acceptCharsetHeader, encoding.name);
}
var response = await request.close();
_throwIfFailed(response, uri);
encoding ??= Encoding.getByName(response.headers.contentType?.charset);
if (encoding == null || encoding == latin1) {
// Default to LATIN-1 if no encoding found.
// Special case LATIN-1 since it is common and doesn't need decoding.
var length = response.contentLength;
if (length < 0) length = 0;
// Create empty buffer with capacity matching contentLength.
var buffer = Uint8Buffer(length)..length = 0;
await for (var bytes in response) {
buffer.addAll(bytes);
}
var byteList = buffer.buffer.asUint8List(0, buffer.length);
return String.fromCharCodes(byteList);
}
return response.cast<List<int>>().transform(encoding.decoder).join();
}
if (uri.scheme == 'data') {
return uri.data.contentAsString(encoding: encoding);
}
throw UnsupportedError('Unsupported scheme: $uri');
}
HttpClient _sharedHttpClient = HttpClient()..maxConnectionsPerHost = 6;
Future<HttpClientResponse> _httpGetBytes(Uri uri) async {
// ignore: omit_local_variable_types
HttpClientRequest request = await _sharedHttpClient.getUrl(uri);
request.headers
.set(HttpHeaders.acceptHeader, 'application/octet-stream, */*');
return request.close();
}
void _throwIfFailed(HttpClientResponse response, Uri uri) {
var statusCode = response.statusCode;
if (statusCode < HttpStatus.ok || statusCode > HttpStatus.noContent) {
throw HttpException(response.reasonPhrase, uri: uri);
}
}