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 {
* @param tab The Tab currently being accessed.
* @return The X-Geo header string or null.
*/
@Nullable
public static String getGeoHeader(String url, Tab tab) {
// TODO(lbargu): Refactor and simplify flow.
Profile profile = Profile.fromWebContents(tab.getWebContents());
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;
VisibleNetworks visibleNetworksToAttach = null;
long locationAge = Long.MAX_VALUE;
......@@ -328,7 +371,7 @@ public class GeolocationHeader {
locationToAttach != null, headerState);
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.
recordLocationAgeHistogram(locationSource, locationAge);
long duration = sFirstLocationTime == Long.MAX_VALUE
......@@ -356,6 +399,7 @@ public class GeolocationHeader {
return header.toString();
}
@SuppressWarnings("unused")
@CalledByNative
static boolean hasGeolocationPermission() {
if (sUseAppPermissionGrantedForTesting) return sAppPermissionGrantedForTesting;
......@@ -390,8 +434,9 @@ public class GeolocationHeader {
return sAppPermissionGrantedForTesting ? Permission.GRANTED : Permission.BLOCKED;
}
if (hasGeolocationPermission()) return Permission.GRANTED;
return tab.getWindowAndroid().canRequestPermission(
Manifest.permission.ACCESS_COARSE_LOCATION)
return (tab != null
&& tab.getWindowAndroid().canRequestPermission(
Manifest.permission.ACCESS_COARSE_LOCATION))
? Permission.PROMPT
: Permission.BLOCKED;
}
......
......@@ -2798,6 +2798,8 @@ static_library("browser") {
"android/ntp/recent_tabs_page_prefs.h",
"android/omnibox/autocomplete_controller_android.cc",
"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.h",
"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 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.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/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_permissions_service.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
......@@ -152,8 +152,7 @@ void SearchGeolocationDisclosureTabHelper::MaybeShowDisclosureForValidUrl(
}
// Check that the Chrome app has geolocation permission.
JNIEnv* env = base::android::AttachCurrentThread();
if (!Java_GeolocationHeader_hasGeolocationPermission(env))
if (!HasGeolocationPermission())
return;
// All good, let's show the disclosure and increment the shown count.
......
......@@ -6,6 +6,7 @@
#include <vector>
#include "build/build_config.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
......@@ -30,6 +31,10 @@
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/origin.h"
#if defined(OS_ANDROID)
#include "chrome/browser/android/omnibox/geolocation_header.h"
#endif // defined(OS_ANDROID)
namespace {
// A custom URLLoaderThrottle delegate that is very sensitive. Anything that
......@@ -174,6 +179,14 @@ bool BaseSearchPrefetchRequest::StartPrefetchRequest(Profile* profile) {
profile->GetClientHintsControllerDelegate(),
/*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
// 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
......
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