New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 793647 link

Starred by 1 user

Issue metadata

Status: WontFix
Owner:
Closed: Dec 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Android
Pri: 2
Type: Bug

Blocking:
issue 766255



Sign in to add a comment

loadUrl("about:blank") does not enable loadData anymore

Reported by andersph...@gmail.com, Dec 10 2017

Issue description

THIS 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

 
After 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.

Labels: Needs-triage-Mobile

Comment 3 Deleted

Comment 4 Deleted

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'>{&#10;  &quot;now&quot;: &quot;2017-04-16T11:23:06Z&quot;,&#10;  &quot;escapeMe&quot;: &quot;\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\&quot;\/&quot;,&#10;  &quot;numbers&quot;: [1e+30,4.5,6]&#10;}</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>
Cc: ntfschr@chromium.org
Labels: Needs-Feedback
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
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
Blocking: 766255
Labels: Proj-PlzNavigate M-63
> 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.
Cc: nasko@chromium.org jam@chromium.org ahemery@chromium.org arthurso...@chromium.org clamy@chromium.org
Labels: -Pri-3 Pri-2
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.

Comment 10 by jam@chromium.org, Dec 12 2017

Cc: cma...@chromium.org
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.

Comment 12 by jam@chromium.org, 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.
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.
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.
> 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.

Comment 16 Deleted

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.

Comment 18 by clamy@chromium.org, 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.
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.

Comment 20 by clamy@chromium.org, Dec 12 2017

Status: WontFix (was: Assigned)

Comment 21 by torne@chromium.org, 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.
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



Comment 23 by torne@chromium.org, 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.
I've uploaded a test to demonstrate using Base64: https://chromium-review.googlesource.com/c/chromium/src/+/852565
Project Member

Comment 25 by bugdroid1@chromium.org, 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

Project Member

Comment 26 by bugdroid1@chromium.org, 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

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