diff --git a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md index 8ab70f9a78d3..631608689a7a 100644 --- a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md @@ -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. diff --git a/packages/webview_flutter/webview_flutter_web/lib/webview_flutter_web.dart b/packages/webview_flutter/webview_flutter_web/lib/webview_flutter_web.dart index 637c24926275..adf6495b8f2a 100644 --- a/packages/webview_flutter/webview_flutter_web/lib/webview_flutter_web.dart +++ b/packages/webview_flutter/webview_flutter_web/lib/webview_flutter_web.dart @@ -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'; @@ -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 @@ -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, + ).toString(); } @override diff --git a/packages/webview_flutter/webview_flutter_web/pubspec.yaml b/packages/webview_flutter/webview_flutter_web/pubspec.yaml index 6464e20fe37c..12bec7242519 100644 --- a/packages/webview_flutter/webview_flutter_web/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_web/pubspec.yaml @@ -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" diff --git a/packages/webview_flutter/webview_flutter_web/test/webview_flutter_web_test.dart b/packages/webview_flutter/webview_flutter_web/test/webview_flutter_web_test.dart index 6058dcf07272..08337e42e661 100644 --- a/packages/webview_flutter/webview_flutter_web/test/webview_flutter_web_test.dart +++ b/packages/webview_flutter/webview_flutter_web/test/webview_flutter_web_test.dart @@ -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', () { @@ -122,8 +138,40 @@ void main() { requestHeaders: {'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.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: {'Foo': 'Bar'}), + ); + // Verify + verify(mockElement.src = argThat(contains('%23'))); }); }); });