| // Copyright 2015 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 "content/test/test_render_frame.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/debug/stack_trace.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "content/common/frame_messages.h" |
| #include "content/common/navigation_params.h" |
| #include "content/common/navigation_params.mojom.h" |
| #include "content/public/common/browser_side_navigation_policy.h" |
| #include "content/public/common/resource_response.h" |
| #include "content/public/test/mock_render_thread.h" |
| #include "content/renderer/loader/web_url_loader_impl.h" |
| #include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h" |
| #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| |
| namespace content { |
| |
| class MockFrameHost : public mojom::FrameHost { |
| public: |
| MockFrameHost() {} |
| ~MockFrameHost() override = default; |
| |
| std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> |
| TakeLastCommitParams() { |
| return std::move(last_commit_params_); |
| } |
| |
| service_manager::mojom::InterfaceProviderRequest |
| TakeLastInterfaceProviderRequest() { |
| return std::move(last_interface_provider_request_); |
| } |
| |
| // Holds on to the request end of the InterfaceProvider interface whose client |
| // end is bound to the corresponding RenderFrame's |remote_interfaces_| to |
| // facilitate retrieving the most recent |interface_provider_request| in |
| // tests. |
| void PassLastInterfaceProviderRequest( |
| service_manager::mojom::InterfaceProviderRequest |
| interface_provider_request) { |
| last_interface_provider_request_ = std::move(interface_provider_request); |
| } |
| |
| protected: |
| // mojom::FrameHost: |
| void CreateNewWindow(mojom::CreateNewWindowParamsPtr, |
| CreateNewWindowCallback) override { |
| NOTREACHED() << "We should never dispatch to the service side signature."; |
| } |
| |
| bool CreateNewWindow(mojom::CreateNewWindowParamsPtr params, |
| mojom::CreateNewWindowStatus* status, |
| mojom::CreateNewWindowReplyPtr* reply) override { |
| *status = mojom::CreateNewWindowStatus::kSuccess; |
| *reply = mojom::CreateNewWindowReply::New(); |
| MockRenderThread* mock_render_thread = |
| static_cast<MockRenderThread*>(RenderThread::Get()); |
| mock_render_thread->OnCreateWindow(*params, reply->get()); |
| return true; |
| } |
| |
| void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override {} |
| |
| void DidCommitProvisionalLoad( |
| std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params, |
| service_manager::mojom::InterfaceProviderRequest request) override { |
| last_commit_params_ = std::move(params); |
| last_interface_provider_request_ = std::move(request); |
| } |
| |
| void BeginNavigation(const CommonNavigationParams& common_params, |
| mojom::BeginNavigationParamsPtr begin_params) override {} |
| |
| void SubresourceResponseStarted(const GURL& url, |
| const GURL& referrer, |
| const std::string& method, |
| ResourceType resource_type, |
| const std::string& ip, |
| uint32_t cert_status) override {} |
| |
| void DidChangeName(const std::string& name, |
| const std::string& unique_name) override {} |
| |
| void EnforceInsecureRequestPolicy( |
| blink::WebInsecureRequestPolicy policy) override {} |
| |
| void DidSetFramePolicyHeaders( |
| blink::WebSandboxFlags sandbox_flags, |
| const blink::ParsedFeaturePolicy& parsed_header) override {} |
| |
| private: |
| std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> |
| last_commit_params_; |
| service_manager::mojom::InterfaceProviderRequest |
| last_interface_provider_request_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MockFrameHost); |
| }; |
| |
| // static |
| RenderFrameImpl* TestRenderFrame::CreateTestRenderFrame( |
| RenderFrameImpl::CreateParams params) { |
| return new TestRenderFrame(std::move(params)); |
| } |
| |
| TestRenderFrame::TestRenderFrame(RenderFrameImpl::CreateParams params) |
| : RenderFrameImpl(std::move(params)), |
| mock_frame_host_(std::make_unique<MockFrameHost>()) { |
| MockRenderThread* mock_render_thread = |
| static_cast<MockRenderThread*>(RenderThread::Get()); |
| mock_frame_host_->PassLastInterfaceProviderRequest( |
| mock_render_thread->TakeInitialInterfaceProviderRequestForFrame( |
| params.routing_id)); |
| } |
| |
| TestRenderFrame::~TestRenderFrame() {} |
| |
| void TestRenderFrame::SetURLOverrideForNextWebURLRequest(const GURL& url) { |
| next_request_url_override_ = url; |
| } |
| |
| void TestRenderFrame::WillSendRequest(blink::WebURLRequest& request) { |
| if (next_request_url_override_.has_value()) |
| request.SetURL(std::move(next_request_url_override_).value()); |
| RenderFrameImpl::WillSendRequest(request); |
| } |
| |
| void TestRenderFrame::Navigate(const CommonNavigationParams& common_params, |
| const StartNavigationParams& start_params, |
| const RequestNavigationParams& request_params) { |
| // PlzNavigate |
| if (IsBrowserSideNavigationEnabled()) { |
| CommitNavigation(ResourceResponseHead(), GURL(), common_params, |
| request_params, mojom::URLLoaderClientEndpointsPtr(), |
| URLLoaderFactoryBundle(), |
| base::UnguessableToken::Create()); |
| } else { |
| OnNavigate(common_params, start_params, request_params); |
| } |
| } |
| |
| void TestRenderFrame::SwapOut( |
| int proxy_routing_id, |
| bool is_loading, |
| const FrameReplicationState& replicated_frame_state) { |
| OnSwapOut(proxy_routing_id, is_loading, replicated_frame_state); |
| } |
| |
| void TestRenderFrame::SetEditableSelectionOffsets(int start, int end) { |
| OnSetEditableSelectionOffsets(start, end); |
| } |
| |
| void TestRenderFrame::ExtendSelectionAndDelete(int before, int after) { |
| OnExtendSelectionAndDelete(before, after); |
| } |
| |
| void TestRenderFrame::DeleteSurroundingText(int before, int after) { |
| OnDeleteSurroundingText(before, after); |
| } |
| |
| void TestRenderFrame::DeleteSurroundingTextInCodePoints(int before, int after) { |
| OnDeleteSurroundingTextInCodePoints(before, after); |
| } |
| |
| void TestRenderFrame::CollapseSelection() { |
| OnCollapseSelection(); |
| } |
| |
| void TestRenderFrame::SetAccessibilityMode(ui::AXMode new_mode) { |
| OnSetAccessibilityMode(new_mode); |
| } |
| |
| void TestRenderFrame::SetCompositionFromExistingText( |
| int start, |
| int end, |
| const std::vector<blink::WebImeTextSpan>& ime_text_spans) { |
| OnSetCompositionFromExistingText(start, end, ime_text_spans); |
| } |
| |
| blink::WebNavigationPolicy TestRenderFrame::DecidePolicyForNavigation( |
| const blink::WebFrameClient::NavigationPolicyInfo& info) { |
| if (IsBrowserSideNavigationEnabled() && |
| info.url_request.CheckForBrowserSideNavigation() && |
| ((GetWebFrame()->Parent() && info.form.IsNull()) || |
| next_request_url_override_.has_value())) { |
| // RenderViewTest::LoadHTML already disables PlzNavigate for the main frame |
| // requests. However if the loaded html has a subframe, the WebURLRequest |
| // will be created inside Blink and it won't have this flag set. |
| info.url_request.SetCheckForBrowserSideNavigation(false); |
| } |
| return RenderFrameImpl::DecidePolicyForNavigation(info); |
| } |
| |
| std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> |
| TestRenderFrame::TakeLastCommitParams() { |
| return mock_frame_host_->TakeLastCommitParams(); |
| } |
| |
| service_manager::mojom::InterfaceProviderRequest |
| TestRenderFrame::TakeLastInterfaceProviderRequest() { |
| return mock_frame_host_->TakeLastInterfaceProviderRequest(); |
| } |
| |
| mojom::FrameHost* TestRenderFrame::GetFrameHost() { |
| // Need to mock this interface directly without going through a binding, |
| // otherwise calling its sync methods could lead to a deadlock. |
| // |
| // Imagine the following sequence of events take place: |
| // |
| // 1.) GetFrameHost() called for the first time |
| // 1.1.) GetRemoteAssociatedInterfaces()->GetInterface(&frame_host_ptr_) |
| // 1.1.1) ... plumbing ... |
| // 1.1.2) Task posted to bind the request end to the Mock implementation |
| // 1.2) The interface pointer end is returned to the caller |
| // 2.) GetFrameHost()->CreateNewWindow(...) sync method invoked |
| // 2.1.) Mojo sync request sent |
| // 2.2.) Waiting for sync response while dispatching incoming sync requests |
| // |
| // Normally the sync Mojo request would be processed in 2.2. However, the |
| // implementation is not yet bound at that point, and will never be, because |
| // only sync IPCs are dispatched by 2.2, not posted tasks. So the sync request |
| // is never dispatched, the response never arrives. |
| // |
| // Because the first invocation to GetFrameHost() may come while we are inside |
| // a message loop already, pumping messags before 1.2 would constitute a |
| // nested message loop and is therefore undesired. |
| return mock_frame_host_.get(); |
| } |
| |
| } // namespace content |