Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter] fix: unreliable encoding for web #5737

Merged
merged 19 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/webview_flutter/webview_flutter_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.1.0+4

* Fixes incorrect escaping of some characters when setting the HTML to the iframe element.

## 0.1.0+3

* Minor fixes for new analysis options.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:html';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
Expand Down Expand Up @@ -183,7 +184,11 @@ class WebWebViewPlatformController implements WebViewPlatformController {
String? baseUrl,
}) async {
// ignore: unsafe_html
_element.src = 'data:text/html,${Uri.encodeFull(html)}';
_element.src = Uri.dataFromString(
html,
mimeType: 'text/html',
encoding: utf8,
).toString();
}

@override
Expand All @@ -199,8 +204,11 @@ class WebWebViewPlatformController implements WebViewPlatformController {
final String contentType =
httpReq.getResponseHeader('content-type') ?? 'text/html';
// ignore: unsafe_html
_element.src =
'data:$contentType,${Uri.encodeFull(httpReq.responseText ?? '')}';
_element.src = Uri.dataFromString(
httpReq.responseText ?? '',
mimeType: contentType,
encoding: utf8,
Comment on lines +209 to +210
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question. This correctly determines the mimeType from the response object. But what if the response is a binary image/png instead of text/html? Would the Uri encoding work in this case?

(Note: this might have been broken in the earlier version too :S)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worked for me.
I replaced the Url in the example project of webview_flutter_web with one that returns a content-type of image/jpeg and it displayed the image.

).toString();
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_web
description: A Flutter plugin that provides a WebView widget on web.
repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_web
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 0.1.0+3
version: 0.1.0+4

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,33 @@ void main() {
verify(mockElement.src = 'test url');
});

test('loadHtmlString loads html into iframe', () {
// Setup
final MockIFrameElement mockElement = MockIFrameElement();
final WebWebViewPlatformController controller =
WebWebViewPlatformController(
mockElement,
);
// Run
controller.loadHtmlString('test html');
// Verify
verify(mockElement.src = 'data:text/html,${Uri.encodeFull('test html')}');
group('loadHtmlString', () {
test('loadHtmlString loads html into iframe', () {
// Setup
final MockIFrameElement mockElement = MockIFrameElement();
final WebWebViewPlatformController controller =
WebWebViewPlatformController(
mockElement,
);
// Run
controller.loadHtmlString('test html');
// Verify
verify(mockElement.src =
'data:text/html;charset=utf-8,${Uri.encodeFull('test html')}');
});

test('loadHtmlString escapes "#" correctly', () {
// Setup
final MockIFrameElement mockElement = MockIFrameElement();
final WebWebViewPlatformController controller =
WebWebViewPlatformController(
mockElement,
);
// Run
controller.loadHtmlString('#');
// Verify
verify(mockElement.src = argThat(contains('%23')));
});
});

group('loadRequest', () {
FlafyDev marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -122,8 +138,40 @@ void main() {
requestHeaders: <String, String>{'Foo': 'Bar'},
sendData: Uint8List.fromList('test body'.codeUnits),
));
verify(
mockElement.src = 'data:text/plain,${Uri.encodeFull('test data')}');
verify(mockElement.src =
'data:;charset=utf-8,${Uri.encodeFull('test data')}');
});

test('loadRequest escapes "#" correctly', () async {
// Setup
final MockIFrameElement mockElement = MockIFrameElement();
final WebWebViewPlatformController controller =
WebWebViewPlatformController(
mockElement,
);
final MockHttpRequest mockHttpRequest = MockHttpRequest();
when(mockHttpRequest.getResponseHeader('content-type'))
.thenReturn('text/html');
when(mockHttpRequest.responseText).thenReturn('#');
final MockHttpRequestFactory mockHttpRequestFactory =
MockHttpRequestFactory();
when(mockHttpRequestFactory.request(
any,
method: anyNamed('method'),
requestHeaders: anyNamed('requestHeaders'),
sendData: anyNamed('sendData'),
)).thenAnswer((_) => Future<HttpRequest>.value(mockHttpRequest));
controller.httpRequestFactory = mockHttpRequestFactory;
// Run
await controller.loadRequest(
WebViewRequest(
uri: Uri.parse('https://flutter.dev'),
method: WebViewRequestMethod.post,
body: Uint8List.fromList('test body'.codeUnits),
headers: <String, String>{'Foo': 'Bar'}),
);
// Verify
verify(mockElement.src = argThat(contains('%23')));
});
});
});
Expand Down