Skip to content

Commit

Permalink
//url: Allow Android WebView to use origins with non-standard schemes
Browse files Browse the repository at this point in the history
This adds an escape hatch so that Android WebView can restore the old
behavior before https://crrev.com/c/1208811/.

Bug: 896059
Change-Id: I90cc51fe5c6ddaa95281a51a5b89795e8a3958fe
Reviewed-on: https://chromium-review.googlesource.com/c/1338660
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
Reviewed-by: Changwan Ryu <changwan@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611436}
  • Loading branch information
zetafunction authored and Commit Bot committed Nov 28, 2018
1 parent 179ebae commit c2b752b
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 14 deletions.
1 change: 1 addition & 0 deletions android_webview/common/aw_content_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void AwContentClient::AddAdditionalSchemes(Schemes* schemes) {
schemes->local_schemes.push_back(url::kContentScheme);
schemes->secure_schemes.push_back(
android_webview::kAndroidWebViewVideoPosterScheme);
schemes->allow_non_standard_schemes_in_origins = true;
}

std::string AwContentClient::GetProduct() const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,7 @@ public void testWindowOriginForCustomSchemeUrl() throws Throwable {
AwSettings contentSettings = mActivityTestRule.getAwSettingsOnUiThread(mAwContents);
contentSettings.setJavaScriptEnabled(true);
loadDataWithBaseUrlSync("", "text/html", false, baseUri, null);
// TODO(dcheng): https://crbug.com/896059 this should be fixed as "x-thread://".
Assert.assertEquals("\"null\"",
Assert.assertEquals("\"x-thread://\"",
mActivityTestRule.executeJavaScriptAndWaitForResult(
mAwContents, mContentsClient, "window.origin;"));
}
Expand All @@ -588,8 +587,7 @@ public void testXhrForHttpSchemeUrl() throws Throwable {
@Feature({"AndroidWebView"})
// https://crbug.com/900528
public void testXhrForCustomSchemeUrl() throws Throwable {
// TODO(dcheng): this should be fixed by https://crbug.com/900528.
Assert.assertFalse(verifyXhrForUrls("myscheme://mydomain/1", "myscheme://mydomain/2"));
Assert.assertTrue(verifyXhrForUrls("myscheme://mydomain/1", "myscheme://mydomain/2"));
}

/**
Expand Down
6 changes: 6 additions & 0 deletions content/common/url_schemes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "url/url_util.h"
Expand Down Expand Up @@ -89,6 +90,11 @@ void RegisterContentSchemes(bool lock_schemes) {
for (auto& scheme : schemes.empty_document_schemes)
url::AddEmptyDocumentScheme(scheme.c_str());

#if defined(OS_ANDROID)
if (schemes.allow_non_standard_schemes_in_origins)
url::EnableNonStandardSchemesForAndroidWebView();
#endif

// Prevent future modification of the scheme lists. This is to prevent
// accidental creation of data races in the program. Add*Scheme aren't
// threadsafe so must be called when GURL isn't used on any other thread. This
Expand Down
5 changes: 5 additions & 0 deletions content/public/common/content_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ class CONTENT_EXPORT ContentClient {
// Registers a URL scheme as strictly empty documents, allowing them to
// commit synchronously.
std::vector<std::string> empty_document_schemes;
#if defined(OS_ANDROID)
// Normally, non-standard schemes canonicalize to opaque origins. However,
// Android WebView requires non-standard schemes to still be preserved.
bool allow_non_standard_schemes_in_origins = false;
#endif
};

virtual void AddAdditionalSchemes(Schemes* schemes) {}
Expand Down
21 changes: 14 additions & 7 deletions third_party/blink/renderer/platform/weborigin/security_origin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "third_party/blink/renderer/platform/wtf/wtf.h"
#include "url/url_canon.h"
#include "url/url_canon_ip.h"
#include "url/url_util.h"

namespace blink {

Expand Down Expand Up @@ -121,13 +122,19 @@ static bool ShouldTreatAsOpaqueOrigin(const KURL& url) {
return true;

// Nonstandard schemes and unregistered schemes aren't known to contain hosts
// and/or ports, so they'll usually be placed in opaque origins. An exception
// is made for non-standard local schemes.
// TODO: Migrate "content:" and "externalfile:" to be standard schemes, and
// remove the local scheme exception.
if (!relevant_url.CanSetHostOrPort() &&
!SchemeRegistry::ShouldTreatURLSchemeAsLocal(relevant_url.Protocol())) {
return true;
// and/or ports, so they'll usually be placed in opaque origins.
if (!relevant_url.CanSetHostOrPort()) {
// A temporary exception is made for non-standard local schemes.
// TODO: Migrate "content:" and "externalfile:" to be standard schemes, and
// remove the local scheme exception.
if (SchemeRegistry::ShouldTreatURLSchemeAsLocal(relevant_url.Protocol()))
return false;

// Otherwise, treat non-standard origins as opaque, unless the Android
// WebView workaround is enabled. If the workaround is enabled, return false
// so that the scheme is retained, to avoid breaking XHRs on custom schemes,
// et cetera.
return !url::AllowNonStandardSchemesForAndroidWebView();
}

// This is the common case.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,4 +790,21 @@ TEST_F(SecurityOriginTest, ToTokenForFastCheck) {
}
}

TEST_F(SecurityOriginTest, NonStandardScheme) {
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString("cow://");
EXPECT_TRUE(origin->IsOpaque());
}

TEST_F(SecurityOriginTest, NonStandardSchemeWithAndroidWebViewHack) {
url::EnableNonStandardSchemesForAndroidWebView();
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString("cow://");
EXPECT_FALSE(origin->IsOpaque());
EXPECT_EQ("cow", origin->Protocol());
EXPECT_EQ("", origin->Host());
EXPECT_EQ(0, origin->Port());
url::Shutdown();
}

} // namespace blink
3 changes: 2 additions & 1 deletion url/origin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ Origin Origin::Create(const GURL& url) {
// It's SchemeHostPort's responsibility to filter out unrecognized schemes;
// sanity check that this is happening.
DCHECK(tuple.IsInvalid() || url.IsStandard() ||
base::ContainsValue(GetLocalSchemes(), url.scheme_piece()));
base::ContainsValue(GetLocalSchemes(), url.scheme_piece()) ||
AllowNonStandardSchemesForAndroidWebView());
}

if (tuple.IsInvalid())
Expand Down
14 changes: 14 additions & 0 deletions url/origin_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -654,4 +654,18 @@ TEST_F(OriginTest, DebugAlias) {
EXPECT_STREQ("https://foo.com", origin1_debug_alias);
}

TEST_F(OriginTest, NonStandardScheme) {
Origin origin = Origin::Create(GURL("cow://"));
EXPECT_TRUE(origin.opaque());
}
TEST_F(OriginTest, NonStandardSchemeWithAndroidWebViewHack) {
EnableNonStandardSchemesForAndroidWebView();
Origin origin = Origin::Create(GURL("cow://"));
EXPECT_FALSE(origin.opaque());
EXPECT_EQ("cow", origin.scheme());
EXPECT_EQ("", origin.host());
EXPECT_EQ(0, origin.port());
Shutdown();
}

} // namespace url
12 changes: 10 additions & 2 deletions url/scheme_host_port.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ bool IsValidInput(const base::StringPiece& scheme,
const base::StringPiece& host,
uint16_t port,
SchemeHostPort::ConstructPolicy policy) {
// Empty schemes are never valid.
if (scheme.empty())
return false;

SchemeType scheme_type = SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION;
bool is_standard = GetStandardSchemeType(
scheme.data(),
Expand All @@ -67,7 +71,10 @@ bool IsValidInput(const base::StringPiece& scheme,
if (base::ContainsValue(GetLocalSchemes(), scheme) && host.empty() &&
port == 0)
return true;
return false;

// Otherwise, allow non-standard schemes only if the Android WebView
// workaround is enabled.
return AllowNonStandardSchemesForAndroidWebView();
}

switch (scheme_type) {
Expand Down Expand Up @@ -135,7 +142,8 @@ SchemeHostPort::SchemeHostPort(std::string scheme,
scheme_ = std::move(scheme);
host_ = std::move(host);
port_ = port;
DCHECK(!IsInvalid());
DCHECK(!IsInvalid()) << "Scheme: " << scheme_ << " Host: " << host_
<< " Port: " << port;
}

SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
Expand Down
11 changes: 11 additions & 0 deletions url/url_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ namespace url {

namespace {

bool g_allow_non_standard_schemes = false;

// Pass this enum through for methods which would like to know if whitespace
// removal is necessary.
enum WhitespaceRemovalPolicy {
Expand Down Expand Up @@ -530,6 +532,7 @@ void Initialize() {

void Shutdown() {
initialized = false;
g_allow_non_standard_schemes = false;
delete standard_schemes;
standard_schemes = nullptr;
delete referrer_schemes;
Expand All @@ -550,6 +553,14 @@ void Shutdown() {
empty_document_schemes = nullptr;
}

void EnableNonStandardSchemesForAndroidWebView() {
g_allow_non_standard_schemes = true;
}

bool AllowNonStandardSchemesForAndroidWebView() {
return g_allow_non_standard_schemes;
}

void AddStandardScheme(const char* new_scheme, SchemeType type) {
Initialize();
DoAddSchemeWithType(new_scheme, type, standard_schemes);
Expand Down
11 changes: 11 additions & 0 deletions url/url_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ URL_EXPORT void Shutdown();

// Schemes ---------------------------------------------------------------------

// Changes the behavior of SchemeHostPort / Origin to allow non-standard schemes
// to be specified, instead of canonicalizing them to an invalid SchemeHostPort
// or opaque Origin, respectively. This is used for Android WebView backwards
// compatibility, which allows the use of custom schemes: content hosted in
// Android WebView assumes that one URL with a non-standard scheme will be
// same-origin to another URL with the same non-standard scheme.
URL_EXPORT void EnableNonStandardSchemesForAndroidWebView();

// Whether or not SchemeHostPort and Origin allow non-standard schemes.
URL_EXPORT bool AllowNonStandardSchemesForAndroidWebView();

// A pair for representing a standard scheme name and the SchemeType for it.
struct URL_EXPORT SchemeWithType {
const char* scheme;
Expand Down

0 comments on commit c2b752b

Please sign in to comment.