Commit 6c2905dd authored by Ryan Sturm's avatar Ryan Sturm Committed by Chromium LUCI CQ

Adding x-geo header to Search Prefetch on Android

This CL exposes the Java API to add the x-geo (geolocation) header based
on URL and Profile. Because prefetch isn't visible to the user or tied
to a tab, this exposes a version of the Java API that does not use Tab
to determine if the permission can be granted.

I added a dedicated bridge file on native to deal with unused build
errors when including the JNI header in two different native cc files.

Bug: 1138648
Change-Id: Ib66469f82a6b2737a4679ea3a911051ad33a16c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2559228
Commit-Queue: Ryan Sturm <ryansturm@chromium.org>
Reviewed-by: default avatarRobert Ogden <robertogden@chromium.org>
Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Cr-Commit-Position: refs/heads/master@{#837829}
parent 65b21d71
...@@ -283,11 +283,54 @@ public class GeolocationHeader { ...@@ -283,11 +283,54 @@ public class GeolocationHeader {
* @param tab The Tab currently being accessed. * @param tab The Tab currently being accessed.
* @return The X-Geo header string or null. * @return The X-Geo header string or null.
*/ */
@Nullable
public static String getGeoHeader(String url, Tab tab) { public static String getGeoHeader(String url, Tab tab) {
// TODO(lbargu): Refactor and simplify flow.
Profile profile = Profile.fromWebContents(tab.getWebContents()); Profile profile = Profile.fromWebContents(tab.getWebContents());
if (profile == null) return null; if (profile == null) return null;
return getGeoHeader(url, profile, tab);
}
/**
* Returns an X-Geo HTTP header string if:
* 1. The current mode is not incognito.
* 2. The url is a google search URL (e.g. www.google.co.uk/search?q=cars), and
* 3. The user has not disabled sharing location with this url, and
* 4. There is a valid and recent location available.
*
* Returns null otherwise. This will never prompt for location access.
*
* @param url The URL of the request with which this header will be sent.
* @param profile The Tab currently being accessed.
* @return The X-Geo header string or null.
*/
@SuppressWarnings("unused")
@CalledByNative
@Nullable
public static String getGeoHeader(String url, Profile profile) {
if (profile == null) return null;
Tab tab = null;
return getGeoHeader(url, profile, tab);
}
/**
* Returns an X-Geo HTTP header string if:
* 1. The current mode is not incognito.
* 2. The url is a google search URL (e.g. www.google.co.uk/search?q=cars), and
* 3. The user has not disabled sharing location with this url, and
* 4. There is a valid and recent location available.
*
* Returns null otherwise.
*
* @param url The URL of the request with which this header will be sent.
* @param profile The user profile being accessed.
* @param tab The Tab currently being accessed. Can be null, in which case, location permissions
* will never prompt.
* @return The X-Geo header string or null.
*/
@Nullable
private static String getGeoHeader(String url, Profile profile, Tab tab) {
Location locationToAttach = null; Location locationToAttach = null;
VisibleNetworks visibleNetworksToAttach = null; VisibleNetworks visibleNetworksToAttach = null;
long locationAge = Long.MAX_VALUE; long locationAge = Long.MAX_VALUE;
...@@ -328,7 +371,7 @@ public class GeolocationHeader { ...@@ -328,7 +371,7 @@ public class GeolocationHeader {
locationToAttach != null, headerState); locationToAttach != null, headerState);
if (locationSource != LocationSource.LOCATION_OFF && appPermission != Permission.BLOCKED if (locationSource != LocationSource.LOCATION_OFF && appPermission != Permission.BLOCKED
&& domainPermission != Permission.BLOCKED && !tab.isIncognito()) { && domainPermission != Permission.BLOCKED && !profile.isOffTheRecord()) {
// Record the Location Age with a histogram. // Record the Location Age with a histogram.
recordLocationAgeHistogram(locationSource, locationAge); recordLocationAgeHistogram(locationSource, locationAge);
long duration = sFirstLocationTime == Long.MAX_VALUE long duration = sFirstLocationTime == Long.MAX_VALUE
...@@ -356,6 +399,7 @@ public class GeolocationHeader { ...@@ -356,6 +399,7 @@ public class GeolocationHeader {
return header.toString(); return header.toString();
} }
@SuppressWarnings("unused")
@CalledByNative @CalledByNative
static boolean hasGeolocationPermission() { static boolean hasGeolocationPermission() {
if (sUseAppPermissionGrantedForTesting) return sAppPermissionGrantedForTesting; if (sUseAppPermissionGrantedForTesting) return sAppPermissionGrantedForTesting;
...@@ -390,8 +434,9 @@ public class GeolocationHeader { ...@@ -390,8 +434,9 @@ public class GeolocationHeader {
return sAppPermissionGrantedForTesting ? Permission.GRANTED : Permission.BLOCKED; return sAppPermissionGrantedForTesting ? Permission.GRANTED : Permission.BLOCKED;
} }
if (hasGeolocationPermission()) return Permission.GRANTED; if (hasGeolocationPermission()) return Permission.GRANTED;
return tab.getWindowAndroid().canRequestPermission( return (tab != null
Manifest.permission.ACCESS_COARSE_LOCATION) && tab.getWindowAndroid().canRequestPermission(
Manifest.permission.ACCESS_COARSE_LOCATION))
? Permission.PROMPT ? Permission.PROMPT
: Permission.BLOCKED; : Permission.BLOCKED;
} }
......
...@@ -2798,6 +2798,8 @@ static_library("browser") { ...@@ -2798,6 +2798,8 @@ static_library("browser") {
"android/ntp/recent_tabs_page_prefs.h", "android/ntp/recent_tabs_page_prefs.h",
"android/omnibox/autocomplete_controller_android.cc", "android/omnibox/autocomplete_controller_android.cc",
"android/omnibox/autocomplete_controller_android.h", "android/omnibox/autocomplete_controller_android.h",
"android/omnibox/geolocation_header.cc",
"android/omnibox/geolocation_header.h",
"android/omnibox/omnibox_prerender.cc", "android/omnibox/omnibox_prerender.cc",
"android/omnibox/omnibox_prerender.h", "android/omnibox/omnibox_prerender.h",
"android/oom_intervention/near_oom_monitor.cc", "android/oom_intervention/near_oom_monitor.cc",
......
// Copyright 2020 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.
#include "chrome/browser/android/omnibox/geolocation_header.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "chrome/android/chrome_jni_headers/GeolocationHeader_jni.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "url/android/gurl_android.h"
#include "url/gurl.h"
bool HasGeolocationPermission() {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_GeolocationHeader_hasGeolocationPermission(env);
}
base::Optional<std::string> GetGeolocationHeaderIfAllowed(const GURL& url,
Profile* profile) {
JNIEnv* env = base::android::AttachCurrentThread();
ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
DCHECK(profile_android);
base::android::ScopedJavaLocalRef<jobject> j_profile_android =
profile_android->GetJavaObject();
DCHECK(!j_profile_android.is_null());
base::android::ScopedJavaLocalRef<jstring> geo_header =
Java_GeolocationHeader_getGeoHeader(
env, base::android::ConvertUTF8ToJavaString(env, url.spec()),
j_profile_android);
if (!geo_header)
return base::nullopt;
return base::android::ConvertJavaStringToUTF8(env, geo_header);
}
// Copyright 2020 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.
#ifndef CHROME_BROWSER_ANDROID_OMNIBOX_GEOLOCATION_HEADER_H_
#define CHROME_BROWSER_ANDROID_OMNIBOX_GEOLOCATION_HEADER_H_
#include <string>
#include "base/optional.h"
class Profile;
class GURL;
// Whether the user has given Chrome location permission.
bool HasGeolocationPermission();
// Gives the full string of the entire Geolocation header if it can be added for
// a request to |url|. Does not prompt for permission.
base::Optional<std::string> GetGeolocationHeaderIfAllowed(const GURL& url,
Profile* profile);
#endif // CHROME_BROWSER_ANDROID_OMNIBOX_GEOLOCATION_HEADER_H_
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/android/chrome_jni_headers/GeolocationHeader_jni.h"
#include "chrome/android/chrome_jni_headers/SearchGeolocationDisclosureTabHelper_jni.h" #include "chrome/android/chrome_jni_headers/SearchGeolocationDisclosureTabHelper_jni.h"
#include "chrome/browser/android/omnibox/geolocation_header.h"
#include "chrome/browser/android/search_permissions/search_geolocation_disclosure_infobar_delegate.h" #include "chrome/browser/android/search_permissions/search_geolocation_disclosure_infobar_delegate.h"
#include "chrome/browser/android/search_permissions/search_permissions_service.h" #include "chrome/browser/android/search_permissions/search_permissions_service.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
...@@ -152,8 +152,7 @@ void SearchGeolocationDisclosureTabHelper::MaybeShowDisclosureForValidUrl( ...@@ -152,8 +152,7 @@ void SearchGeolocationDisclosureTabHelper::MaybeShowDisclosureForValidUrl(
} }
// Check that the Chrome app has geolocation permission. // Check that the Chrome app has geolocation permission.
JNIEnv* env = base::android::AttachCurrentThread(); if (!HasGeolocationPermission())
if (!Java_GeolocationHeader_hasGeolocationPermission(env))
return; return;
// All good, let's show the disclosure and increment the shown count. // All good, let's show the disclosure and increment the shown count.
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "build/build_config.h"
#include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/search_engines/template_url_service_factory.h"
...@@ -30,6 +31,10 @@ ...@@ -30,6 +31,10 @@
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/origin.h" #include "url/origin.h"
#if defined(OS_ANDROID)
#include "chrome/browser/android/omnibox/geolocation_header.h"
#endif // defined(OS_ANDROID)
namespace { namespace {
// A custom URLLoaderThrottle delegate that is very sensitive. Anything that // A custom URLLoaderThrottle delegate that is very sensitive. Anything that
...@@ -174,6 +179,14 @@ bool BaseSearchPrefetchRequest::StartPrefetchRequest(Profile* profile) { ...@@ -174,6 +179,14 @@ bool BaseSearchPrefetchRequest::StartPrefetchRequest(Profile* profile) {
profile->GetClientHintsControllerDelegate(), profile->GetClientHintsControllerDelegate(),
/*is_ua_override_on=*/false, js_enabled); /*is_ua_override_on=*/false, js_enabled);
#if defined(OS_ANDROID)
base::Optional<std::string> geo_header =
GetGeolocationHeaderIfAllowed(resource_request->url, profile);
if (geo_header) {
resource_request->headers.AddHeaderFromString(geo_header.value());
}
#endif // defined(OS_ANDROID)
// Before sending out the request, allow throttles to modify the request (not // Before sending out the request, allow throttles to modify the request (not
// the URL). The rest of the URL Loader throttle calls are captured in the // the URL). The rest of the URL Loader throttle calls are captured in the
// navigation stack. Headers can be added by throttles at this point, which we // navigation stack. Headers can be added by throttles at this point, which we
......
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