loadUrl("about:blank") does not enable loadData anymore
Reported by
andersph...@gmail.com,
Dec 10 2017
|
|||||||
Issue descriptionTHIS TEMPLATE IS FOR FILING BUGS ON THE ANDROID SYSTEM WEBVIEW. GENERAL WEB BUGS SHOULD BE FILED USING A DIFFERENT TEMPLATE! Device name: HUAWEI VNS-L31 Android version: 7.0 WebView version (from system settings -> Apps -> Android System WebView): There is no such option but webView.getSettings().getUserAgentString() returns: Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L31 Build/HUAWEIVNS-L31; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 Application: https://github.com/cyberphone/android-json Application version: 1 URLs (if applicable): Steps to reproduce: (1) Start the application (2) The start screen using WebView is shown (2) Click on any of the four alternatives Expected result: The screen should change Actual result: The initial screen is still shown The debugger does not indicate any errors so it appears to be a regression bug or changed behaviour
,
Dec 11 2017
,
Dec 11 2017
It is possible that Chrome 63 puts the WebView in an error mode and refuses to load data again if there has been errors before. This is the HTML used in one of my two applications that ceased to work. Missing <!Doctype> and <title> shouldn't lead to hard errors, at least it didn't before :-)
Anyway, the only thing I have done is base64-encode to get it to work, no HTML fixes whatsoever.
Initial view which displays as expected:
<html><head><style type='text/css'>body {margin:12pt;font-size:10pt;color:#000000;font-family:Roboto;background-color:white}div {text-align:center;padding:3pt 6pt 3pt 6pt;border-width:1px;margin-bottom:15pt;border-style:solid;border-color:#a0a0a0;box-shadow:3pt 3pt 3pt #d0d0d0;background:linear-gradient(to bottom, #eaeaea 14%,#fcfcfc 52%,#e5e5e5 89%);border-radius:3pt;margin-left:auto;margin-right:auto}</style><script type='text/javascript'>
'use strict';
</script></head><body><div style='width:4em;margin-left:0pt' onclick='WebPKI.homeScreen()'>Home</div><h3 style='text-align:center'>JSON Signatures and Encryption</h3><div style='width:15em' onclick='WebPKI.signData()'>Sign JSON Data</div><div style='width:15em' onclick='WebPKI.verifySignature()'>Verify JSON (JCS) Signature</div><div style='width:15em' onclick='WebPKI.encryptData()'>Encrypt Arbitrary Data</div><div style='width:15em' onclick='WebPKI.decryptData()'>Decrypt JEF Encoded Data</div></body></html>
Other view which is invoked from the initial view and does not update WebView.
<html><head><style type='text/css'>body {margin:12pt;font-size:10pt;color:#000000;font-family:Roboto;background-color:white}div {text-align:center;padding:3pt 6pt 3pt 6pt;border-width:1px;margin-bottom:15pt;border-style:solid;border-color:#a0a0a0;box-shadow:3pt 3pt 3pt #d0d0d0;background:linear-gradient(to bottom, #eaeaea 14%,#fcfcfc 52%,#e5e5e5 89%);border-radius:3pt;margin-left:auto;margin-right:auto}</style><script type='text/javascript'>
'use strict';
function getRadio() {
return document.querySelector('input[name = "keyType"]:checked').value;
}</script></head><body><div style='width:4em;margin-left:0pt' onclick='WebPKI.homeScreen()'>Home</div><h3 style='text-align:center'>Sign JSON Data using JCS</h3><textarea id='jsonData' style='width:100%;height:40%;word-break:break-all'>{ "now": "2017-04-16T11:23:06Z", "escapeMe": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/", "numbers": [1e+30,4.5,6] }</textarea><table style='margin-top:10pt;margin-left:auto;margin-right:auto;font-size:10pt'><tr><td><input type='radio' name='keyType' value='EC_KEY' checked>EC_KEY</td></tr><tr><td><input type='radio' name='keyType' value='RSA_KEY'>RSA_KEY</td></tr><tr><td><input type='radio' name='keyType' value='PKI'>PKI</td></tr><tr><td><input type='radio' name='keyType' value='SYMMETRIC_KEY'>SYMMETRIC_KEY</td></tr></table><div style='width:6em;margin-bottom:0pt;margin-top:15pt' onclick='WebPKI.doSign(document.getElementById("jsonData").value, getRadio())'>Execute!</div></body></html>
,
Dec 11 2017
Hi andersphone@, I tried this out (I went on your github and clicked on the pre-built APK), but could not reproduce this. Tested on 63.0.3239.83. Could you please update this bug with the following: - attach a compiled APK - video showing the bug reproduced (you can follow these steps [1] to capture the video) Thanks! [1] https://developer.android.com/studio/command-line/adb.html#screenrecord
,
Dec 11 2017
Hi ntfschr@ Thanx for looking into this! Did you actually test with the OLD version of the APK which I kept just for this purpose? https://github.com/cyberphone/android-json/releases/download/1.2/android-json.apk Anders
,
Dec 11 2017
> Did you actually test with the OLD version of the APK which I kept just for this purpose? Nope, I figured you had pushed an update with the workaround. Now I can indeed reproduce. The old behavior returns if I use --disable-browser-side-navigation, so I'm flagging this as PlzNavigate-related. I'll try to dig deeper to find out what's really going on.
,
Dec 12 2017
Aha! I think this has to do with the '#' character in the URL.
This repro's in chrome. CC'ing lots of PlzNavigate people.
Minimal repro URLs:
[1] data:text/html,<html><head><style type='text/css'>body {color:#000000}</style>
</head><body>first</body></html>
[2] data:text/html,<html><head><style type='text/css'>body {color:#000000}</style>
</head><body>second</body></html>
Steps to repro:
1. Open a new tab in chrome (M63)
2. Copy-paste URL 1 in the ommnibox. Press enter. Observe that it says "first"
3. Copy-paste URL 2 in the same tab's omnibox. Press enter. Observe that it does *not* say "second", even though it should
The bug goes away if I replace '#' with '%23' (its URL encoding). I can fix the same bug using the URLs from c#5 after doing the same replacement.
---
To the PlzNavigate folks: is this a bug? It seems weird to work as expected on the first load, but not on the second (and to indeed be put in the "error mode" that the reporter suggested in c#5). For backwards compatibility, it would be nice to support '#' characters.
,
Dec 12 2017
,
Dec 12 2017
Nice work guys! I still find the documentation https://developer.android.com/reference/android/webkit/WebView.html#loadData(java.lang.String, java.lang.String, java.lang.String) pretty confusing because if you properly URL-encode text/html virtually nothing will work.
,
Dec 12 2017
The link above says "The encoding parameter specifies whether the data is base64 or URL encoded. If the data is base64 encoded, the value of the encoding parameter must be 'base64'. For all other values of the parameter, including null, it is assumed that the data uses ASCII encoding for octets inside the range of safe URL characters and use the standard %xx hex encoding of URLs for octets outside that range. For example, '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively." So it's not clear that anything is wrong? FWIW I tried the repro from comment 9 in Safari and Firefox. Safari also loaded the first one and didn't the second one (it seems to hang). Firefox didn't load either.
,
Dec 12 2017
To me it doesn't seem right to sometimes work and sometimes not work--we should really figure out the behavior we want. From WebView's perspective, we do indeed document that '#' should be escaped. Unfortunately, we haven't enforced this until M63, so we may see more broken apps. I would be (pleasantly) surprised if this is the only app relying on this behavior.
,
Dec 12 2017
Well, one might think that URLEncoder.encode would be the right thing to do but it doesn't work at all. '/' is not a URL-safe character as far as I know. Coding '#' as %23 in javascript string literals would't work as expected either. For practical purposes (reliability) base64 seems the currently only recommendable way.
,
Dec 12 2017
> Well, one might think that URLEncoder.encode would be the right thing to do but it doesn't work at all. Right, this is for a different style of encoding (for encoding forms). As far as I know, the main difference is that ' ' becomes '+' instead of '%20', but there are likely other subtle differences. > For practical purposes (reliability) base64 seems the currently only recommendable way. That's probably the "right" way to do this.
,
Dec 12 2017
I will take a look at it today. I think I understand the issue. GURL::EqualsIgnoringRef(..) return true for [1] and [2]. It caused the second navigation to be classified as a same-document navigation with the first one. I tried to fix it, but I think that KURL::EqualIgnoringFragmentIdentifier() must be updated as well. I think there was no issue without PlzNavigate because some data-url were handled directly inside the renderer. Now with PlzNavigate, all the data-url are using the same-path. If we decide that the data-urls don't have a fragment/reference (the part after the '#' symbol), I am worried that it might break same-document navigation inside documents whose urls are data-urls. I will work on a fix and see if it breaks some tests. We will decide later if it is a good idea or not.
,
Dec 12 2017
Issue 123004 had us support fragment identifiers in data URLs. As far as we can see, PlzNavigate is following the URL spec which specifies that the part after # is a fragment regardless of the URL scheme. We are doing a same-document navigation here, as expected when given to URLs matching but for the fragment identifier. I don't know why we didn't follow the spec before, but PlzNavigate is WAI. So I consider this a Wont Fix.
,
Dec 12 2017
I agree that it should be "working as intended". I added new tests related to this bug and issue 123004: https://chromium-review.googlesource.com/c/chromium/src/+/822392 Note that if we fix issue 123004, then the initial navigation in comment #5 will fail if the '#' character is not encoded.
,
Dec 12 2017
,
Dec 12 2017
Also re comment 14: there's a set of reserved characters and a set of unreserved characters in URLs. Characters in neither set (such as '%' itself) must always be percent-encoded; characters in the unreserved set never need to be percent-encoded; but characters in the reserved set only need to be percent-encoded in contexts where it's ambiguous. So, '/' is a url-safe character in a context where a path can't appear, such as in a data URI, or after the ? in a query string. You only have to encode it as %2f if it's in the path part of a URL. See https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters Coding # as %23 in a JS string literal inside a data URI does work. The %-encoding is decoded *first*, before anything is parsed as HTML/JS at all. Try data:text/html,<script>alert('%23')</script> to see it.
,
Dec 12 2017
Just for my poor understanding (as well as for my Apps...), is it correct that Base64-ing of the very same (unescaped) HTML should work? https://bugs.chromium.org/p/chromium/issues/detail?id=793647#c15 effectively says that. However, if the above assertion is incorrect, we (the application programmers), need a more exact description of what characters that MUST be translated than currently specified. "For example, '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively" is a bit imprecise IMHO. Thanx
,
Dec 12 2017
base64 encoding it and specifying the encoding as base64 will definitely work for all cases, yes. If you want to use URL encoding then the rules are the normal rules for URL encoding, and you can guarantee it will work (in all implementations everywhere) by encoding all characters that aren't in the unreserved set. None of the characters in the reserved set are special in data URIs so leaving those unencoded is fine, but it doesn't hurt to encode them either. The docs could definitely do with improvement, because the examples are wrong as well as incomplete: it doesn't appear to actually be necessary to encode '?' (because this isn't meaningful in a data URI; they do not have query strings). I'll file an internal doc bug for this on Android.
,
Jan 6 2018
I've uploaded a test to demonstrate using Base64: https://chromium-review.googlesource.com/c/chromium/src/+/852565
,
Jan 8 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/313d530f51c8ac8acffeb4c964ab75c1e870cd38 commit 313d530f51c8ac8acffeb4c964ab75c1e870cd38 Author: arthursonzogni <arthursonzogni@chromium.org> Date: Mon Jan 08 09:35:22 2018 Add tests for data URLs with reference fragments. If a data URL has a reference fragment, the '#' separator and the fragment identifier should not be part of the data URL's data. It can be very ambiguous, for instance in this URL: data:text/html,<html><head><style type='text/css'>body {color:#000000}</style></head><body>first</body></html> The data is: "<html><head><style type='text/css'>body {color:" The reference fragment is "#000000}</style></head><body>first</body></html>" Bug: 793647 , 123004 Change-Id: I95183b607daedde4e0bbc8697c543fdd293e71d4 Reviewed-on: https://chromium-review.googlesource.com/822392 Reviewed-by: Camille Lamy <clamy@chromium.org> Reviewed-by: Brett Wilson <brettw@chromium.org> Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org> Cr-Commit-Position: refs/heads/master@{#527590} [modify] https://crrev.com/313d530f51c8ac8acffeb4c964ab75c1e870cd38/content/browser/browser_side_navigation_browsertest.cc [modify] https://crrev.com/313d530f51c8ac8acffeb4c964ab75c1e870cd38/content/browser/frame_host/navigation_controller_impl_browsertest.cc [modify] https://crrev.com/313d530f51c8ac8acffeb4c964ab75c1e870cd38/url/gurl_unittest.cc
,
Jan 8 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/bd53b71c7356dca6b8a34191823f6de06f1d09b6 commit bd53b71c7356dca6b8a34191823f6de06f1d09b6 Author: Nate Fischer <ntfschr@chromium.org> Date: Mon Jan 08 19:29:24 2018 AW: modify test for Base64-encoding a data URL No change to logic. This adds more tests for Base64 encoding data URLs, including throwing some weird characters in the HTML to make sure they really do get represented literally. This also explicitly tests that using Base64.encodeToString() is supported, using the NO_PADDING flag. See also b/70555565. Bug: 793647 Test: run_webview_instrumentation_test_apk -f LoadUrlTest#testDataUrlBase64 Change-Id: Ife3756c4f9d42c702567a7ea1841eedb98143e37 Reviewed-on: https://chromium-review.googlesource.com/852565 Reviewed-by: Richard Coles <torne@chromium.org> Commit-Queue: Nate Fischer <ntfschr@chromium.org> Cr-Commit-Position: refs/heads/master@{#527710} [modify] https://crrev.com/bd53b71c7356dca6b8a34191823f6de06f1d09b6/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
,
Jan 8 2018
re comment #1 and comment #14, we'll update WebView documentation to show an example of Base64 encoding (it will look like the test case I uploaded). |
|||||||
►
Sign in to add a comment |
|||||||
Comment 1 by andersph...@gmail.com
, Dec 10 2017After some more debugging it became clear that you nowadays (from 63.x) must deal with locally created HTML in a rather quirky way: loadData(Base64.encodeToString(rawHtml.getBytes("utf-8"), Base64.NO_WRAP), "text/html", "base64"); This is unclear when reading the documentation showing an example like this: // OR, you can also load from an HTML string: String summary = "<html><body>You scored <b>192</b> points.</body></html>"; webview.loadData(summary, "text/html", null); Which is not escaping '/' etc. which the docs say is necessary. This is probably a documentation bug/issue then.