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 {
IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
RestoreFileAccessForHistoryNavigation) {
StartServer();
base::FilePath file_path;
EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path));
file_path = file_path.AppendASCII("bar");
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.html"));
NavigateToURL(shell(), url1);
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());
EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
"document.getElementById('fileinput').click();"));
EXPECT_TRUE(delegate->file_chosen());
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
// the old process to exit.
......@@ -1567,16 +1567,16 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"));
exit_observer.Wait();
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.
NavigationEntry* prev_entry =
shell()->web_contents()->GetController().GetEntryAtIndex(0);
EXPECT_EQ(url1, prev_entry->GetURL());
const std::vector<base::FilePath>& file_paths =
const std::vector<base::FilePath>& files =
prev_entry->GetPageState().GetReferencedFiles();
ASSERT_EQ(1U, file_paths.size());
EXPECT_EQ(file_path, file_paths.at(0));
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());
......@@ -1587,7 +1587,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
// Ensure that the file access still exists in the new process ID.
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
// renderer is not killed.
......@@ -1595,4 +1595,57 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
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
......@@ -68,6 +68,9 @@ private:
};
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;
ExplodedFrameState top;
......
......@@ -26,7 +26,7 @@ namespace {
void ToNullableString16Vector(const WebVector<WebString>& input,
std::vector<base::NullableString16>* output) {
output->reserve(input.size());
output->reserve(output->size() + input.size());
for (size_t i = 0; i < input.size(); ++i)
output->push_back(input[i]);
}
......@@ -114,14 +114,20 @@ void GenerateFrameStateFromItem(const WebHistoryItem& item,
}
}
void RecursivelyGenerateFrameState(HistoryEntry::HistoryNode* node,
ExplodedFrameState* state) {
void RecursivelyGenerateFrameState(
HistoryEntry::HistoryNode* node,
ExplodedFrameState* state,
std::vector<base::NullableString16>* referenced_files) {
GenerateFrameStateFromItem(node->item(), state);
ToNullableString16Vector(node->item().getReferencedFilePaths(),
referenced_files);
std::vector<HistoryEntry::HistoryNode*>& children = node->children();
state->children.resize(children.size());
for (size_t i = 0; i < children.size(); ++i)
RecursivelyGenerateFrameState(children[i], &state->children[i]);
for (size_t i = 0; i < children.size(); ++i) {
RecursivelyGenerateFrameState(children[i], &state->children[i],
referenced_files);
}
}
void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
......@@ -169,11 +175,9 @@ void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
PageState HistoryEntryToPageState(HistoryEntry* entry) {
ExplodedPageState state;
ToNullableString16Vector(entry->root().getReferencedFilePaths(),
RecursivelyGenerateFrameState(entry->root_history_node(), &state.top,
&state.referenced_files);
RecursivelyGenerateFrameState(entry->root_history_node(), &state.top);
std::string encoded_data;
if (!EncodePageState(state, &encoded_data))
return PageState();
......
<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