Commit 6bf58bbf authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

Android: Factor out trusted CDN publisher URL provider

This CL extends the present trusted_cdn.* to be a provider
of the CDN publisher url for Java layer.

Bug: 925242
Change-Id: I232b427cbc1a5ba66d6dcc6c9f0c64b2f314892d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1493335
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638025}
parent ab064be3
......@@ -2349,6 +2349,7 @@ generate_jni("jni_headers") {
"java/src/org/chromium/chrome/browser/tab/TabFavicon.java",
"java/src/org/chromium/chrome/browser/tab/TabState.java",
"java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java",
"java/src/org/chromium/chrome/browser/tab/TrustedCdn.java",
"java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java",
"java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java",
"java/src/org/chromium/chrome/browser/tabmodel/TabModelObserverJniBridge.java",
......
......@@ -293,11 +293,6 @@ public class Tab
private FullscreenManager mFullscreenManager;
/**
* The publisher URL for pages hosted on a trusted CDN, or null otherwise.
*/
private @Nullable String mTrustedCdnPublisherUrl;
/** The current browser controls constraints. -1 if not set. */
private @BrowserControlsState int mBrowserConstrolsConstraints = -1;
......@@ -1430,6 +1425,7 @@ public class Tab
InfoBarContainer.from(this);
SwipeRefreshHandler.from(this);
TrustedCdn.from(this);
notifyContentChanged();
......@@ -2518,22 +2514,6 @@ public class Tab
return nativeAreRendererInputEventsIgnored(mNativeTabAndroid);
}
/**
* @return The publisher URL if the current page is hosted on a trusted CDN, or null otherwise.
*/
public @Nullable String getTrustedCdnPublisherUrl() {
ChromeActivity activity = getActivity();
if (activity == null) return null;
if (!activity.canShowTrustedCdnPublisherUrl()) return null;
if (getSecurityLevel() == ConnectionSecurityLevel.DANGEROUS) return null;
return mTrustedCdnPublisherUrl;
}
@CalledByNative
private void setTrustedCdnPublisherUrl(@Nullable String url) {
mTrustedCdnPublisherUrl = url;
}
private native void nativeInit();
private native void nativeDestroy(long nativeTabAndroid);
private native void nativeInitWebContents(long nativeTabAndroid, boolean incognito,
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab;
import android.support.annotation.Nullable;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ssl.SecurityStateModel;
import org.chromium.components.security_state.ConnectionSecurityLevel;
import org.chromium.content_public.browser.WebContents;
/**
* Provides a trusted CDN publisher URL for the current web contents in a Tab.
*/
public class TrustedCdn extends TabWebContentsUserData {
private static final Class<TrustedCdn> USER_DATA_KEY = TrustedCdn.class;
private final Tab mTab;
private final long mNativeTrustedCdn;
/**
* The publisher URL for pages hosted on a trusted CDN, or null otherwise.
*/
private String mPublisherUrl;
/**
* @return The publisher URL if the current page is hosted on a trusted CDN, or null otherwise
*/
@Nullable
public static String getPublisherUrl(Tab tab) {
TrustedCdn cdn = get(tab);
return cdn != null ? cdn.getPublisherUrl() : null;
}
static TrustedCdn from(Tab tab) {
TrustedCdn trustedCdn = get(tab);
if (trustedCdn == null) {
trustedCdn = tab.getUserDataHost().setUserData(USER_DATA_KEY, new TrustedCdn(tab));
}
return trustedCdn;
}
private static TrustedCdn get(Tab tab) {
return tab != null ? tab.getUserDataHost().getUserData(USER_DATA_KEY) : null;
}
private TrustedCdn(Tab tab) {
super(tab);
mTab = tab;
mNativeTrustedCdn = nativeInit();
}
@Override
public void initWebContents(WebContents webContents) {
nativeSetWebContents(mNativeTrustedCdn, webContents);
}
@Override
public void cleanupWebContents(WebContents webContents) {
nativeResetWebContents(mNativeTrustedCdn);
mPublisherUrl = null;
}
@Override
public void destroyInternal() {
nativeOnDestroyed(mNativeTrustedCdn);
}
@Nullable
private String getPublisherUrl() {
ChromeActivity activity = mTab.getActivity();
if (activity == null) return null;
if (!activity.canShowTrustedCdnPublisherUrl()) return null;
if (getSecurityLevel() == ConnectionSecurityLevel.DANGEROUS) return null;
return mPublisherUrl;
}
private int getSecurityLevel() {
return SecurityStateModel.getSecurityLevelForWebContents(mTab.getWebContents());
}
@CalledByNative
private void setPublisherUrl(@Nullable String url) {
mPublisherUrl = url;
}
private native long nativeInit();
private native void nativeOnDestroyed(long nativeTrustedCdn);
private native void nativeSetWebContents(long nativeTrustedCdn, WebContents webContents);
private native void nativeResetWebContents(long nativeTrustedCdn);
}
......@@ -29,6 +29,7 @@ import org.chromium.chrome.browser.omnibox.UrlBarData;
import org.chromium.chrome.browser.previews.PreviewsAndroidBridge;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TrustedCdn;
import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.chrome.browser.util.UrlUtilities;
import org.chromium.components.dom_distiller.core.DomDistillerService;
......@@ -238,7 +239,7 @@ public class LocationBarModel implements ToolbarDataProvider {
// If the toolbar shows the publisher URL, it applies its own formatting for emphasis.
if (mTab == null) return true;
return !shouldDisplaySearchTerms() && mTab.getTrustedCdnPublisherUrl() == null;
return !shouldDisplaySearchTerms() && TrustedCdn.getPublisherUrl(mTab) == null;
}
/**
......@@ -322,8 +323,7 @@ public class LocationBarModel implements ToolbarDataProvider {
@Override
public int getSecurityLevel() {
Tab tab = getTab();
return getSecurityLevel(
tab, isOfflinePage(), tab == null ? null : tab.getTrustedCdnPublisherUrl());
return getSecurityLevel(tab, isOfflinePage(), TrustedCdn.getPublisherUrl(tab));
}
@Override
......
......@@ -57,6 +57,7 @@ import org.chromium.chrome.browser.omnibox.UrlBarData;
import org.chromium.chrome.browser.page_info.PageInfoController;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TrustedCdn;
import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
import org.chromium.chrome.browser.toolbar.ToolbarTabController;
import org.chromium.chrome.browser.util.AccessibilityUtil;
......@@ -350,7 +351,7 @@ public class CustomTabToolbar
Tab tab = getToolbarDataProvider().getTab();
if (tab == null) return null;
String publisherUrl = tab.getTrustedCdnPublisherUrl();
String publisherUrl = TrustedCdn.getPublisherUrl(tab);
if (publisherUrl != null) return extractPublisherFromPublisherUrl(publisherUrl);
// TODO(bauerb): Remove this once trusted CDN publisher URLs have rolled out completely.
......@@ -407,14 +408,15 @@ public class CustomTabToolbar
@Override
public void setUrlToPageUrl() {
if (getCurrentTab() == null) {
Tab tab = getCurrentTab();
if (tab == null) {
mUrlCoordinator.setUrlBarData(
UrlBarData.EMPTY, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
return;
}
String publisherUrl = getCurrentTab().getTrustedCdnPublisherUrl();
String url = publisherUrl != null ? publisherUrl : getCurrentTab().getUrl().trim();
String publisherUrl = TrustedCdn.getPublisherUrl(tab);
String url = publisherUrl != null ? publisherUrl : tab.getUrl().trim();
if (mState == STATE_TITLE_ONLY) {
if (!TextUtils.isEmpty(getToolbarDataProvider().getTitle())) setTitleToPageTitle();
}
......
......@@ -1543,6 +1543,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java",
"java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java",
"java/src/org/chromium/chrome/browser/tab/TabWebContentsUserData.java",
"java/src/org/chromium/chrome/browser/tab/TrustedCdn.java",
"java/src/org/chromium/chrome/browser/tabmodel/AsyncTabParams.java",
"java/src/org/chromium/chrome/browser/tabmodel/AsyncTabParamsManager.java",
"java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java",
......
......@@ -51,6 +51,7 @@ import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
import org.chromium.chrome.browser.omnibox.UrlBar;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TrustedCdn;
import org.chromium.chrome.browser.test.ScreenShooter;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.browser.Features;
......@@ -281,7 +282,7 @@ public class TrustedCdnPublisherUrlTest {
CustomTabActivity customTabActivity = mCustomTabActivityTestRule.getActivity();
final Tab tab = customTabActivity.getActivityTab();
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
Assert.assertEquals(publisherUrl, tab.getTrustedCdnPublisherUrl());
Assert.assertEquals(publisherUrl, TrustedCdn.getPublisherUrl(tab));
customTabActivity.openCurrentUrlInBrowser(true);
Assert.assertNull(customTabActivity.getActivityTab());
});
......@@ -298,7 +299,7 @@ public class TrustedCdnPublisherUrlTest {
CriteriaHelper.pollUiThread(() -> newActivity.getActivityTab() == tab, "Tab did not load");
ThreadUtils.runOnUiThreadBlocking(
() -> { Assert.assertNull(tab.getTrustedCdnPublisherUrl()); });
() -> { Assert.assertNull(TrustedCdn.getPublisherUrl(tab)); });
String testUrl = mWebServer.getResponseUrl("/test.html");
String expectedUrl = UrlFormatter.formatUrlForDisplayOmitScheme(testUrl);
......
......@@ -18,13 +18,11 @@
#include "chrome/browser/android/metrics/uma_utils.h"
#include "chrome/browser/android/tab_printer.h"
#include "chrome/browser/android/tab_web_contents_delegate_android.h"
#include "chrome/browser/android/trusted_cdn.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
#include "chrome/browser/browser_about_handler.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/offline_pages/offline_page_utils.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/prerender/prerender_manager_factory.h"
......@@ -118,35 +116,6 @@ class TabAndroidHelper : public content::WebContentsUserData<TabAndroidHelper> {
WEB_CONTENTS_USER_DATA_KEY_IMPL(TabAndroidHelper)
GURL GetPublisherURLForTrustedCDN(
content::NavigationHandle* navigation_handle) {
if (!trusted_cdn::IsTrustedCDN(navigation_handle->GetURL()))
return GURL();
// Offline pages don't have headers when they are loaded.
// TODO(bauerb): Consider storing the publisher URL on the offline page item.
if (offline_pages::OfflinePageUtils::GetOfflinePageFromWebContents(
navigation_handle->GetWebContents())) {
return GURL();
}
const net::HttpResponseHeaders* headers =
navigation_handle->GetResponseHeaders();
if (!headers) {
// TODO(https://crbug.com/829323): In some cases other than offline pages
// we don't have headers.
LOG(WARNING) << "No headers for navigation to "
<< navigation_handle->GetURL();
return GURL();
}
std::string publisher_url;
if (!headers->GetNormalizedHeader("x-amp-cache", &publisher_url))
return GURL();
return GURL(publisher_url);
}
} // namespace
TabAndroid* TabAndroid::FromWebContents(
......@@ -326,7 +295,6 @@ void TabAndroid::InitWebContents(
TabAndroidHelper::SetTabForWebContents(web_contents(), this);
AttachTabHelpers(web_contents_.get());
WebContentsObserver::Observe(web_contents_.get());
SetWindowSessionID(session_window_id_);
......@@ -377,8 +345,6 @@ void TabAndroid::DestroyWebContents(JNIEnv* env,
if (web_contents()->GetNativeView())
web_contents()->GetNativeView()->GetLayer()->RemoveFromParent();
WebContentsObserver::Observe(nullptr);
web_contents()->SetDelegate(nullptr);
if (delete_native) {
......@@ -758,26 +724,6 @@ void TabAndroid::ClearThumbnailPlaceholder(JNIEnv* env,
tab_content_manager_->NativeRemoveTabThumbnail(GetAndroidId());
}
void TabAndroid::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
// Skip subframe, same-document, or non-committed navigations (downloads or
// 204/205 responses).
if (!navigation_handle->IsInMainFrame() ||
navigation_handle->IsSameDocument() ||
!navigation_handle->HasCommitted()) {
return;
}
GURL publisher_url = GetPublisherURLForTrustedCDN(navigation_handle);
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_publisher_url;
if (publisher_url.is_valid())
j_publisher_url = ConvertUTF8ToJavaString(env, publisher_url.spec());
Java_Tab_setTrustedCdnPublisherUrl(env, weak_java_tab_.get(env),
j_publisher_url);
}
bool TabAndroid::AreRendererInputEventsIgnored(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
......
......@@ -20,7 +20,6 @@
#include "components/infobars/core/infobar_manager.h"
#include "components/omnibox/browser/location_bar_model.h"
#include "components/sessions/core/session_id.h"
#include "content/public/browser/web_contents_observer.h"
class GURL;
class Profile;
......@@ -38,7 +37,6 @@ class TabContentManager;
namespace content {
class DevToolsAgentHost;
class NavigationHandle;
class WebContents;
}
......@@ -46,7 +44,7 @@ namespace prerender {
class PrerenderManager;
}
class TabAndroid : public content::WebContentsObserver {
class TabAndroid {
public:
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser
......@@ -70,7 +68,7 @@ class TabAndroid : public content::WebContentsObserver {
static void AttachTabHelpers(content::WebContents* web_contents);
TabAndroid(JNIEnv* env, const base::android::JavaRef<jobject>& obj);
~TabAndroid() override;
~TabAndroid();
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
......@@ -242,9 +240,6 @@ class TabAndroid : public content::WebContentsObserver {
void AttachDetachedTab(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
bool AreRendererInputEventsIgnored(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
......
......@@ -4,17 +4,33 @@
#include "chrome/browser/android/trusted_cdn.h"
#include <string>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/offline_pages/offline_page_utils.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "jni/TrustedCdn_jni.h"
#include "url/gurl.h"
namespace trusted_cdn {
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using content::WebContents;
constexpr char kDefaultTrustedCDNBaseURL[] = "https://cdn.ampproject.org";
namespace {
// Returns whether the given URL is hosted by a trusted CDN. This can be turned
// off via a Feature, and the base URL to trust can be set via a command line
// flag for testing.
bool IsTrustedCDN(const GURL& url) {
if (!base::FeatureList::IsEnabled(features::kShowTrustedPublisherURL))
return false;
......@@ -43,4 +59,76 @@ bool IsTrustedCDN(const GURL& url) {
(url.EffectiveIntPort() == trusted_cdn_base_url->EffectiveIntPort());
}
} // namespace trusted_cdn
GURL GetPublisherURL(content::NavigationHandle* navigation_handle) {
if (!IsTrustedCDN(navigation_handle->GetURL()))
return GURL();
// Offline pages don't have headers when they are loaded.
// TODO(bauerb): Consider storing the publisher URL on the offline page item.
if (offline_pages::OfflinePageUtils::GetOfflinePageFromWebContents(
navigation_handle->GetWebContents())) {
return GURL();
}
const net::HttpResponseHeaders* headers =
navigation_handle->GetResponseHeaders();
if (!headers) {
// TODO(https://crbug.com/829323): In some cases other than offline pages
// we don't have headers.
LOG(WARNING) << "No headers for navigation to "
<< navigation_handle->GetURL();
return GURL();
}
std::string publisher_url;
if (!headers->GetNormalizedHeader("x-amp-cache", &publisher_url))
return GURL();
return GURL(publisher_url);
}
} // namespace
TrustedCdn::TrustedCdn(JNIEnv* env, const JavaParamRef<jobject>& obj)
: jobj_(env, obj) {}
TrustedCdn::~TrustedCdn() = default;
void TrustedCdn::SetWebContents(JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jweb_contents) {
WebContentsObserver::Observe(WebContents::FromJavaWebContents(jweb_contents));
}
void TrustedCdn::ResetWebContents(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
WebContentsObserver::Observe(nullptr);
}
void TrustedCdn::OnDestroyed(JNIEnv* env, const JavaParamRef<jobject>& obj) {
delete this;
}
void TrustedCdn::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
// Skip subframe, same-document, or non-committed navigations (downloads or
// 204/205 responses).
if (!navigation_handle->IsInMainFrame() ||
navigation_handle->IsSameDocument() ||
!navigation_handle->HasCommitted()) {
return;
}
GURL publisher_url = GetPublisherURL(navigation_handle);
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_publisher_url;
if (publisher_url.is_valid())
j_publisher_url = ConvertUTF8ToJavaString(env, publisher_url.spec());
Java_TrustedCdn_setPublisherUrl(env, jobj_, j_publisher_url);
}
static jlong JNI_TrustedCdn_Init(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
return reinterpret_cast<intptr_t>(new TrustedCdn(env, obj));
}
......@@ -5,15 +5,34 @@
#ifndef CHROME_BROWSER_ANDROID_TRUSTED_CDN_H_
#define CHROME_BROWSER_ANDROID_TRUSTED_CDN_H_
class GURL;
#include "base/android/scoped_java_ref.h"
#include "content/public/browser/web_contents_observer.h"
namespace trusted_cdn {
namespace content {
class NavigationHandle;
}
// Returns whether the given URL is hosted by a trusted CDN. This can be turned
// off via a Feature, and the base URL to trust can be set via a command line
// flag for testing.
bool IsTrustedCDN(const GURL& url);
// Native part of Trusted CDN publisher URL provider. Managed by Java layer.
class TrustedCdn : public content::WebContentsObserver {
public:
TrustedCdn(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
~TrustedCdn() override;
} // namespace trusted_cdn
void SetWebContents(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& jweb_contents);
void ResetWebContents(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
void OnDestroyed(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
// content::WebContentsObserver
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
private:
base::android::ScopedJavaGlobalRef<jobject> jobj_;
};
#endif // CHROME_BROWSER_ANDROID_TRUSTED_CDN_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment