Commit ca387231 authored by Danyao Wang's avatar Danyao Wang Committed by Commit Bot

[Nav Experiment] Set virtual URL for restore_session.html items.

This CL handles two cases:
1) When restore_session.html is first loaded, set virtual URL to the
   item that will be displayed when session is fully restored.
2) If a restore_session.html is loaded in the webview, set the virtual
   URL to the encoded URL, as that will be the page that will eventually
   be displayed.

Moved session restore logic into a separate util file so it's easier to
test.

Bug: 789993
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: I1547f792f1e3de0bf97d11dced09383b82c507fc
Reviewed-on: https://chromium-review.googlesource.com/817713
Commit-Queue: Danyao Wang <danyao@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#524418}
parent 7c1a115d
......@@ -257,6 +257,7 @@ source_set("ios_web_navigation_unittests") {
"navigation/placeholder_navigation_util_unittest.mm",
"navigation/serializable_user_data_manager_impl_unittest.mm",
"navigation/wk_based_navigation_manager_impl_unittest.mm",
"navigation/wk_based_restore_session_util_unittest.mm",
]
}
......
......@@ -43,6 +43,8 @@ source_set("navigation") {
"time_smoother.h",
"wk_based_navigation_manager_impl.h",
"wk_based_navigation_manager_impl.mm",
"wk_based_restore_session_util.h",
"wk_based_restore_session_util.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
......
......@@ -7,23 +7,19 @@
#import <Foundation/Foundation.h>
#include <memory>
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "ios/web/navigation/crw_navigation_item_holder.h"
#import "ios/web/navigation/navigation_item_impl.h"
#include "ios/web/navigation/navigation_item_impl_list.h"
#import "ios/web/navigation/navigation_manager_delegate.h"
#include "ios/web/navigation/wk_based_restore_session_util.h"
#include "ios/web/public/load_committed_details.h"
#import "ios/web/public/navigation_item.h"
#import "ios/web/public/web_client.h"
#import "ios/web/web_state/ui/crw_web_view_navigation_proxy.h"
#import "net/base/mac/url_conversions.h"
#include "net/base/url_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -383,38 +379,17 @@ void WKBasedNavigationManagerImpl::Restore(
// TODO(crbug.com/771200): Retain these original NavigationItems restored from
// storage and associate them with new WKBackForwardListItems created after
// history restore so information such as scroll position is restored.
// The URLs and titles of the restored entries are stored in two separate
// lists instead of a single list of objects to reduce the size of the JSON
// string to be included in the query parameter.
base::Value restored_urls(base::Value::Type::LIST);
base::Value restored_titles(base::Value::Type::LIST);
restored_urls.GetList().reserve(items.size());
restored_titles.GetList().reserve(items.size());
for (size_t index = 0; index < items.size(); index++) {
restored_urls.GetList().push_back(
base::Value(items[index]->GetURL().spec()));
restored_titles.GetList().push_back(base::Value(items[index]->GetTitle()));
}
base::Value session(base::Value::Type::DICTIONARY);
int offset = last_committed_item_index + 1 - items.size();
session.SetKey("offset", base::Value(offset));
session.SetKey("urls", std::move(restored_urls));
session.SetKey("titles", std::move(restored_titles));
std::string session_json;
base::JSONWriter::Write(session, &session_json);
std::string restore_session_resource_path = base::SysNSStringToUTF8(
[base::mac::FrameworkBundle() pathForResource:@"restore_session"
ofType:@"html"]);
std::string url_spec = base::StringPrintf(
"%s://%s", url::kFileScheme, restore_session_resource_path.c_str());
GURL url = net::AppendQueryParameter(GURL(url_spec), "session", session_json);
GURL url = CreateRestoreSessionUrl(last_committed_item_index, items);
WebLoadParams params(url);
// It's not clear how this transition type will be used and what's the impact.
// For now, use RELOAD because restoring history is kind of like a reload of
// the current page.
params.transition_type = ui::PAGE_TRANSITION_RELOAD;
LoadURLWithParams(params);
GetPendingItemImpl()->SetVirtualURL(
items[last_committed_item_index]->GetVirtualURL());
}
NavigationItemImpl* WKBasedNavigationManagerImpl::GetNavigationItemImplAtIndex(
......@@ -444,6 +419,20 @@ NavigationItemImpl* WKBasedNavigationManagerImpl::GetNavigationItemImplAtIndex(
net::GURLWithNSURL(prev_wk_item.URL),
nullptr /* use default rewriters only */);
new_item->SetTimestamp(time_smoother_.GetSmoothedTime(base::Time::Now()));
const GURL& url = new_item->GetURL();
// If this navigation item has a restore_session.html URL, then it was created
// to restore session history and will redirect to the target URL encoded in
// the query parameter automatically. Set virtual URL to the target URL so the
// internal restore_session.html is not exposed in the UI and to URL-sensing
// components outside of //ios/web layer.
if (IsRestoreSessionUrl(url)) {
GURL virtual_url;
bool success = ExtractTargetURL(url, &virtual_url);
DCHECK(success);
if (success)
new_item->SetVirtualURL(virtual_url);
}
SetNavigationItemInWKItem(wk_item, std::move(new_item));
return GetNavigationItemFromWKItem(wk_item);
}
......
......@@ -8,10 +8,12 @@
#include <memory>
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "ios/web/navigation/navigation_manager_delegate.h"
#import "ios/web/navigation/navigation_manager_impl.h"
#include "ios/web/navigation/wk_based_restore_session_util.h"
#include "ios/web/public/load_committed_details.h"
#include "ios/web/public/navigation_item.h"
#include "ios/web/public/test/fakes/test_browser_state.h"
......@@ -583,9 +585,11 @@ TEST_F(WKBasedNavigationManagerTest, RestoreSessionWithHistory) {
GURL pending_url = pending_item->GetURL();
EXPECT_TRUE(pending_url.SchemeIsFile());
EXPECT_EQ("restore_session.html", pending_url.ExtractFileName());
EXPECT_EQ("http://www.0.com/", pending_item->GetVirtualURL());
std::string session_json;
net::GetValueForKeyInQuery(pending_url, "session", &session_json);
net::GetValueForKeyInQuery(pending_url, kRestoreSessionSessionQueryKey,
&session_json);
EXPECT_EQ(
"{\"offset\":-1,\"titles\":[\"Test Website 0\",\"\"],"
"\"urls\":[\"http://www.0.com/\",\"http://www.1.com/\"]}",
......@@ -660,4 +664,19 @@ TEST_F(WKBasedNavigationManagerTest, RestoreSessionWithEmptyHistory) {
ASSERT_EQ(nullptr, manager_->GetPendingItem());
}
// Tests that the virtual URL of a restore_session redirect item is updated to
// the target URL.
TEST_F(WKBasedNavigationManagerTest, HideInternalRedirectUrl) {
GURL target_url = GURL("http://www.1.com?query=special%26chars");
GURL url = net::AppendQueryParameter(GetRestoreSessionBaseUrl(),
kRestoreSessionTargetUrlQueryKey,
target_url.spec());
NSString* url_spec = base::SysUTF8ToNSString(url.spec());
[mock_wk_list_ setCurrentURL:url_spec];
NavigationItem* item = manager_->GetItemAtIndex(0);
ASSERT_TRUE(item);
EXPECT_EQ(target_url, item->GetVirtualURL());
EXPECT_EQ(url, item->GetURL());
}
} // namespace web
// Copyright 2017 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.
//
// This file contains utility functions for WKBasedNavigationManagerImpl.
#ifndef IOS_WEB_NAVIGATION_WK_BASED_RESTORE_SESSION_UTIL_H_
#define IOS_WEB_NAVIGATION_WK_BASED_RESTORE_SESSION_UTIL_H_
#include <memory>
#include <vector>
#include "url/gurl.h"
namespace web {
class NavigationItem;
// Query parameter key used to encode the session history to inject in a
// restore_session.html URL.
extern const char kRestoreSessionSessionQueryKey[];
// Query parameter key used to encode target URL in a restore_session.html URL.
extern const char kRestoreSessionTargetUrlQueryKey[];
// Returns a file:// URL that points to the magic restore_session.html file.
// This is used in unit tests.
GURL GetRestoreSessionBaseUrl();
// Creates a restore_session.html URL with the provided session history encoded
// in the query argument, such that when this URL is loaded in the web view,
// recreates all the history entries in |items| and the current loaded item is
// the entry at |last_committed_item_index|.
GURL CreateRestoreSessionUrl(
int last_committed_item_index,
const std::vector<std::unique_ptr<NavigationItem>>& items);
// Returns true if the base URL of |url| is restore_session.html.
bool IsRestoreSessionUrl(const GURL& url);
// Extracts the URL encoded in the 'targetUrl' query component of
// |restore_session_url| to |target_url| and returns true. If no such query
// component exists, returns false.
bool ExtractTargetURL(const GURL& restore_session_url, GURL* target_url);
} // namespace web
#endif // IOS_WEB_NAVIGATION_WK_BASED_RESTORE_SESSION_UTIL_H_
// Copyright 2017 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 "ios/web/navigation/wk_based_restore_session_util.h"
#include "base/json/json_writer.h"
#include "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "ios/web/public/navigation_item.h"
#include "net/base/url_util.h"
#include "url/url_constants.h"
namespace web {
const char kRestoreSessionSessionQueryKey[] = "session";
const char kRestoreSessionTargetUrlQueryKey[] = "targetUrl";
GURL GetRestoreSessionBaseUrl() {
std::string restore_session_resource_path = base::SysNSStringToUTF8(
[base::mac::FrameworkBundle() pathForResource:@"restore_session"
ofType:@"html"]);
GURL::Replacements replacements;
replacements.SetSchemeStr(url::kFileScheme);
replacements.SetPathStr(restore_session_resource_path);
return GURL(url::kAboutBlankURL).ReplaceComponents(replacements);
}
GURL CreateRestoreSessionUrl(
int last_committed_item_index,
const std::vector<std::unique_ptr<NavigationItem>>& items) {
DCHECK(last_committed_item_index >= 0 &&
last_committed_item_index < static_cast<int>(items.size()));
// The URLs and titles of the restored entries are stored in two separate
// lists instead of a single list of objects to reduce the size of the JSON
// string to be included in the query parameter.
base::Value restored_urls(base::Value::Type::LIST);
base::Value restored_titles(base::Value::Type::LIST);
restored_urls.GetList().reserve(items.size());
restored_titles.GetList().reserve(items.size());
for (size_t index = 0; index < items.size(); index++) {
restored_urls.GetList().push_back(
base::Value(items[index]->GetURL().spec()));
restored_titles.GetList().push_back(base::Value(items[index]->GetTitle()));
}
base::Value session(base::Value::Type::DICTIONARY);
int offset = last_committed_item_index + 1 - items.size();
session.SetKey("offset", base::Value(offset));
session.SetKey("urls", std::move(restored_urls));
session.SetKey("titles", std::move(restored_titles));
std::string session_json;
base::JSONWriter::Write(session, &session_json);
return net::AppendQueryParameter(
GetRestoreSessionBaseUrl(), kRestoreSessionSessionQueryKey, session_json);
}
bool IsRestoreSessionUrl(const GURL& url) {
return url.SchemeIsFile() && url.path() == GetRestoreSessionBaseUrl().path();
}
bool ExtractTargetURL(const GURL& restore_session_url, GURL* target_url) {
DCHECK(IsRestoreSessionUrl(restore_session_url))
<< restore_session_url.possibly_invalid_spec()
<< " is not a restore session URL";
std::string target_url_spec;
bool success = net::GetValueForKeyInQuery(
restore_session_url, kRestoreSessionTargetUrlQueryKey, &target_url_spec);
if (success)
*target_url = GURL(target_url_spec);
return success;
}
} // namespace web
// Copyright 2017 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 "ios/web/navigation/wk_based_restore_session_util.h"
#include <memory>
#include <vector>
#include "base/strings/utf_string_conversions.h"
#import "ios/web/navigation/navigation_item_impl.h"
#include "net/base/url_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace web {
typedef PlatformTest WKBasedRestoreSessionUtilTest;
TEST_F(WKBasedRestoreSessionUtilTest, CreateRestoreSessionUrl) {
auto item0 = std::make_unique<NavigationItemImpl>();
item0->SetURL(GURL("http://www.0.com"));
item0->SetTitle(base::ASCIIToUTF16("Test Website 0"));
auto item1 = std::make_unique<NavigationItemImpl>();
item1->SetURL(GURL("http://www.1.com"));
std::vector<std::unique_ptr<NavigationItem>> items;
items.push_back(std::move(item0));
items.push_back(std::move(item1));
GURL restore_session_url =
CreateRestoreSessionUrl(0 /* last_committed_item_index */, items);
ASSERT_TRUE(IsRestoreSessionUrl(restore_session_url));
std::string session_json;
net::GetValueForKeyInQuery(restore_session_url,
kRestoreSessionSessionQueryKey, &session_json);
EXPECT_EQ(
"{\"offset\":-1,\"titles\":[\"Test Website 0\",\"\"],"
"\"urls\":[\"http://www.0.com/\",\"http://www.1.com/\"]}",
session_json);
}
TEST_F(WKBasedRestoreSessionUtilTest, IsNotRestoreSessionUrl) {
EXPECT_FALSE(IsRestoreSessionUrl(GURL()));
EXPECT_FALSE(IsRestoreSessionUrl(GURL("file://somefile")));
EXPECT_FALSE(IsRestoreSessionUrl(GURL("http://www.1.com")));
}
TEST_F(WKBasedRestoreSessionUtilTest, ExtractTargetURL) {
GURL target_url = GURL("http://www.1.com?query=special%26chars");
GURL url = net::AppendQueryParameter(GetRestoreSessionBaseUrl(),
kRestoreSessionTargetUrlQueryKey,
target_url.spec());
GURL extracted_url;
ASSERT_TRUE(ExtractTargetURL(url, &extracted_url));
EXPECT_EQ(target_url, extracted_url);
}
} // namespace web
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