Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
74c1be6f
Commit
74c1be6f
authored
Jan 28, 2020
by
Zachary Anderson
Committed by
Flutter GitHub Bot
Jan 28, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tool] Make base/net.dart context free (#49575)
parent
9980d6e5
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
295 additions
and
216 deletions
+295
-216
net.dart
packages/flutter_tools/lib/src/base/net.dart
+144
-121
cache.dart
packages/flutter_tools/lib/src/cache.dart
+29
-17
create.dart
packages/flutter_tools/lib/src/commands/create.dart
+14
-3
update_packages.dart
packages/flutter_tools/lib/src/commands/update_packages.dart
+17
-2
net_test.dart
packages/flutter_tools/test/general.shard/base/net_test.dart
+82
-73
testbed.dart
packages/flutter_tools/test/src/testbed.dart
+9
-0
No files found.
packages/flutter_tools/lib/src/base/net.dart
View file @
74c1be6f
...
...
@@ -4,12 +4,14 @@
import
'dart:async'
;
import
'../base/context.dart'
;
import
'package:meta/meta.dart'
;
import
'package:platform/platform.dart'
;
import
'../convert.dart'
;
import
'../globals.dart'
as
globals
;
import
'common.dart'
;
import
'file_system.dart'
;
import
'io.dart'
;
import
'logger.dart'
;
const
int
kNetworkProblemExitCode
=
50
;
...
...
@@ -17,139 +19,160 @@ typedef HttpClientFactory = HttpClient Function();
typedef
UrlTunneller
=
Future
<
String
>
Function
(
String
url
);
/// Download a file from the given URL.
///
/// If a destination file is not provided, returns the bytes.
///
/// If a destination file is provided, streams the bytes to that file and
/// returns an empty list.
///
/// If [maxAttempts] is exceeded, returns null.
Future
<
List
<
int
>>
fetchUrl
(
Uri
url
,
{
int
maxAttempts
,
File
destFile
,
})
async
{
int
attempts
=
0
;
int
durationSeconds
=
1
;
while
(
true
)
{
attempts
+=
1
;
_MemoryIOSink
memorySink
;
IOSink
sink
;
if
(
destFile
==
null
)
{
memorySink
=
_MemoryIOSink
();
sink
=
memorySink
;
}
else
{
sink
=
destFile
.
openWrite
();
}
class
Net
{
Net
({
HttpClientFactory
httpClientFactory
,
@required
Logger
logger
,
@required
Platform
platform
,
})
:
_httpClientFactory
=
httpClientFactory
,
_logger
=
logger
,
_platform
=
platform
;
final
HttpClientFactory
_httpClientFactory
;
final
Logger
_logger
;
final
Platform
_platform
;
/// Download a file from the given URL.
///
/// If a destination file is not provided, returns the bytes.
///
/// If a destination file is provided, streams the bytes to that file and
/// returns an empty list.
///
/// If [maxAttempts] is exceeded, returns null.
Future
<
List
<
int
>>
fetchUrl
(
Uri
url
,
{
int
maxAttempts
,
File
destFile
,
})
async
{
int
attempts
=
0
;
int
durationSeconds
=
1
;
while
(
true
)
{
attempts
+=
1
;
_MemoryIOSink
memorySink
;
IOSink
sink
;
if
(
destFile
==
null
)
{
memorySink
=
_MemoryIOSink
();
sink
=
memorySink
;
}
else
{
sink
=
destFile
.
openWrite
();
}
final
bool
result
=
await
_attempt
(
url
,
destSink:
sink
,
);
if
(
result
)
{
return
memorySink
?.
writes
?.
takeBytes
()
??
<
int
>[];
}
final
bool
result
=
await
_attempt
(
url
,
destSink:
sink
,
);
if
(
result
)
{
return
memorySink
?.
writes
?.
takeBytes
()
??
<
int
>[];
}
if
(
maxAttempts
!=
null
&&
attempts
>=
maxAttempts
)
{
globals
.
printStatus
(
'Download failed -- retry
$attempts
'
);
return
null
;
}
globals
.
printStatus
(
'Download failed -- attempting retry
$attempts
in '
'
$durationSeconds
second
${ durationSeconds == 1 ? "" : "s"}
...'
);
await
Future
<
void
>.
delayed
(
Duration
(
seconds:
durationSeconds
));
if
(
durationSeconds
<
64
)
{
durationSeconds
*=
2
;
if
(
maxAttempts
!=
null
&&
attempts
>=
maxAttempts
)
{
_logger
.
printStatus
(
'Download failed -- retry
$attempts
'
);
return
null
;
}
_logger
.
printStatus
(
'Download failed -- attempting retry
$attempts
in '
'
$durationSeconds
second
${ durationSeconds == 1 ? "" : "s"}
...'
,
);
await
Future
<
void
>.
delayed
(
Duration
(
seconds:
durationSeconds
));
if
(
durationSeconds
<
64
)
{
durationSeconds
*=
2
;
}
}
}
}
/// Check if the given URL points to a valid endpoint.
Future
<
bool
>
doesRemoteFileExist
(
Uri
url
)
async
=>
await
_attempt
(
url
,
onlyHeaders:
true
);
// Returns true on success and false on failure.
Future
<
bool
>
_attempt
(
Uri
url
,
{
IOSink
destSink
,
bool
onlyHeaders
=
false
,
})
async
{
assert
(
onlyHeaders
||
destSink
!=
null
);
globals
.
printTrace
(
'Downloading:
$url
'
);
HttpClient
httpClient
;
if
(
context
.
get
<
HttpClientFactory
>()
!=
null
)
{
httpClient
=
context
.
get
<
HttpClientFactory
>()();
}
else
{
httpClient
=
HttpClient
();
}
HttpClientRequest
request
;
HttpClientResponse
response
;
try
{
if
(
onlyHeaders
)
{
request
=
await
httpClient
.
headUrl
(
url
);
/// Check if the given URL points to a valid endpoint.
Future
<
bool
>
doesRemoteFileExist
(
Uri
url
)
=>
_attempt
(
url
,
onlyHeaders:
true
);
// Returns true on success and false on failure.
Future
<
bool
>
_attempt
(
Uri
url
,
{
IOSink
destSink
,
bool
onlyHeaders
=
false
,
})
async
{
assert
(
onlyHeaders
||
destSink
!=
null
);
_logger
.
printTrace
(
'Downloading:
$url
'
);
HttpClient
httpClient
;
if
(
_httpClientFactory
!=
null
)
{
httpClient
=
_httpClientFactory
();
}
else
{
request
=
await
httpClient
.
getUrl
(
url
);
}
response
=
await
request
.
close
();
}
on
ArgumentError
catch
(
error
)
{
final
String
overrideUrl
=
globals
.
platform
.
environment
[
'FLUTTER_STORAGE_BASE_URL'
];
if
(
overrideUrl
!=
null
&&
url
.
toString
().
contains
(
overrideUrl
))
{
globals
.
printError
(
error
.
toString
());
throwToolExit
(
'The value of FLUTTER_STORAGE_BASE_URL (
$overrideUrl
) could not be '
'parsed as a valid url. Please see https://flutter.dev/community/china '
'for an example of how to use it.
\n
'
'Full URL:
$url
'
,
exitCode:
kNetworkProblemExitCode
,);
httpClient
=
HttpClient
();
}
globals
.
printError
(
error
.
toString
());
rethrow
;
}
on
HandshakeException
catch
(
error
)
{
globals
.
printTrace
(
error
.
toString
());
throwToolExit
(
'Could not authenticate download server. You may be experiencing a man-in-the-middle attack,
\n
'
'your network may be compromised, or you may have malware installed on your computer.
\n
'
'URL:
$url
'
,
exitCode:
kNetworkProblemExitCode
,
);
}
on
SocketException
catch
(
error
)
{
globals
.
printTrace
(
'Download error:
$error
'
);
return
false
;
}
on
HttpException
catch
(
error
)
{
globals
.
printTrace
(
'Download error:
$error
'
);
return
false
;
}
assert
(
response
!=
null
);
// If we're making a HEAD request, we're only checking to see if the URL is
// valid.
if
(
onlyHeaders
)
{
return
response
.
statusCode
==
HttpStatus
.
ok
;
}
if
(
response
.
statusCode
!=
HttpStatus
.
ok
)
{
if
(
response
.
statusCode
>
0
&&
response
.
statusCode
<
500
)
{
HttpClientRequest
request
;
HttpClientResponse
response
;
try
{
if
(
onlyHeaders
)
{
request
=
await
httpClient
.
headUrl
(
url
);
}
else
{
request
=
await
httpClient
.
getUrl
(
url
);
}
response
=
await
request
.
close
();
}
on
ArgumentError
catch
(
error
)
{
final
String
overrideUrl
=
_platform
.
environment
[
'FLUTTER_STORAGE_BASE_URL'
];
if
(
overrideUrl
!=
null
&&
url
.
toString
().
contains
(
overrideUrl
))
{
_logger
.
printError
(
error
.
toString
());
throwToolExit
(
'The value of FLUTTER_STORAGE_BASE_URL (
$overrideUrl
) could not be '
'parsed as a valid url. Please see https://flutter.dev/community/china '
'for an example of how to use it.
\n
'
'Full URL:
$url
'
,
exitCode:
kNetworkProblemExitCode
,);
}
_logger
.
printError
(
error
.
toString
());
rethrow
;
}
on
HandshakeException
catch
(
error
)
{
_logger
.
printTrace
(
error
.
toString
());
throwToolExit
(
'
Download failed.
\n
'
'
URL:
$url
\n
'
'
Error:
${response.statusCode}
${response.reasonPhrase}
'
,
'
Could not authenticate download server. You may be experiencing a man-in-the-middle attack,
\n
'
'
your network may be compromised, or you may have malware installed on your computer.
\n
'
'
URL:
$url
'
,
exitCode:
kNetworkProblemExitCode
,
);
}
on
SocketException
catch
(
error
)
{
_logger
.
printTrace
(
'Download error:
$error
'
);
return
false
;
}
on
HttpException
catch
(
error
)
{
_logger
.
printTrace
(
'Download error:
$error
'
);
return
false
;
}
assert
(
response
!=
null
);
// If we're making a HEAD request, we're only checking to see if the URL is
// valid.
if
(
onlyHeaders
)
{
return
response
.
statusCode
==
HttpStatus
.
ok
;
}
if
(
response
.
statusCode
!=
HttpStatus
.
ok
)
{
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
_logger
.
printTrace
(
'Download error:
${response.statusCode}
${response.reasonPhrase}
'
);
return
false
;
}
_logger
.
printTrace
(
'Received response from server, collecting bytes...'
);
try
{
assert
(
destSink
!=
null
);
await
response
.
forEach
(
destSink
.
add
);
return
true
;
}
on
IOException
catch
(
error
)
{
_logger
.
printTrace
(
'Download error:
$error
'
);
return
false
;
}
finally
{
await
destSink
?.
flush
();
await
destSink
?.
close
();
}
// 5xx errors are server errors and we can try again
globals
.
printTrace
(
'Download error:
${response.statusCode}
${response.reasonPhrase}
'
);
return
false
;
}
globals
.
printTrace
(
'Received response from server, collecting bytes...'
);
try
{
assert
(
destSink
!=
null
);
await
response
.
forEach
(
destSink
.
add
);
return
true
;
}
on
IOException
catch
(
error
)
{
globals
.
printTrace
(
'Download error:
$error
'
);
return
false
;
}
finally
{
await
destSink
?.
flush
();
await
destSink
?.
close
();
}
}
/// An IOSink that collects whatever is written to it.
class
_MemoryIOSink
implements
IOSink
{
@override
...
...
packages/flutter_tools/lib/src/cache.dart
View file @
74c1be6f
...
...
@@ -103,6 +103,9 @@ class Cache {
_fileSystem
=
fileSystem
??
globals
.
fs
,
_platform
=
platform
??
globals
.
platform
,
_osUtils
=
osUtils
??
os
{
// TODO(zra): Move to initializer list once logger and platform parameters
// are required.
_net
=
Net
(
logger:
_logger
,
platform:
_platform
);
if
(
artifacts
==
null
)
{
_artifacts
.
add
(
MaterialFonts
(
this
));
...
...
@@ -135,6 +138,8 @@ class Cache {
final
FileSystem
_fileSystem
;
final
OperatingSystemUtils
_osUtils
;
Net
_net
;
static
const
List
<
String
>
_hostsBlockedInChina
=
<
String
>
[
'storage.googleapis.com'
,
];
...
...
@@ -386,7 +391,7 @@ class Cache {
final
File
cachedFile
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
serviceDir
.
path
,
url
.
pathSegments
.
last
));
if
(!
cachedFile
.
existsSync
())
{
try
{
await
_
downloadFile
(
url
,
cachedFile
);
await
downloadFile
(
url
,
cachedFile
);
}
catch
(
e
)
{
throwToolExit
(
'Failed to fetch third-party artifact
$url
:
$e
'
);
}
...
...
@@ -439,6 +444,26 @@ class Cache {
this
.
includeAllPlatforms
=
includeAllPlatformsState
;
return
allAvailible
;
}
/// Download a file from the given [url] and write it to [location].
Future
<
void
>
downloadFile
(
Uri
url
,
File
location
)
async
{
_ensureExists
(
location
.
parent
);
await
_net
.
fetchUrl
(
url
,
destFile:
location
);
}
Future
<
bool
>
doesRemoteExist
(
String
message
,
Uri
url
)
async
{
final
Status
status
=
globals
.
logger
.
startProgress
(
message
,
timeout:
timeoutConfiguration
.
slowOperation
,
);
bool
exists
;
try
{
exists
=
await
_net
.
doesRemoteFileExist
(
url
);
}
finally
{
status
.
stop
();
}
return
exists
;
}
}
/// Representation of a set of artifacts used by the tool.
...
...
@@ -559,7 +584,7 @@ abstract class CachedArtifact extends ArtifactSet {
if
(!
verifier
(
tempFile
))
{
final
Status
status
=
globals
.
logger
.
startProgress
(
message
,
timeout:
timeoutConfiguration
.
slowOperation
);
try
{
await
_
downloadFile
(
url
,
tempFile
);
await
cache
.
downloadFile
(
url
,
tempFile
);
status
.
stop
();
}
catch
(
exception
)
{
status
.
cancel
();
...
...
@@ -741,7 +766,7 @@ abstract class EngineCachedArtifact extends CachedArtifact {
bool
exists
=
false
;
for
(
final
String
pkgName
in
getPackageDirs
())
{
exists
=
await
_
doesRemoteExist
(
'Checking package
$pkgName
is available...'
,
exists
=
await
cache
.
doesRemoteExist
(
'Checking package
$pkgName
is available...'
,
Uri
.
parse
(
url
+
pkgName
+
'.zip'
));
if
(!
exists
)
{
return
false
;
...
...
@@ -751,7 +776,7 @@ abstract class EngineCachedArtifact extends CachedArtifact {
for
(
final
List
<
String
>
toolsDir
in
getBinaryDirs
())
{
final
String
cacheDir
=
toolsDir
[
0
];
final
String
urlPath
=
toolsDir
[
1
];
exists
=
await
_
doesRemoteExist
(
'Checking
$cacheDir
tools are available...'
,
exists
=
await
cache
.
doesRemoteExist
(
'Checking
$cacheDir
tools are available...'
,
Uri
.
parse
(
url
+
urlPath
));
if
(!
exists
)
{
return
false
;
...
...
@@ -1305,19 +1330,6 @@ String flattenNameSubdirs(Uri url) {
return
globals
.
fs
.
path
.
joinAll
(
convertedPieces
);
}
/// Download a file from the given [url] and write it to [location].
Future
<
void
>
_downloadFile
(
Uri
url
,
File
location
)
async
{
_ensureExists
(
location
.
parent
);
await
fetchUrl
(
url
,
destFile:
location
);
}
Future
<
bool
>
_doesRemoteExist
(
String
message
,
Uri
url
)
async
{
final
Status
status
=
globals
.
logger
.
startProgress
(
message
,
timeout:
timeoutConfiguration
.
slowOperation
);
final
bool
exists
=
await
doesRemoteFileExist
(
url
);
status
.
stop
();
return
exists
;
}
/// Create the given [directory] and parents, as necessary.
void
_ensureExists
(
Directory
directory
)
{
if
(!
directory
.
existsSync
())
{
...
...
packages/flutter_tools/lib/src/commands/create.dart
View file @
74c1be6f
...
...
@@ -11,7 +11,9 @@ import '../android/android.dart' as android;
import
'../android/android_sdk.dart'
as
android_sdk
;
import
'../android/gradle_utils.dart'
as
gradle
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/net.dart'
;
import
'../base/os.dart'
;
import
'../base/utils.dart'
;
...
...
@@ -165,6 +167,14 @@ class CreateCommand extends FlutterCommand {
};
}
// Lazy-initialize the net utilities with values from the context.
Net
_cachedNet
;
Net
get
_net
=>
_cachedNet
??=
Net
(
httpClientFactory:
context
.
get
<
HttpClientFactory
>()
??
()
=>
HttpClient
(),
logger:
globals
.
logger
,
platform:
globals
.
platform
,
);
// If it has a .metadata file with the project_type in it, use that.
// If it has an android dir and an android/app dir, it's a legacy app
// If it has an ios dir and an ios/Flutter dir, it's a legacy app
...
...
@@ -229,13 +239,14 @@ class CreateCommand extends FlutterCommand {
'documentation and try again.'
);
}
return
utf8
.
decode
(
await
fetchUrl
(
Uri
.
https
(
_snippetsHost
,
'snippets/
$sampleId
.dart'
)));
final
Uri
snippetsUri
=
Uri
.
https
(
_snippetsHost
,
'snippets/
$sampleId
.dart'
);
return
utf8
.
decode
(
await
_net
.
fetchUrl
(
snippetsUri
));
}
/// Fetches the samples index file from the Flutter docs website.
Future
<
String
>
_fetchSamplesIndexFromServer
()
async
{
return
utf8
.
decode
(
await
fetchUrl
(
Uri
.
https
(
_snippetsHost
,
'snippets/index.json'
)
,
maxAttempts:
2
));
final
Uri
snippetsUri
=
Uri
.
https
(
_snippetsHost
,
'snippets/index.json'
);
return
utf8
.
decode
(
await
_net
.
fetchUrl
(
snippetsUri
,
maxAttempts:
2
));
}
/// Fetches the samples index file from the server and writes it to
...
...
packages/flutter_tools/lib/src/commands/update_packages.dart
View file @
74c1be6f
...
...
@@ -8,7 +8,9 @@ import 'dart:collection';
import
'package:meta/meta.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/net.dart'
;
import
'../cache.dart'
;
...
...
@@ -88,14 +90,27 @@ class UpdatePackagesCommand extends FlutterCommand {
@override
final
bool
hidden
;
// Lazy-initialize the net utilities with values from the context.
Net
_cachedNet
;
Net
get
_net
=>
_cachedNet
??=
Net
(
httpClientFactory:
context
.
get
<
HttpClientFactory
>()
??
()
=>
HttpClient
(),
logger:
globals
.
logger
,
platform:
globals
.
platform
,
);
Future
<
void
>
_downloadCoverageData
()
async
{
final
Status
status
=
globals
.
logger
.
startProgress
(
'Downloading lcov data for package:flutter...'
,
timeout:
timeoutConfiguration
.
slowOperation
,
);
final
String
urlBase
=
globals
.
platform
.
environment
[
'FLUTTER_STORAGE_BASE_URL'
]
??
'https://storage.googleapis.com'
;
final
List
<
int
>
data
=
await
fetchUrl
(
Uri
.
parse
(
'
$urlBase
/flutter_infra/flutter/coverage/lcov.info'
));
final
String
coverageDir
=
globals
.
fs
.
path
.
join
(
Cache
.
flutterRoot
,
'packages/flutter/coverage'
);
final
Uri
coverageUri
=
Uri
.
parse
(
'
$urlBase
/flutter_infra/flutter/coverage/lcov.info'
);
final
List
<
int
>
data
=
await
_net
.
fetchUrl
(
coverageUri
);
final
String
coverageDir
=
globals
.
fs
.
path
.
join
(
Cache
.
flutterRoot
,
'packages/flutter/coverage'
,
);
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
coverageDir
,
'lcov.base.info'
))
..
createSync
(
recursive:
true
)
..
writeAsBytesSync
(
data
,
flush:
true
);
...
...
packages/flutter_tools/test/general.shard/base/net_test.dart
View file @
74c1be6f
This diff is collapsed.
Click to expand it.
packages/flutter_tools/test/src/testbed.dart
View file @
74c1be6f
...
...
@@ -922,4 +922,13 @@ class FakeCache implements Cache {
@override
Future
<
void
>
updateAll
(
Set
<
DevelopmentArtifact
>
requiredArtifacts
)
async
{
}
@override
Future
<
void
>
downloadFile
(
Uri
url
,
File
location
)
async
{
}
@override
Future
<
bool
>
doesRemoteExist
(
String
message
,
Uri
url
)
async
{
return
true
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment