Commit 9ff677af authored by Olivier Robin's avatar Olivier Robin Committed by Chromium LUCI CQ

QR code scanner: ignore non HTTP(s) URLs

If the result is a valid URL with a not HTTP(s) scheme, add
quotes so it triggers a search instead of a load.

Bug: 1153445
Change-Id: I5d9d79feafc6d2df756da5a9d35c434ce22393f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2611735
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarStepan Khapugin <stkhapugin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841011}
parent 61d434d1
......@@ -90,10 +90,12 @@ source_set("eg_app_support+eg2") {
deps = [
":qr_scanner",
"//base",
"//components/search_engines",
"//components/version_info",
"//ios/chrome/app:app_internal",
"//ios/chrome/app/strings",
"//ios/chrome/browser/main",
"//ios/chrome/browser/search_engines",
"//ios/chrome/browser/ui/icons",
"//ios/chrome/browser/ui/location_bar",
"//ios/chrome/browser/ui/scanner",
......
......@@ -30,13 +30,13 @@
// should not be called directly.
+ (id)cameraControllerSwizzleBlockWithMock:(id)cameraControllerMock;
// Returns the block to use for swizzling the LocationBarCoordinator
// loadGURLFromLocationBarBlock:transition: method to load |searchURL| instead
// of the generated search URL.
// This block is only used for swizzling, which is why its type is opaque. It
// should not be called directly.
+ (id)locationBarCoordinatorLoadGURLFromLocationBarSwizzleBlockForSearchURL:
(NSURL*)searchURL;
#pragma mark Search engine override
// Overrides the default search engine with the |templateURL|.
+ (void)overrideSearchEngine:(NSString*)templateURL;
// Restored the Google default search engine.
+ (void)resetSearchEngine;
#pragma mark Mocking and Expectations
......
......@@ -7,9 +7,11 @@
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/search_engines/template_url_service.h"
#include "components/version_info/version_info.h"
#import "ios/chrome/app/main_controller.h"
#include "ios/chrome/browser/main/browser.h"
#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
#include "ios/chrome/browser/ui/icons/chrome_icon.h"
#import "ios/chrome/browser/ui/location_bar/location_bar_coordinator.h"
#import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h"
......@@ -23,6 +25,7 @@
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/testing/nserror_util.h"
#import "net/base/mac/url_conversions.h"
#include "net/base/mac/url_conversions.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "ui/base/l10n/l10n_util.h"
#import "ui/base/l10n/l10n_util_mac.h"
......@@ -56,20 +59,31 @@ using scanner::CameraState;
return swizzleCameraControllerBlock;
}
+ (id)locationBarCoordinatorLoadGURLFromLocationBarSwizzleBlockForSearchURL:
(NSURL*)searchURL {
GURL searchGURL = net::GURLWithNSURL(searchURL);
auto loadGURLFromLocationBarBlock = ^void(
LocationBarCoordinator* self, TemplateURLRef::PostContent* postContent,
const GURL& url, ui::PageTransition transition) {
web::NavigationManager::WebLoadParams params(searchGURL);
params.transition_type = transition;
UrlLoadingBrowserAgent::FromBrowser(self.browser)
->Load(UrlLoadParams::InCurrentTab(params));
[self cancelOmniboxEdit];
};
#pragma mark Search engine override
+ (void)overrideSearchEngine:(NSString*)templateURL {
TemplateURLData data;
data.SetShortName(base::ASCIIToUTF16("testSearchEngine"));
data.SetKeyword(base::ASCIIToUTF16("testSearchEngine"));
GURL searchableURL(base::SysNSStringToUTF8(templateURL));
data.SetURL(searchableURL.possibly_invalid_spec());
data.favicon_url = TemplateURL::GenerateFaviconURL(searchableURL);
data.last_visited = base::Time::Now();
TemplateURLService* service =
ios::TemplateURLServiceFactory::GetForBrowserState(
chrome_test_util::GetOriginalBrowserState());
TemplateURL* url = service->Add(std::make_unique<TemplateURL>(data));
service->SetUserSelectedDefaultSearchProvider(url);
}
+ (void)resetSearchEngine {
TemplateURLService* service =
ios::TemplateURLServiceFactory::GetForBrowserState(
chrome_test_util::GetOriginalBrowserState());
return loadGURLFromLocationBarBlock;
TemplateURL* templateURL = service->GetTemplateURLForHost("google.com");
service->SetUserSelectedDefaultSearchProvider(templateURL);
}
#pragma mark Mocking and Expectations
......
......@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/sys_string_conversions.h"
#include "ios/chrome/browser/ui/commands/load_query_commands.h"
#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_camera_controller.h"
#include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view.h"
......@@ -16,6 +17,7 @@
#include "ios/chrome/browser/ui/scanner/scanner_view.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -82,6 +84,13 @@ using base::UserMetricsAction;
#pragma mark - QRScannerCameraControllerDelegate
- (void)receiveQRScannerResult:(NSString*)result loadImmediately:(BOOL)load {
GURL url = GURL(base::SysNSStringToUTF8(result));
if (url.is_valid() && !url.SchemeIsHTTPOrHTTPS()) {
// Only HTTP(S) URLs are supported.
// For other URLs, add quotes so they are considered as search terms instead
// of URLs.
result = [NSString stringWithFormat:@"\"%@\"", result];
}
if ([self isVoiceOverActive]) {
// Post a notification announcing that a code was scanned. QR scanner will
// be dismissed when the UIAccessibilityAnnouncementDidFinishNotification is
......
......@@ -17,6 +17,7 @@
#include "ios/chrome/test/earl_grey/earl_grey_scoped_block_swizzler.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "net/base/mac/url_conversions.h"
#include "net/base/url_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
......@@ -66,14 +67,18 @@ namespace {
char kTestURL[] = "/testurl";
char kTestURLResponse[] = "Test URL page";
char kTestQuery[] = "testquery";
char kTestQueryURL[] = "/searchurl/testquery";
char kTestQueryResponse[] = "Test query page";
char kTestURLEdited[] = "/testuredited";
char kTestURLEditedResponse[] = "Test URL edited page";
char kTestQueryEditedURL[] = "/searchurl/testqueredited";
char kTestQueryEditedResponse[] = "Test query edited page";
char kTestQuery[] = "testquery";
char kTestQueryURL[] = "/search";
char kTestQueryURLParams[] = "?q={searchTerms}";
char kTestQueryResponse[] = "Query: testquery";
char kTestQueryEditedResponse[] = "Query: testqueredited";
char kTestDataURL[] = "data:dataURL";
char kTestSanitizedDataURL[] = "\"data:dataURL\"";
char kTestDataURLResponse[] = "Query: \"data:dataURL\"";
// The GREYCondition timeout used for calls to waitWithTimeout:pollInterval:.
CFTimeInterval kGREYConditionTimeout = 5;
......@@ -168,19 +173,24 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
char* body_content = nullptr;
const char* body_content = nullptr;
if (base::StartsWith(request.relative_url, kTestURL,
base::CompareCase::SENSITIVE)) {
body_content = kTestURLResponse;
} else if (base::StartsWith(request.relative_url, kTestQueryURL,
base::CompareCase::SENSITIVE)) {
body_content = kTestQueryResponse;
} else if (base::StartsWith(request.relative_url, kTestURLEdited,
base::CompareCase::SENSITIVE)) {
body_content = kTestURLEditedResponse;
} else if (base::StartsWith(request.relative_url, kTestQueryEditedURL,
} else if (base::StartsWith(request.relative_url, kTestQueryURL,
base::CompareCase::SENSITIVE)) {
body_content = kTestQueryEditedResponse;
GURL url = request.GetURL();
std::string query;
bool found = net::GetValueForKeyInQuery(url, "q", &query);
if (found) {
std::string content = "Query: " + query;
body_content = content.c_str();
} else {
body_content = "No query";
}
} else {
return nullptr;
}
......@@ -201,7 +211,6 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
GURL _testURL;
GURL _testURLEdited;
GURL _testQuery;
GURL _testQueryEdited;
}
@end
......@@ -209,10 +218,6 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
@implementation QRScannerViewControllerTestCase {
// A swizzler for the CameraController method cameraControllerWithDelegate:.
std::unique_ptr<EarlGreyScopedBlockSwizzler> _camera_controller_swizzler;
// A swizzler for the LocationBarCoordinator method
// loadGURLFromLocationBar:transition:.
std::unique_ptr<EarlGreyScopedBlockSwizzler>
_load_GURL_from_location_bar_swizzler;
}
- (void)setUp {
......@@ -225,12 +230,15 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
_testURL = self.testServer->GetURL(kTestURL);
_testURLEdited = self.testServer->GetURL(kTestURLEdited);
_testQuery = self.testServer->GetURL(kTestQueryURL);
_testQueryEdited = self.testServer->GetURL(kTestQueryEditedURL);
NSString* templateURL =
base::SysUTF8ToNSString(_testQuery.spec() + kTestQueryURLParams);
[QRScannerAppInterface overrideSearchEngine:templateURL];
}
- (void)tearDown {
[super tearDown];
_load_GURL_from_location_bar_swizzler.reset();
[QRScannerAppInterface resetSearchEngine];
_camera_controller_swizzler.reset();
}
......@@ -364,22 +372,6 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
swizzleCameraControllerBlock);
}
// Swizzles the LocationBarCoordinator loadGURLFromLocationBarBlock:transition:
// method to load |searchURL| instead of the generated search URL.
- (void)swizzleLocationBarCoordinatorLoadGURLFromLocationBar:
(const GURL&)replacementURL {
NSURL* replacementNSURL = net::NSURLWithGURL(replacementURL);
id loadGURLFromLocationBarBlock = [QRScannerAppInterface
locationBarCoordinatorLoadGURLFromLocationBarSwizzleBlockForSearchURL:
replacementNSURL];
_load_GURL_from_location_bar_swizzler =
std::make_unique<EarlGreyScopedBlockSwizzler>(
@"LocationBarCoordinator",
@"loadGURLFromLocationBar:postContent:transition:disposition:",
loadGURLFromLocationBarBlock);
}
// Checks that the modal presented by |viewController| is of class |klass| and
// waits for the modal's view to load.
- (void)waitForModalOfClass:(NSString*)klassString
......@@ -684,6 +676,7 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
// which can be appended to the response in the omnibox before the page is
// loaded.
- (void)doTestReceivingResult:(std::string)result
sanitizedResult:(std::string)sanitizedResult
response:(std::string)response
edit:(NSString*)editString {
id cameraControllerMock =
......@@ -707,11 +700,11 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
[cameraControllerMock verify];
// Optionally edit the text in the omnibox before pressing return.
[self assertOmniboxIsVisibleWithText:result];
[self assertOmniboxIsVisibleWithText:sanitizedResult];
if (editString != nil) {
EditOmniboxTextAndTapKeyboardReturn(result, editString);
EditOmniboxTextAndTapKeyboardReturn(sanitizedResult, editString);
} else {
TapKeyboardReturnKeyInOmniboxWithText(result);
TapKeyboardReturnKeyInOmniboxWithText(sanitizedResult);
}
[ChromeEarlGrey waitForWebStateContainingText:response];
......@@ -724,6 +717,15 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
GREYAssertNil(error, error.localizedDescription);
}
- (void)doTestReceivingResult:(std::string)result
response:(std::string)response
edit:(NSString*)editString {
[self doTestReceivingResult:result
sanitizedResult:result
response:response
edit:editString];
}
// Test that the correct page is loaded if the scanner result is a URL which is
// then manually edited when VoiceOver is enabled.
- (void)testReceivingQRScannerURLResultWithVoiceOver {
......@@ -784,7 +786,6 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
// Test that the correct page is loaded if the scanner result is a search query.
- (void)testReceivingQRScannerSearchQueryResult {
[self swizzleLocationBarCoordinatorLoadGURLFromLocationBar:_testQuery];
[self doTestReceivingResult:kTestQuery response:kTestQueryResponse edit:nil];
}
......@@ -797,10 +798,18 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
}
[self swizzleLocationBarCoordinatorLoadGURLFromLocationBar:_testQueryEdited];
[self doTestReceivingResult:kTestQuery
response:kTestQueryEditedResponse
edit:@"\bedited"];
}
// Test that the correct page is loaded if the scanner result is a not supported
// URL.
- (void)testReceivingQRScannerLoadDataResult {
[self doTestReceivingResult:kTestDataURL
sanitizedResult:kTestSanitizedDataURL
response:kTestDataURLResponse
edit:nil];
}
@end
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