Commit df887034 authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

[iOS] Fix UserAgent restored for preloaded page

When the page is preloaded, a session restoration is done.
But the "visible" page isn't loaded as it would in a normal session
restoration.
This CL makes sure that this page gets the correct UA.

Bug: 1100852
Change-Id: Ia666dd17e512c8d9c7e84e750722dae90f56ca14
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2279757
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarSylvain Defresne <sdefresne@chromium.org>
Reviewed-by: default avatarAli Juma <ajuma@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791785}
parent 1001c66b
...@@ -89,9 +89,12 @@ source_set("eg2_tests") { ...@@ -89,9 +89,12 @@ source_set("eg2_tests") {
testonly = true testonly = true
sources = [ "prerender_egtest.mm" ] sources = [ "prerender_egtest.mm" ]
deps = [ deps = [
"//components/version_info",
"//ios/chrome/browser/ui/popup_menu:constants",
"//ios/chrome/test/earl_grey:eg_test_support+eg2", "//ios/chrome/test/earl_grey:eg_test_support+eg2",
"//ios/testing/earl_grey:eg_test_support+eg2", "//ios/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib", "//ios/third_party/earl_grey2:test_lib",
"//ios/web/common:user_agent",
"//net:test_support", "//net:test_support",
] ]
frameworks = [ "UIKit.framework" ] frameworks = [ "UIKit.framework" ]
......
...@@ -10,9 +10,13 @@ ...@@ -10,9 +10,13 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h" #import "base/test/ios/wait_util.h"
#include "components/version_info/version_info.h"
#import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h"
#include "ios/web/common/user_agent.h"
#include "net/test/embedded_test_server/embedded_test_server.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_request.h"
#include "net/test/embedded_test_server/http_response.h" #include "net/test/embedded_test_server/http_response.h"
...@@ -25,56 +29,87 @@ using base::test::ios::WaitUntilConditionOrTimeout; ...@@ -25,56 +29,87 @@ using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kWaitForPageLoadTimeout; using base::test::ios::kWaitForPageLoadTimeout;
namespace { namespace {
const char kPageURL[] = "/test-page.html"; const char kPageURL[] = "/test-page.html";
const char kUserAgentPageURL[] = "/user-agent-test-page.html";
const char kPageTitle[] = "Page title!"; const char kPageTitle[] = "Page title!";
const char kPageLoadedString[] = "Page loaded!"; const char kPageLoadedString[] = "Page loaded!";
const char kMobileSiteLabel[] = "Mobile";
const char kDesktopSiteLabel[] = "Desktop";
// Provides responses for redirect and changed window location URLs. // Provides responses for redirect and changed window location URLs.
std::unique_ptr<net::test_server::HttpResponse> StandardResponse( std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
int* counter, int* counter,
const net::test_server::HttpRequest& request) { const net::test_server::HttpRequest& request) {
if (request.relative_url != kPageURL) {
return nullptr;
}
std::unique_ptr<net::test_server::BasicHttpResponse> http_response = std::unique_ptr<net::test_server::BasicHttpResponse> http_response =
std::make_unique<net::test_server::BasicHttpResponse>(); std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK); http_response->set_code(net::HTTP_OK);
http_response->set_content("<html><head><title>" + std::string(kPageTitle) + if (request.relative_url == kPageURL) {
"</title></head><body>" + http_response->set_content("<html><head><title>" + std::string(kPageTitle) +
std::string(kPageLoadedString) + "</body></html>"); "</title></head><body>" +
(*counter)++; std::string(kPageLoadedString) +
return std::move(http_response); "</body></html>");
(*counter)++;
return std::move(http_response);
} else if (request.relative_url == kUserAgentPageURL) {
std::string desktop_product =
"CriOS/" + version_info::GetMajorVersionNumber();
std::string desktop_user_agent =
web::BuildDesktopUserAgent(desktop_product);
std::string response_body;
auto user_agent = request.headers.find("User-Agent");
if (user_agent != request.headers.end() &&
user_agent->second == desktop_user_agent) {
response_body = std::string(kDesktopSiteLabel);
} else {
response_body = std::string(kMobileSiteLabel);
}
http_response->set_content("<html><head></head><body>" +
std::string(response_body) + "</body></html>");
return std::move(http_response);
}
return nullptr;
} }
// Select the button to request desktop site by scrolling the collection.
// 200 is a reasonable scroll displacement that works for all UI elements, while
// not being too slow.
GREYElementInteraction* RequestDesktopButton() {
return [[EarlGrey
selectElementWithMatcher:grey_allOf(grey_accessibilityID(
kToolsMenuRequestDesktopId),
grey_sufficientlyVisible(), nil)]
usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
onElementWithMatcher:grey_accessibilityID(
kPopupMenuToolsMenuTableViewId)];
}
} // namespace } // namespace
// Test case for the prerender. // Test case for the prerender.
@interface PrerenderTestCase : ChromeTestCase @interface PrerenderTestCase : ChromeTestCase {
int _visitCounter;
}
@end @end
@implementation PrerenderTestCase @implementation PrerenderTestCase
// Test that tapping the prerendered suggestions opens it. - (void)addURLToHistory {
- (void)testTapPrerenderSuggestions {
// TODO(crbug.com/793306): Re-enable the test on iPad once the alternate
// letters problem is fixed.
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_DISABLED(
@"Disabled for iPad due to alternate letters educational screen.");
}
[ChromeEarlGrey clearBrowsingHistory]; [ChromeEarlGrey clearBrowsingHistory];
// Set server up. // Set server up.
int visitCounter = 0; _visitCounter = 0;
self.testServer->RegisterRequestHandler( self.testServer->RegisterRequestHandler(
base::BindRepeating(&StandardResponse, &visitCounter)); base::BindRepeating(&StandardResponse, &_visitCounter));
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
const GURL pageURL = self.testServer->GetURL(kPageURL); const GURL pageURL = self.testServer->GetURL(kPageURL);
NSString* pageString = base::SysUTF8ToNSString(pageURL.GetContent()); NSString* pageString = base::SysUTF8ToNSString(pageURL.GetContent());
// Go to the page a couple of time so it shows as suggestion. // Go to the page a couple of time so it shows as suggestion.
[ChromeEarlGrey loadURL:pageURL]; [ChromeEarlGrey loadURL:pageURL];
GREYAssertEqual(1, visitCounter, @"The page should have been loaded once"); GREYAssertEqual(1, _visitCounter, @"The page should have been loaded once");
[ChromeEarlGrey goBack]; [ChromeEarlGrey goBack];
[[self class] closeAllTabs]; [[self class] closeAllTabs];
[ChromeEarlGrey openNewTab]; [ChromeEarlGrey openNewTab];
...@@ -86,9 +121,26 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse( ...@@ -86,9 +121,26 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
[[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()] [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
performAction:grey_typeText([pageString stringByAppendingString:@"\n"])]; performAction:grey_typeText([pageString stringByAppendingString:@"\n"])];
[ChromeEarlGrey waitForPageToFinishLoading]; [ChromeEarlGrey waitForPageToFinishLoading];
static int visitCountBeforePrerender = visitCounter;
[[self class] closeAllTabs]; [[self class] closeAllTabs];
[ChromeEarlGrey openNewTab]; [ChromeEarlGrey openNewTab];
}
#pragma mark - Tests
// Test that tapping the prerendered suggestions opens it.
- (void)testTapPrerenderSuggestions {
// TODO(crbug.com/793306): Re-enable the test on iPad once the alternate
// letters problem is fixed.
if ([ChromeEarlGrey isIPadIdiom]) {
EARL_GREY_TEST_DISABLED(
@"Disabled for iPad due to alternate letters educational screen.");
}
[self addURLToHistory];
const GURL pageURL = self.testServer->GetURL(kPageURL);
NSString* pageString = base::SysUTF8ToNSString(pageURL.GetContent());
static int visitCountBeforePrerender = _visitCounter;
// Type the begining of the address to have the autocomplete suggestion. // Type the begining of the address to have the autocomplete suggestion.
[[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()] [[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
...@@ -101,7 +153,7 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse( ...@@ -101,7 +153,7 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
// Wait until prerender request reaches the server. // Wait until prerender request reaches the server.
bool prerendered = WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ bool prerendered = WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
return visitCounter == visitCountBeforePrerender + 1; return _visitCounter == visitCountBeforePrerender + 1;
}); });
GREYAssertTrue(prerendered, @"Prerender did not happen"); GREYAssertTrue(prerendered, @"Prerender did not happen");
...@@ -125,8 +177,68 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse( ...@@ -125,8 +177,68 @@ std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
performAction:grey_tap()]; performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kPageLoadedString]; [ChromeEarlGrey waitForWebStateContainingText:kPageLoadedString];
GREYAssertEqual(visitCountBeforePrerender + 1, visitCounter, GREYAssertEqual(visitCountBeforePrerender + 1, _visitCounter,
@"Prerender should have been the last load"); @"Prerender should have been the last load");
} }
// Tests that tapping the prerendered suggestions keeps the UserAgent of the
// previous page.
- (void)testUserAgentTypeInPreviousLoad {
[self addURLToHistory];
const GURL pageURL = self.testServer->GetURL(kPageURL);
NSString* pageString = base::SysUTF8ToNSString(pageURL.GetContent());
static int visitCountBeforePrerender = _visitCounter;
// Load the UserAgent page.
const GURL userAgentPageURL = self.testServer->GetURL(kUserAgentPageURL);
[ChromeEarlGrey loadURL:userAgentPageURL];
[ChromeEarlGrey waitForWebStateContainingText:kMobileSiteLabel];
// Type the begining of the address to have the autocomplete suggestion.
[ChromeEarlGreyUI focusOmnibox];
[[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
performAction:grey_typeText(
[pageString substringToIndex:[pageString length] - 6])];
// Wait until prerender request reaches the server.
bool prerendered = WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
return _visitCounter == visitCountBeforePrerender + 1;
});
GREYAssertTrue(prerendered, @"Prerender did not happen");
// Open the suggestion. The suggestion needs to be the first suggestion to
// have the prerenderer activated.
[[EarlGrey
selectElementWithMatcher:grey_allOf(
grey_accessibilityLabel(pageString),
grey_kindOfClassName(@"FadeTruncatingLabel"),
grey_ancestor(grey_accessibilityID(
@"omnibox suggestion 0")),
grey_sufficientlyVisible(), nil)]
performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kPageLoadedString];
GREYAssertEqual(visitCountBeforePrerender + 1, _visitCounter,
@"Prerender should have been the last load");
// Request the desktop site.
[ChromeEarlGreyUI openToolsMenu];
[RequestDesktopButton() performAction:grey_tap()];
prerendered = WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
return _visitCounter == visitCountBeforePrerender + 2;
});
GREYAssertTrue(prerendered, @"Page wasn't reloaded");
// Verify that going back returns to the mobile site.
[[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
performAction:grey_tap()];
[ChromeEarlGrey waitForWebStateContainingText:kMobileSiteLabel];
// The content of the page can be cached, check the button also.
[ChromeEarlGreyUI openToolsMenu];
[RequestDesktopButton() assertWithMatcher:grey_notNil()];
}
@end @end
...@@ -109,6 +109,20 @@ void WKBasedNavigationManagerImpl::OnNavigationStarted(const GURL& url) { ...@@ -109,6 +109,20 @@ void WKBasedNavigationManagerImpl::OnNavigationStarted(const GURL& url) {
restoration_timer_->Elapsed()); restoration_timer_->Elapsed());
restoration_timer_.reset(); restoration_timer_.reset();
} }
// Get the last committed item directly because the restoration is in
// progress so the item returned by the last committed item is the
// last_committed_web_view_item_ as the origins mistmatch.
int index = GetLastCommittedItemIndexInCurrentOrRestoredSession();
DCHECK(index != -1 || 0 == GetItemCount());
if (index != -1 &&
restored_visible_item_->GetUserAgentType() != UserAgentType::NONE) {
NavigationItemImpl* last_committed_item =
GetNavigationItemImplAtIndex(static_cast<size_t>(index));
last_committed_item->SetUserAgentType(
restored_visible_item_->GetUserAgentType());
}
FinalizeSessionRestore(); FinalizeSessionRestore();
} }
} }
...@@ -390,6 +404,12 @@ bool WKBasedNavigationManagerImpl::ShouldBlockUrlDuringRestore( ...@@ -390,6 +404,12 @@ bool WKBasedNavigationManagerImpl::ShouldBlockUrlDuringRestore(
// Abort restore. // Abort restore.
DiscardNonCommittedItems(); DiscardNonCommittedItems();
last_committed_item_index_ = web_view_cache_.GetCurrentItemIndex(); last_committed_item_index_ = web_view_cache_.GetCurrentItemIndex();
if (restored_visible_item_->GetUserAgentType() != UserAgentType::NONE) {
NavigationItem* last_committed_item =
GetLastCommittedItemInCurrentOrRestoredSession();
last_committed_item->SetUserAgentType(
restored_visible_item_->GetUserAgentType());
}
restored_visible_item_.reset(); restored_visible_item_.reset();
FinalizeSessionRestore(); FinalizeSessionRestore();
return true; return true;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#import "ios/web/web_state/user_interaction_state.h" #import "ios/web/web_state/user_interaction_state.h"
#import "ios/web/web_state/web_state_impl.h" #import "ios/web/web_state/web_state_impl.h"
#import "net/base/mac/url_conversions.h" #import "net/base/mac/url_conversions.h"
#include "net/base/url_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
...@@ -324,9 +325,12 @@ enum class BackForwardNavigationType { ...@@ -324,9 +325,12 @@ enum class BackForwardNavigationType {
// redirects can not change the origin. It is possible to have more than one // redirects can not change the origin. It is possible to have more than one
// pending navigations, so the redirect does not necesserily belong to the // pending navigations, so the redirect does not necesserily belong to the
// pending navigation item. // pending navigation item.
// Do not do it for localhost address as this is needed to have
// pre-rendering in tests.
if ((base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage) || if ((base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage) ||
!placeholderNavigation) && !placeholderNavigation) &&
item->GetURL().GetOrigin() == requestURL.GetOrigin()) { item->GetURL().GetOrigin() == requestURL.GetOrigin() &&
!net::IsLocalhost(requestURL)) {
self.navigationManagerImpl->UpdatePendingItemUrl(requestURL); self.navigationManagerImpl->UpdatePendingItemUrl(requestURL);
} }
} else { } else {
......
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