Commit babe6604 authored by creis's avatar creis Committed by Commit bot

Track referenced files of subframes in PageState.

BUG=441966
TEST=Upload a previously selected file from subframe form after restore.

Review URL: https://codereview.chromium.org/805563003

Cr-Commit-Position: refs/heads/master@{#308238}
parent 9ad06b87
...@@ -1543,21 +1543,21 @@ class FileChooserDelegate : public WebContentsDelegate { ...@@ -1543,21 +1543,21 @@ class FileChooserDelegate : public WebContentsDelegate {
IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
RestoreFileAccessForHistoryNavigation) { RestoreFileAccessForHistoryNavigation) {
StartServer(); StartServer();
base::FilePath file_path; base::FilePath file;
EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path)); EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
file_path = file_path.AppendASCII("bar"); file = file.AppendASCII("bar");
// Navigate to url and get it to reference a file in its PageState. // Navigate to url and get it to reference a file in its PageState.
GURL url1(test_server()->GetURL("files/file_input.html")); GURL url1(test_server()->GetURL("files/file_input.html"));
NavigateToURL(shell(), url1); NavigateToURL(shell(), url1);
int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID(); int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file_path)); scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
shell()->web_contents()->SetDelegate(delegate.get()); shell()->web_contents()->SetDelegate(delegate.get());
EXPECT_TRUE(ExecuteScript(shell()->web_contents(), EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
"document.getElementById('fileinput').click();")); "document.getElementById('fileinput').click();"));
EXPECT_TRUE(delegate->file_chosen()); EXPECT_TRUE(delegate->file_chosen());
EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
process_id, file_path)); process_id, file));
// Navigate to a different process without access to the file, and wait for // Navigate to a different process without access to the file, and wait for
// the old process to exit. // the old process to exit.
...@@ -1567,16 +1567,16 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ...@@ -1567,16 +1567,16 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
exit_observer.Wait(); exit_observer.Wait();
EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path)); shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
// Ensure that the file ended up in the PageState of the previous entry. // Ensure that the file ended up in the PageState of the previous entry.
NavigationEntry* prev_entry = NavigationEntry* prev_entry =
shell()->web_contents()->GetController().GetEntryAtIndex(0); shell()->web_contents()->GetController().GetEntryAtIndex(0);
EXPECT_EQ(url1, prev_entry->GetURL()); EXPECT_EQ(url1, prev_entry->GetURL());
const std::vector<base::FilePath>& file_paths = const std::vector<base::FilePath>& files =
prev_entry->GetPageState().GetReferencedFiles(); prev_entry->GetPageState().GetReferencedFiles();
ASSERT_EQ(1U, file_paths.size()); ASSERT_EQ(1U, files.size());
EXPECT_EQ(file_path, file_paths.at(0)); EXPECT_EQ(file, files.at(0));
// Go back, ending up in a different RenderProcessHost than before. // Go back, ending up in a different RenderProcessHost than before.
TestNavigationObserver back_nav_load_observer(shell()->web_contents()); TestNavigationObserver back_nav_load_observer(shell()->web_contents());
...@@ -1587,7 +1587,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ...@@ -1587,7 +1587,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
// Ensure that the file access still exists in the new process ID. // Ensure that the file access still exists in the new process ID.
EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path)); shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
// Navigate to a same site page to trigger a PageState update and ensure the // Navigate to a same site page to trigger a PageState update and ensure the
// renderer is not killed. // renderer is not killed.
...@@ -1595,4 +1595,57 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ...@@ -1595,4 +1595,57 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
NavigateToURL(shell(), test_server()->GetURL("files/title2.html"))); NavigateToURL(shell(), test_server()->GetURL("files/title2.html")));
} }
// Test for http://crbug.com/441966.
IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
RestoreSubframeFileAccessForHistoryNavigation) {
StartServer();
base::FilePath file;
EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file));
file = file.AppendASCII("bar");
// Navigate to url and get it to reference a file in its PageState.
GURL url1(test_server()->GetURL("files/file_input_subframe.html"));
NavigateToURL(shell(), url1);
WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = wc->GetFrameTree()->root();
int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file));
shell()->web_contents()->SetDelegate(delegate.get());
EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
"document.getElementById('fileinput').click();"));
EXPECT_TRUE(delegate->file_chosen());
EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
process_id, file));
// Navigate to a different process without access to the file, and wait for
// the old process to exit.
RenderProcessHostWatcher exit_observer(
shell()->web_contents()->GetRenderProcessHost(),
RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
exit_observer.Wait();
EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
// Ensure that the file ended up in the PageState of the previous entry.
NavigationEntry* prev_entry =
shell()->web_contents()->GetController().GetEntryAtIndex(0);
EXPECT_EQ(url1, prev_entry->GetURL());
const std::vector<base::FilePath>& files =
prev_entry->GetPageState().GetReferencedFiles();
ASSERT_EQ(1U, files.size());
EXPECT_EQ(file, files.at(0));
// Go back, ending up in a different RenderProcessHost than before.
TestNavigationObserver back_nav_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_nav_load_observer.Wait();
EXPECT_NE(process_id,
shell()->web_contents()->GetRenderProcessHost()->GetID());
// Ensure that the file access still exists in the new process ID.
EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
shell()->web_contents()->GetRenderProcessHost()->GetID(), file));
}
} // namespace content } // namespace content
...@@ -68,6 +68,9 @@ private: ...@@ -68,6 +68,9 @@ private:
}; };
struct CONTENT_EXPORT ExplodedPageState { struct CONTENT_EXPORT ExplodedPageState {
// TODO(creis): Move referenced_files to ExplodedFrameState.
// It currently contains a list from all frames, but cannot be deserialized
// into the files referenced by each frame. See http://crbug.com/441966.
std::vector<base::NullableString16> referenced_files; std::vector<base::NullableString16> referenced_files;
ExplodedFrameState top; ExplodedFrameState top;
......
...@@ -26,7 +26,7 @@ namespace { ...@@ -26,7 +26,7 @@ namespace {
void ToNullableString16Vector(const WebVector<WebString>& input, void ToNullableString16Vector(const WebVector<WebString>& input,
std::vector<base::NullableString16>* output) { std::vector<base::NullableString16>* output) {
output->reserve(input.size()); output->reserve(output->size() + input.size());
for (size_t i = 0; i < input.size(); ++i) for (size_t i = 0; i < input.size(); ++i)
output->push_back(input[i]); output->push_back(input[i]);
} }
...@@ -114,14 +114,20 @@ void GenerateFrameStateFromItem(const WebHistoryItem& item, ...@@ -114,14 +114,20 @@ void GenerateFrameStateFromItem(const WebHistoryItem& item,
} }
} }
void RecursivelyGenerateFrameState(HistoryEntry::HistoryNode* node, void RecursivelyGenerateFrameState(
ExplodedFrameState* state) { HistoryEntry::HistoryNode* node,
ExplodedFrameState* state,
std::vector<base::NullableString16>* referenced_files) {
GenerateFrameStateFromItem(node->item(), state); GenerateFrameStateFromItem(node->item(), state);
ToNullableString16Vector(node->item().getReferencedFilePaths(),
referenced_files);
std::vector<HistoryEntry::HistoryNode*>& children = node->children(); std::vector<HistoryEntry::HistoryNode*>& children = node->children();
state->children.resize(children.size()); state->children.resize(children.size());
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i) {
RecursivelyGenerateFrameState(children[i], &state->children[i]); RecursivelyGenerateFrameState(children[i], &state->children[i],
referenced_files);
}
} }
void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state, void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
...@@ -169,10 +175,8 @@ void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state, ...@@ -169,10 +175,8 @@ void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
PageState HistoryEntryToPageState(HistoryEntry* entry) { PageState HistoryEntryToPageState(HistoryEntry* entry) {
ExplodedPageState state; ExplodedPageState state;
ToNullableString16Vector(entry->root().getReferencedFilePaths(), RecursivelyGenerateFrameState(entry->root_history_node(), &state.top,
&state.referenced_files); &state.referenced_files);
RecursivelyGenerateFrameState(entry->root_history_node(), &state.top);
std::string encoded_data; std::string encoded_data;
if (!EncodePageState(state, &encoded_data)) if (!EncodePageState(state, &encoded_data))
......
<iframe srcdoc="<form action='title2.html' enctype='multipart/form-data' method='post'><input type='file' id='fileinput' /></form>">
</iframe>
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