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
31ca4db5
Unverified
Commit
31ca4db5
authored
Jan 26, 2022
by
Jonas Martinez
Committed by
GitHub
Jan 26, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Flutter web add support for NetworkImage headers (#85954)
parent
0e2f51df
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
314 additions
and
10 deletions
+314
-10
_network_image_web.dart
packages/flutter/lib/src/painting/_network_image_web.dart
+76
-10
_network_image_test_web.dart
packages/flutter/test/painting/_network_image_test_web.dart
+221
-0
_network_image_web_test_io.dart
...ges/flutter/test/painting/_network_image_web_test_io.dart
+7
-0
network_image_web_test.dart
packages/flutter/test/painting/network_image_web_test.dart
+10
-0
No files found.
packages/flutter/lib/src/painting/_network_image_web.dart
View file @
31ca4db5
...
...
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:html'
as
html
;
import
'dart:typed_data'
;
import
'dart:ui'
as
ui
;
import
'package:flutter/foundation.dart'
;
...
...
@@ -11,6 +12,22 @@ import 'package:flutter/foundation.dart';
import
'image_provider.dart'
as
image_provider
;
import
'image_stream.dart'
;
/// Creates a type for an overridable factory function for testing purposes.
typedef
HttpRequestFactory
=
html
.
HttpRequest
Function
();
/// Default HTTP client.
html
.
HttpRequest
_httpClient
(
)
{
return
html
.
HttpRequest
();
}
/// Creates an overridable factory function.
HttpRequestFactory
httpRequestFactory
=
_httpClient
;
/// Restores to the default HTTP request factory.
void
debugRestoreHttpRequestFactory
(
)
{
httpRequestFactory
=
_httpClient
;
}
/// The dart:html implementation of [image_provider.NetworkImage].
///
/// NetworkImage on the web does not support decoding to a specified size.
...
...
@@ -78,18 +95,67 @@ class NetworkImage
NetworkImage
key
,
image_provider
.
DecoderCallback
decode
,
StreamController
<
ImageChunkEvent
>
chunkEvents
,
)
{
)
async
{
assert
(
key
==
this
);
final
Uri
resolved
=
Uri
.
base
.
resolve
(
key
.
url
);
// This API only exists in the web engine implementation and is not
// contained in the analyzer summary for Flutter.
return
ui
.
webOnlyInstantiateImageCodecFromUrl
(
// ignore: undefined_function, avoid_dynamic_calls
resolved
,
chunkCallback:
(
int
bytes
,
int
total
)
{
chunkEvents
.
add
(
ImageChunkEvent
(
cumulativeBytesLoaded:
bytes
,
expectedTotalBytes:
total
));
},
)
as
Future
<
ui
.
Codec
>;
// We use a different method when headers are set because the
// `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers.
if
(
key
.
headers
?.
isNotEmpty
??
false
)
{
final
Completer
<
html
.
HttpRequest
>
completer
=
Completer
<
html
.
HttpRequest
>();
final
html
.
HttpRequest
request
=
httpRequestFactory
();
request
.
open
(
'GET'
,
key
.
url
,
async:
true
);
request
.
responseType
=
'arraybuffer'
;
key
.
headers
!.
forEach
((
String
header
,
String
value
)
{
request
.
setRequestHeader
(
header
,
value
);
});
request
.
onLoad
.
listen
((
html
.
ProgressEvent
e
)
{
final
int
?
status
=
request
.
status
;
final
bool
accepted
=
status
!
>=
200
&&
status
<
300
;
final
bool
fileUri
=
status
==
0
;
// file:// URIs have status of 0.
final
bool
notModified
=
status
==
304
;
final
bool
unknownRedirect
=
status
>
307
&&
status
<
400
;
final
bool
success
=
accepted
||
fileUri
||
notModified
||
unknownRedirect
;
if
(
success
)
{
completer
.
complete
(
request
);
}
else
{
completer
.
completeError
(
e
);
throw
image_provider
.
NetworkImageLoadException
(
statusCode:
request
.
status
??
400
,
uri:
resolved
);
}
});
request
.
onError
.
listen
(
completer
.
completeError
);
request
.
send
();
await
completer
.
future
;
final
Uint8List
bytes
=
(
request
.
response
as
ByteBuffer
).
asUint8List
();
if
(
bytes
.
lengthInBytes
==
0
)
throw
image_provider
.
NetworkImageLoadException
(
statusCode:
request
.
status
!,
uri:
resolved
);
return
decode
(
bytes
);
}
else
{
// This API only exists in the web engine implementation and is not
// contained in the analyzer summary for Flutter.
// ignore: undefined_function, avoid_dynamic_calls
return
ui
.
webOnlyInstantiateImageCodecFromUrl
(
resolved
,
chunkCallback:
(
int
bytes
,
int
total
)
{
chunkEvents
.
add
(
ImageChunkEvent
(
cumulativeBytesLoaded:
bytes
,
expectedTotalBytes:
total
));
},
)
as
Future
<
ui
.
Codec
>;
}
}
@override
...
...
packages/flutter/test/painting/_network_image_test_web.dart
0 → 100644
View file @
31ca4db5
// Copyright 2014 The Flutter 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'
;
import
'dart:html'
as
html
;
import
'dart:typed_data'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/src/painting/_network_image_web.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../image_data.dart'
;
void
runTests
(
)
{
tearDown
(()
{
debugRestoreHttpRequestFactory
();
});
testWidgets
(
'loads an image from the network with headers'
,
(
WidgetTester
tester
)
async
{
final
TestHttpRequest
testHttpRequest
=
TestHttpRequest
()
..
status
=
200
..
onLoad
=
Stream
<
html
.
ProgressEvent
>.
fromIterable
(<
html
.
ProgressEvent
>[
html
.
ProgressEvent
(
'test error'
),
])
..
response
=
(
Uint8List
.
fromList
(
kTransparentImage
)).
buffer
;
httpRequestFactory
=
()
{
return
testHttpRequest
;
};
const
Map
<
String
,
String
>
headers
=
<
String
,
String
>{
'flutter'
:
'flutter'
,
'second'
:
'second'
};
final
Image
image
=
Image
.
network
(
'https://www.example.com/images/frame.png'
,
headers:
headers
,
);
await
tester
.
pumpWidget
(
image
);
assert
(
mapEquals
(
testHttpRequest
.
responseHeaders
,
headers
),
true
);
});
testWidgets
(
'loads an image from the network with unsuccessful HTTP code'
,
(
WidgetTester
tester
)
async
{
final
TestHttpRequest
testHttpRequest
=
TestHttpRequest
()
..
status
=
404
..
onError
=
Stream
<
html
.
ProgressEvent
>.
fromIterable
(<
html
.
ProgressEvent
>[
html
.
ProgressEvent
(
'test error'
),
]);
httpRequestFactory
=
()
{
return
testHttpRequest
;
};
const
Map
<
String
,
String
>
headers
=
<
String
,
String
>{
'flutter'
:
'flutter'
,
'second'
:
'second'
};
final
Image
image
=
Image
.
network
(
'https://www.example.com/images/frame2.png'
,
headers:
headers
,
);
await
tester
.
pumpWidget
(
image
);
expect
((
tester
.
takeException
()
as
html
.
ProgressEvent
).
type
,
'test error'
);
});
testWidgets
(
'loads an image from the network with empty response'
,
(
WidgetTester
tester
)
async
{
final
TestHttpRequest
testHttpRequest
=
TestHttpRequest
()
..
status
=
200
..
onLoad
=
Stream
<
html
.
ProgressEvent
>.
fromIterable
(<
html
.
ProgressEvent
>[
html
.
ProgressEvent
(
'test error'
),
])
..
response
=
(
Uint8List
.
fromList
(<
int
>[])).
buffer
;
httpRequestFactory
=
()
{
return
testHttpRequest
;
};
const
Map
<
String
,
String
>
headers
=
<
String
,
String
>{
'flutter'
:
'flutter'
,
'second'
:
'second'
};
final
Image
image
=
Image
.
network
(
'https://www.example.com/images/frame3.png'
,
headers:
headers
,
);
await
tester
.
pumpWidget
(
image
);
expect
(
tester
.
takeException
().
toString
(),
'HTTP request failed, statusCode: 200, https://www.example.com/images/frame3.png'
);
});
}
// ignore: avoid_implementing_value_types
class
TestHttpRequest
implements
html
.
HttpRequest
{
@override
String
responseType
=
'invalid'
;
@override
int
?
timeout
=
10
;
@override
bool
?
withCredentials
=
false
;
@override
void
abort
()
{
throw
UnimplementedError
();
}
@override
void
addEventListener
(
String
type
,
html
.
EventListener
?
listener
,
[
bool
?
useCapture
])
{
throw
UnimplementedError
();
}
@override
bool
dispatchEvent
(
html
.
Event
event
)
{
throw
UnimplementedError
();
}
@override
String
getAllResponseHeaders
()
{
throw
UnimplementedError
();
}
@override
String
getResponseHeader
(
String
name
)
{
throw
UnimplementedError
();
}
@override
html
.
Events
get
on
=>
throw
UnimplementedError
();
@override
Stream
<
html
.
ProgressEvent
>
get
onAbort
=>
throw
UnimplementedError
();
@override
Stream
<
html
.
ProgressEvent
>
onError
=
Stream
<
html
.
ProgressEvent
>.
fromIterable
(<
html
.
ProgressEvent
>[]);
@override
Stream
<
html
.
ProgressEvent
>
onLoad
=
Stream
<
html
.
ProgressEvent
>.
fromIterable
(<
html
.
ProgressEvent
>[]);
@override
Stream
<
html
.
ProgressEvent
>
get
onLoadEnd
=>
throw
UnimplementedError
();
@override
Stream
<
html
.
ProgressEvent
>
get
onLoadStart
=>
throw
UnimplementedError
();
@override
Stream
<
html
.
ProgressEvent
>
get
onProgress
=>
throw
UnimplementedError
();
@override
Stream
<
html
.
Event
>
get
onReadyStateChange
=>
throw
UnimplementedError
();
@override
Stream
<
html
.
ProgressEvent
>
get
onTimeout
=>
throw
UnimplementedError
();
@override
void
open
(
String
method
,
String
url
,
{
bool
?
async
,
String
?
user
,
String
?
password
})
{}
@override
void
overrideMimeType
(
String
mime
)
{
throw
UnimplementedError
();
}
@override
int
get
readyState
=>
throw
UnimplementedError
();
@override
void
removeEventListener
(
String
type
,
html
.
EventListener
?
listener
,
[
bool
?
useCapture
])
{
throw
UnimplementedError
();
}
@override
dynamic
response
;
Map
<
String
,
String
>
headers
=
<
String
,
String
>{};
@override
Map
<
String
,
String
>
get
responseHeaders
=>
headers
;
@override
String
get
responseText
=>
throw
UnimplementedError
();
@override
String
get
responseUrl
=>
throw
UnimplementedError
();
@override
html
.
Document
get
responseXml
=>
throw
UnimplementedError
();
@override
void
send
([
dynamic
bodyOrData
])
{}
@override
void
setRequestHeader
(
String
name
,
String
value
)
{
headers
[
name
]
=
value
;
}
@override
int
status
=
-
1
;
@override
String
get
statusText
=>
throw
UnimplementedError
();
@override
html
.
HttpRequestUpload
get
upload
=>
throw
UnimplementedError
();
}
packages/flutter/test/painting/_network_image_web_test_io.dart
0 → 100644
View file @
31ca4db5
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
void
runTests
(
)
{
// This is a web-specific test. Nothing to do for AOT engine.
}
packages/flutter/test/painting/network_image_web_test.dart
0 → 100644
View file @
31ca4db5
// Copyright 2014 The Flutter 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
'_network_image_web_test_io.dart'
if
(
dart
.
library
.
html
)
'_network_image_test_web.dart'
;
void
main
(
)
{
runTests
();
}
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