Commit 6aea9a3e authored by ppi@chromium.org's avatar ppi@chromium.org

Android: support http referrers for context menu navigations.

This patch provides the support needed for setting http referrers on URL
loads triggered from the context menu:

- adds Referrer.java holder corresponding to the native
  content::Referrer
- ContextMenuParams.java now holds a Referrer field set (along with
  sanitization) by ContextMenuHelper
- ContextMenuItemDelegate methods that trigger new navigations accept a
  Referrer parameter (save for OpenInNewIncognitoTab, as we drop the
  referrer in this case)
- LoadUrlParams.java also gets a Referrer field, so that embedders can
  set it in their ContextMenuItemDelegate implementations

BUG=340295

Review URL: https://codereview.chromium.org/178193033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255370 0039d316-1c4b-4281-b951-d872f2087c98
parent ad35a60c
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
package org.chromium.chrome.browser.contextmenu; package org.chromium.chrome.browser.contextmenu;
import org.chromium.chrome.browser.Tab; import org.chromium.chrome.browser.Tab;
import org.chromium.content.browser.ContentView; import org.chromium.content_public.Referrer;
/** /**
* A delegate responsible for taking actions based on context menu selections. * A delegate responsible for taking actions based on context menu selections.
...@@ -39,7 +39,7 @@ public interface ChromeContextMenuItemDelegate { ...@@ -39,7 +39,7 @@ public interface ChromeContextMenuItemDelegate {
* the current {@link Tab}. * the current {@link Tab}.
* @param url The URL to open. * @param url The URL to open.
*/ */
void onOpenInNewTab(String url); void onOpenInNewTab(String url, Referrer referrer);
/** /**
* Called when the {@code url} should be opened in a new incognito tab. * Called when the {@code url} should be opened in a new incognito tab.
...@@ -51,13 +51,13 @@ public interface ChromeContextMenuItemDelegate { ...@@ -51,13 +51,13 @@ public interface ChromeContextMenuItemDelegate {
* Called when the {@code url} is of an image and should be opened in the same tab. * Called when the {@code url} is of an image and should be opened in the same tab.
* @param url The image URL to open. * @param url The image URL to open.
*/ */
void onOpenImageUrl(String url); void onOpenImageUrl(String url, Referrer referrer);
/** /**
* Called when the {@code url} is of an image and should be opened in a new tab. * Called when the {@code url} is of an image and should be opened in a new tab.
* @param url The image URL to open. * @param url The image URL to open.
*/ */
void onOpenImageInNewTab(String url); void onOpenImageInNewTab(String url, Referrer referrer);
/** /**
* Called when the {@code text} should be saved to the clipboard. * Called when the {@code text} should be saved to the clipboard.
......
...@@ -95,14 +95,14 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator { ...@@ -95,14 +95,14 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
@Override @Override
public boolean onItemSelected(ContextMenuHelper helper, ContextMenuParams params, int itemId) { public boolean onItemSelected(ContextMenuHelper helper, ContextMenuParams params, int itemId) {
if (itemId == R.id.contextmenu_open_in_new_tab) { if (itemId == R.id.contextmenu_open_in_new_tab) {
mDelegate.onOpenInNewTab(params.getLinkUrl()); mDelegate.onOpenInNewTab(params.getLinkUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_in_incognito_tab) { } else if (itemId == R.id.contextmenu_open_in_incognito_tab) {
mDelegate.onOpenInNewIncognitoTab(params.getLinkUrl()); mDelegate.onOpenInNewIncognitoTab(params.getLinkUrl());
} else if (itemId == R.id.contextmenu_open_image) { } else if (itemId == R.id.contextmenu_open_image) {
mDelegate.onOpenImageUrl(params.getSrcUrl()); mDelegate.onOpenImageUrl(params.getSrcUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_image_in_new_tab || } else if (itemId == R.id.contextmenu_open_image_in_new_tab ||
itemId == R.id.contextmenu_open_original_image_in_new_tab) { itemId == R.id.contextmenu_open_original_image_in_new_tab) {
mDelegate.onOpenImageInNewTab(params.getSrcUrl()); mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_copy_link_address_text) { } else if (itemId == R.id.contextmenu_copy_link_address_text) {
mDelegate.onSaveToClipboard(params.getUnfilteredLinkUrl(), true); mDelegate.onSaveToClipboard(params.getUnfilteredLinkUrl(), true);
} else if (itemId == R.id.contextmenu_copy_link_text) { } else if (itemId == R.id.contextmenu_copy_link_text) {
...@@ -122,4 +122,4 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator { ...@@ -122,4 +122,4 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
return true; return true;
} }
} }
\ No newline at end of file
...@@ -8,6 +8,7 @@ import android.text.TextUtils; ...@@ -8,6 +8,7 @@ import android.text.TextUtils;
import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace; import org.chromium.base.JNINamespace;
import org.chromium.content_public.Referrer;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -43,6 +44,7 @@ public class ContextMenuParams { ...@@ -43,6 +44,7 @@ public class ContextMenuParams {
private final String mUnfilteredLinkUrl; private final String mUnfilteredLinkUrl;
private final String mSrcUrl; private final String mSrcUrl;
private final boolean mIsEditable; private final boolean mIsEditable;
private final Referrer mReferrer;
private final boolean mIsAnchor; private final boolean mIsAnchor;
private final boolean mIsSelectedText; private final boolean mIsSelectedText;
...@@ -120,6 +122,13 @@ public class ContextMenuParams { ...@@ -120,6 +122,13 @@ public class ContextMenuParams {
return mIsEditable; return mIsEditable;
} }
/**
* @return the referrer associated with the frame on which the menu is invoked
*/
public Referrer getReferrer() {
return mReferrer;
}
/** /**
* @return Whether or not the context menu is being shown for an anchor. * @return Whether or not the context menu is being shown for an anchor.
*/ */
...@@ -149,12 +158,14 @@ public class ContextMenuParams { ...@@ -149,12 +158,14 @@ public class ContextMenuParams {
} }
private ContextMenuParams(int mediaType, String linkUrl, String linkText, private ContextMenuParams(int mediaType, String linkUrl, String linkText,
String unfilteredLinkUrl, String srcUrl, String selectionText, boolean isEditable) { String unfilteredLinkUrl, String srcUrl, String selectionText, boolean isEditable,
Referrer referrer) {
mLinkUrl = linkUrl; mLinkUrl = linkUrl;
mLinkText = linkText; mLinkText = linkText;
mUnfilteredLinkUrl = unfilteredLinkUrl; mUnfilteredLinkUrl = unfilteredLinkUrl;
mSrcUrl = srcUrl; mSrcUrl = srcUrl;
mIsEditable = isEditable; mIsEditable = isEditable;
mReferrer = referrer;
mIsAnchor = !TextUtils.isEmpty(linkUrl); mIsAnchor = !TextUtils.isEmpty(linkUrl);
mIsSelectedText = !TextUtils.isEmpty(selectionText); mIsSelectedText = !TextUtils.isEmpty(selectionText);
...@@ -164,13 +175,16 @@ public class ContextMenuParams { ...@@ -164,13 +175,16 @@ public class ContextMenuParams {
@CalledByNative @CalledByNative
private static ContextMenuParams create(int mediaType, String linkUrl, String linkText, private static ContextMenuParams create(int mediaType, String linkUrl, String linkText,
String unfilteredLinkUrl, String srcUrl, String selectionText, boolean isEditable) { String unfilteredLinkUrl, String srcUrl, String selectionText, boolean isEditable,
String sanitizedReferrer, int referrerPolicy) {
Referrer referrer = TextUtils.isEmpty(sanitizedReferrer) ?
null : new Referrer(sanitizedReferrer, referrerPolicy);
return new ContextMenuParams(mediaType, linkUrl, linkText, unfilteredLinkUrl, srcUrl, return new ContextMenuParams(mediaType, linkUrl, linkText, unfilteredLinkUrl, srcUrl,
selectionText, isEditable); selectionText, isEditable, referrer);
} }
@CalledByNative @CalledByNative
private void addCustomItem(String label, int action) { private void addCustomItem(String label, int action) {
mCustomMenuItems.add(new CustomMenuItem(label, action)); mCustomMenuItems.add(new CustomMenuItem(label, action));
} }
} }
\ No newline at end of file
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.contextmenu; package org.chromium.chrome.browser.contextmenu;
import org.chromium.content_public.Referrer;
/** /**
* An empty implementation of {@link ChromeContextMenuItemDelegate} to make overriding subsets of * An empty implementation of {@link ChromeContextMenuItemDelegate} to make overriding subsets of
* the delegate methods easier. * the delegate methods easier.
...@@ -30,7 +32,7 @@ public class EmptyChromeContextMenuItemDelegate implements ChromeContextMenuItem ...@@ -30,7 +32,7 @@ public class EmptyChromeContextMenuItemDelegate implements ChromeContextMenuItem
} }
@Override @Override
public void onOpenInNewTab(String url) { public void onOpenInNewTab(String url, Referrer referrer) {
} }
@Override @Override
...@@ -38,11 +40,11 @@ public class EmptyChromeContextMenuItemDelegate implements ChromeContextMenuItem ...@@ -38,11 +40,11 @@ public class EmptyChromeContextMenuItemDelegate implements ChromeContextMenuItem
} }
@Override @Override
public void onOpenImageUrl(String url) { public void onOpenImageUrl(String url, Referrer referrer) {
} }
@Override @Override
public void onOpenImageInNewTab(String url) { public void onOpenImageInNewTab(String url, Referrer referrer) {
} }
@Override @Override
...@@ -56,4 +58,4 @@ public class EmptyChromeContextMenuItemDelegate implements ChromeContextMenuItem ...@@ -56,4 +58,4 @@ public class EmptyChromeContextMenuItemDelegate implements ChromeContextMenuItem
@Override @Override
public void onSearchByImageInNewTab() { public void onSearchByImageInNewTab() {
} }
} }
\ No newline at end of file
...@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.infobar.AutoLoginProcessor; ...@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.infobar.AutoLoginProcessor;
import org.chromium.content.browser.ContentView; import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.ContentViewClient; import org.chromium.content.browser.ContentViewClient;
import org.chromium.content.browser.LoadUrlParams; import org.chromium.content.browser.LoadUrlParams;
import org.chromium.content_public.Referrer;
import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid;
/** /**
...@@ -102,7 +103,7 @@ public class TestShellTab extends Tab { ...@@ -102,7 +103,7 @@ public class TestShellTab extends Tab {
protected ContextMenuPopulator createContextMenuPopulator() { protected ContextMenuPopulator createContextMenuPopulator() {
return new ChromeContextMenuPopulator(new TabChromeContextMenuItemDelegate() { return new ChromeContextMenuPopulator(new TabChromeContextMenuItemDelegate() {
@Override @Override
public void onOpenImageUrl(String url) { public void onOpenImageUrl(String url, Referrer referrer) {
loadUrlWithSanitization(url); loadUrlWithSanitization(url);
} }
}); });
......
...@@ -66,6 +66,9 @@ void ContextMenuHelper::SetPopulator(jobject jpopulator) { ...@@ -66,6 +66,9 @@ void ContextMenuHelper::SetPopulator(jobject jpopulator) {
base::android::ScopedJavaLocalRef<jobject> base::android::ScopedJavaLocalRef<jobject>
ContextMenuHelper::CreateJavaContextMenuParams( ContextMenuHelper::CreateJavaContextMenuParams(
const content::ContextMenuParams& params) { const content::ContextMenuParams& params) {
GURL sanitizedReferrer = SanitizeReferrer(
params.frame_url.is_empty() ? params.page_url : params.frame_url);
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> jmenu_info = base::android::ScopedJavaLocalRef<jobject> jmenu_info =
ContextMenuParamsAndroid::Java_ContextMenuParams_create( ContextMenuParamsAndroid::Java_ContextMenuParams_create(
...@@ -76,7 +79,9 @@ ContextMenuHelper::CreateJavaContextMenuParams( ...@@ -76,7 +79,9 @@ ContextMenuHelper::CreateJavaContextMenuParams(
ConvertUTF8ToJavaString(env, params.unfiltered_link_url.spec()).obj(), ConvertUTF8ToJavaString(env, params.unfiltered_link_url.spec()).obj(),
ConvertUTF8ToJavaString(env, params.src_url.spec()).obj(), ConvertUTF8ToJavaString(env, params.src_url.spec()).obj(),
ConvertUTF16ToJavaString(env, params.selection_text).obj(), ConvertUTF16ToJavaString(env, params.selection_text).obj(),
params.is_editable); params.is_editable,
ConvertUTF8ToJavaString(env, sanitizedReferrer.spec()).obj(),
params.referrer_policy);
std::vector<content::MenuItem>::const_iterator i; std::vector<content::MenuItem>::const_iterator i;
for (i = params.custom_items.begin(); i != params.custom_items.end(); ++i) { for (i = params.custom_items.begin(); i != params.custom_items.end(); ++i) {
...@@ -90,6 +95,19 @@ ContextMenuHelper::CreateJavaContextMenuParams( ...@@ -90,6 +95,19 @@ ContextMenuHelper::CreateJavaContextMenuParams(
return jmenu_info; return jmenu_info;
} }
GURL ContextMenuHelper::SanitizeReferrer(const GURL& referring_url) {
// This mirrors sanitization done on Desktop in RenderViewContextMenu.
if (referring_url.is_valid() && (referring_url.has_ref() ||
referring_url.has_username() || referring_url.has_password())) {
GURL::Replacements referrer_mods;
referrer_mods.ClearRef();
referrer_mods.ClearUsername();
referrer_mods.ClearPassword();
return referring_url.ReplaceComponents(referrer_mods);
}
return referring_url;
}
void ContextMenuHelper::OnCustomItemSelected(JNIEnv* env, void ContextMenuHelper::OnCustomItemSelected(JNIEnv* env,
jobject obj, jobject obj,
jint action) { jint action) {
......
...@@ -41,6 +41,9 @@ class ContextMenuHelper ...@@ -41,6 +41,9 @@ class ContextMenuHelper
static base::android::ScopedJavaLocalRef<jobject> CreateJavaContextMenuParams( static base::android::ScopedJavaLocalRef<jobject> CreateJavaContextMenuParams(
const content::ContextMenuParams& params); const content::ContextMenuParams& params);
// Strips the referring url of the username, password and ref fields.
static GURL SanitizeReferrer(const GURL& referrer);
base::android::ScopedJavaGlobalRef<jobject> java_obj_; base::android::ScopedJavaGlobalRef<jobject> java_obj_;
content::WebContents* web_contents_; content::WebContents* web_contents_;
......
...@@ -33,6 +33,16 @@ public final class TestHttpServerClient { ...@@ -33,6 +33,16 @@ public final class TestHttpServerClient {
return "http://localhost:" + SERVER_PORT + "/" + path; return "http://localhost:" + SERVER_PORT + "/" + path;
} }
/**
* Construct a URL for loading a test data file with HTTP authentication fields.
*
* @param path path relative to the document root.
* @return an HTTP url.
*/
public static String getUrl(String path, String username, String password) {
return "http://" + username + ":" + password + "@localhost:" + SERVER_PORT + "/" + path;
}
/** /**
* Establishes a connection with the test server at default URL and verifies that it is running. * Establishes a connection with the test server at default URL and verifies that it is running.
*/ */
......
...@@ -6,6 +6,7 @@ package org.chromium.content.browser; ...@@ -6,6 +6,7 @@ package org.chromium.content.browser;
import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace; import org.chromium.base.JNINamespace;
import org.chromium.content_public.Referrer;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
...@@ -37,9 +38,10 @@ public class LoadUrlParams { ...@@ -37,9 +38,10 @@ public class LoadUrlParams {
String mUrl; String mUrl;
int mLoadUrlType; int mLoadUrlType;
int mTransitionType; int mTransitionType;
int mUaOverrideOption; Referrer mReferrer;
private Map<String, String> mExtraHeaders; private Map<String, String> mExtraHeaders;
private String mVerbatimHeaders; private String mVerbatimHeaders;
int mUaOverrideOption;
byte[] mPostData; byte[] mPostData;
String mBaseUrlForDataUrl; String mBaseUrlForDataUrl;
String mVirtualUrlForDataUrl; String mVirtualUrlForDataUrl;
...@@ -222,11 +224,17 @@ public class LoadUrlParams { ...@@ -222,11 +224,17 @@ public class LoadUrlParams {
} }
/** /**
* Set user agent override option of this load. Defaults to UA_OVERRIDE_INHERIT. * @return the referrer of this load
* @param uaOption One of UA_OVERRIDE static constants above.
*/ */
public void setOverrideUserAgent(int uaOption) { public void setReferrer(Referrer referrer) {
mUaOverrideOption = uaOption; mReferrer = referrer;
}
/**
* Sets the referrer of this load.
*/
public Referrer getReferrer() {
return mReferrer;
} }
/** /**
...@@ -291,6 +299,14 @@ public class LoadUrlParams { ...@@ -291,6 +299,14 @@ public class LoadUrlParams {
return mVerbatimHeaders; return mVerbatimHeaders;
} }
/**
* Set user agent override option of this load. Defaults to UA_OVERRIDE_INHERIT.
* @param uaOption One of UA_OVERRIDE static constants above.
*/
public void setOverrideUserAgent(int uaOption) {
mUaOverrideOption = uaOption;
}
/** /**
* Set the post data of this load. This field is ignored unless load type is * Set the post data of this load. This field is ignored unless load type is
* LOAD_TYPE_BROWSER_INITIATED_HTTP_POST. * LOAD_TYPE_BROWSER_INITIATED_HTTP_POST.
......
// Copyright 2014 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.content_public;
/**
* Container that holds together a referrer URL along with the referrer policy set on the
* originating frame. This corresponds to native content/public/common/referrer.h.
*/
public class Referrer {
private final String mUrl;
private final int mPolicy;
public Referrer(String url, int policy) {
mUrl = url;
mPolicy = policy;
}
public String getUrl() {
return mUrl;
}
public int getPolicy() {
return mPolicy;
}
}
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