OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/subresource_filter/content/browser/content_subresource_filt er_throttle_manager.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/memory/ptr_util.h" | |
10 #include "components/subresource_filter/content/browser/activation_state_computi ng_navigation_throttle.h" | |
11 #include "components/subresource_filter/content/browser/async_document_subresour ce_filter.h" | |
12 #include "components/subresource_filter/content/browser/subframe_navigation_filt ering_throttle.h" | |
13 #include "content/public/browser/navigation_handle.h" | |
14 #include "content/public/browser/render_frame_host.h" | |
15 #include "content/public/browser/web_contents.h" | |
16 #include "net/base/net_errors.h" | |
17 | |
18 namespace subresource_filter { | |
19 | |
20 bool ContentSubresourceFilterThrottleManager::Delegate:: | |
21 ShouldSuppressActivation(content::NavigationHandle* navigation_handle) { | |
22 return false; | |
23 } | |
24 | |
25 ContentSubresourceFilterThrottleManager:: | |
26 ContentSubresourceFilterThrottleManager( | |
27 Delegate* delegate, | |
28 VerifiedRulesetDealer::Handle* dealer_handle, | |
29 content::WebContents* web_contents) | |
30 : content::WebContentsObserver(web_contents), | |
31 dealer_handle_(dealer_handle), | |
32 delegate_(delegate), | |
33 weak_ptr_factory_(this) {} | |
34 | |
35 ContentSubresourceFilterThrottleManager:: | |
36 ~ContentSubresourceFilterThrottleManager() {} | |
37 | |
38 void ContentSubresourceFilterThrottleManager::NotifyPageActivationComputed( | |
39 content::NavigationHandle* navigation_handle, | |
40 const ActivationState& activation_state) { | |
41 DCHECK(navigation_handle->IsInMainFrame()); | |
42 DCHECK(!navigation_handle->HasCommitted()); | |
43 auto it = ongoing_activation_throttles_.find(navigation_handle); | |
44 if (it != ongoing_activation_throttles_.end()) { | |
45 it->second->NotifyPageActivationWithRuleset(EnsureRulesetHandle(), | |
46 activation_state); | |
47 } | |
48 } | |
49 | |
50 void ContentSubresourceFilterThrottleManager::RenderFrameDeleted( | |
51 content::RenderFrameHost* frame_host) { | |
52 activated_frame_hosts_.erase(frame_host); | |
53 DestroyRulesetHandleIfNoLongerUsed(); | |
54 } | |
55 | |
56 // Pull the AsyncDocumentSubresourceFilter and its associated ActivationState | |
57 // out of the activation state computing throttle. Store it for later filtering | |
58 // of subframe navigations. | |
59 void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation( | |
60 content::NavigationHandle* navigation_handle) { | |
61 auto throttle = ongoing_activation_throttles_.find(navigation_handle); | |
62 if (throttle == ongoing_activation_throttles_.end()) | |
63 return; | |
64 | |
65 // Some browser-initiated navigations (like about:blank) do not go through | |
66 // WillProcessResponse, and won't receive valid filters or activation states. | |
67 AsyncDocumentSubresourceFilter* filter = throttle->second->filter(); | |
68 if (!filter || navigation_handle->GetNetErrorCode() != net::OK || | |
engedy
2017/03/20 18:58:14
nit: Can |filter| really be false for the reason a
Charlie Harrison
2017/03/20 20:02:56
I can't reproduce this now, as NavigationSimulator
| |
69 delegate_->ShouldSuppressActivation(navigation_handle)) { | |
70 return; | |
71 } | |
72 | |
73 DCHECK_NE(ActivationLevel::DISABLED, | |
74 filter->activation_state().activation_level); | |
75 | |
76 filter->set_first_disallowed_load_callback(base::Bind( | |
engedy
2017/03/20 18:58:14
nit: Could we set this later once we have taken ow
Charlie Harrison
2017/03/20 20:02:56
Done.
| |
77 &ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad, | |
78 weak_ptr_factory_.GetWeakPtr())); | |
79 throttle->second->WillSendActivationToRenderer(); | |
80 // TODO(csharrison): Send an IPC to the renderer. | |
81 } | |
82 | |
83 void ContentSubresourceFilterThrottleManager::DidFinishNavigation( | |
84 content::NavigationHandle* navigation_handle) { | |
85 // Do nothing if the navigation finished in the same document. Just make sure | |
86 // to not leak throttle pointers. | |
87 if (!navigation_handle->HasCommitted() || | |
88 navigation_handle->IsSameDocument()) { | |
89 ongoing_activation_throttles_.erase(navigation_handle); | |
90 return; | |
91 } | |
92 | |
93 auto throttle = ongoing_activation_throttles_.find(navigation_handle); | |
94 std::unique_ptr<AsyncDocumentSubresourceFilter> filter; | |
95 if (throttle != ongoing_activation_throttles_.end()) { | |
96 filter = throttle->second->ReleaseFilter(); | |
97 ongoing_activation_throttles_.erase(throttle); | |
98 } | |
99 | |
100 // Make sure |activated_frame_hosts_| is updated or cleaned up depending on | |
101 // this navigation's activation state. | |
102 content::RenderFrameHost* frame_host = | |
103 navigation_handle->GetRenderFrameHost(); | |
104 if (filter) { | |
105 activated_frame_hosts_[frame_host] = std::move(filter); | |
106 } else { | |
107 activated_frame_hosts_.erase(frame_host); | |
108 } | |
109 | |
110 if (navigation_handle->IsInMainFrame()) | |
111 current_committed_load_has_notified_disallowed_load_ = false; | |
112 DestroyRulesetHandleIfNoLongerUsed(); | |
113 } | |
114 | |
115 void ContentSubresourceFilterThrottleManager::MaybeAppendNavigationThrottles( | |
116 content::NavigationHandle* navigation_handle, | |
117 std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles) { | |
118 DCHECK(!navigation_handle->IsSameDocument()); | |
119 if (auto filtering_throttle = | |
120 MaybeCreateSubframeNavigationFilteringThrottle(navigation_handle)) { | |
121 throttles->push_back(std::move(filtering_throttle)); | |
122 } | |
123 if (auto activation_throttle = | |
124 MaybeCreateActivationStateComputingThrottle(navigation_handle)) { | |
125 ongoing_activation_throttles_[navigation_handle] = | |
126 activation_throttle.get(); | |
127 throttles->push_back(std::move(activation_throttle)); | |
128 } | |
129 } | |
130 | |
131 std::unique_ptr<SubframeNavigationFilteringThrottle> | |
132 ContentSubresourceFilterThrottleManager:: | |
133 MaybeCreateSubframeNavigationFilteringThrottle( | |
134 content::NavigationHandle* navigation_handle) { | |
135 if (navigation_handle->IsInMainFrame()) | |
136 return nullptr; | |
137 AsyncDocumentSubresourceFilter* parent_filter = | |
138 GetParentFrameFilter(navigation_handle); | |
139 return parent_filter ? base::MakeUnique<SubframeNavigationFilteringThrottle>( | |
140 navigation_handle, parent_filter) | |
141 : nullptr; | |
142 } | |
143 | |
144 std::unique_ptr<ActivationStateComputingNavigationThrottle> | |
145 ContentSubresourceFilterThrottleManager:: | |
146 MaybeCreateActivationStateComputingThrottle( | |
147 content::NavigationHandle* navigation_handle) { | |
148 // Main frames: create unconditionally. | |
149 if (navigation_handle->IsInMainFrame()) { | |
150 return ActivationStateComputingNavigationThrottle::CreateForMainFrame( | |
151 navigation_handle); | |
152 } | |
153 | |
154 // Subframes: create only for frames with activated parents. | |
155 AsyncDocumentSubresourceFilter* parent_filter = | |
156 GetParentFrameFilter(navigation_handle); | |
157 if (!parent_filter) | |
158 return nullptr; | |
159 DCHECK(ruleset_handle_); | |
160 return ActivationStateComputingNavigationThrottle::CreateForSubframe( | |
161 navigation_handle, ruleset_handle_.get(), | |
162 parent_filter->activation_state()); | |
163 } | |
164 | |
165 AsyncDocumentSubresourceFilter* | |
166 ContentSubresourceFilterThrottleManager::GetParentFrameFilter( | |
167 content::NavigationHandle* child_frame_navigation) { | |
168 DCHECK(!child_frame_navigation->IsInMainFrame()); | |
169 content::RenderFrameHost* parent = web_contents()->FindFrameByFrameTreeNodeId( | |
170 child_frame_navigation->GetParentFrameTreeNodeId()); | |
171 DCHECK(parent); | |
172 auto it = activated_frame_hosts_.find(parent); | |
173 return it == activated_frame_hosts_.end() ? nullptr : it->second.get(); | |
174 } | |
175 | |
176 void ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad() { | |
177 if (current_committed_load_has_notified_disallowed_load_) | |
178 return; | |
179 delegate_->OnFirstSubresourceLoadDisallowed(); | |
180 current_committed_load_has_notified_disallowed_load_ = true; | |
181 } | |
182 | |
183 VerifiedRuleset::Handle* | |
184 ContentSubresourceFilterThrottleManager::EnsureRulesetHandle() { | |
185 if (!ruleset_handle_) | |
186 ruleset_handle_ = base::MakeUnique<VerifiedRuleset::Handle>(dealer_handle_); | |
187 return ruleset_handle_.get(); | |
188 } | |
189 | |
190 void ContentSubresourceFilterThrottleManager:: | |
191 DestroyRulesetHandleIfNoLongerUsed() { | |
192 if (activated_frame_hosts_.size() == 0) | |
engedy
2017/03/20 18:58:14
Can it happen that |activated_frame_hosts| is empt
Charlie Harrison
2017/03/20 20:02:56
This is pretty tricky. I think we're ok here but I
| |
193 ruleset_handle_.reset(); | |
194 } | |
195 | |
196 } // namespace subresource_filter | |
OLD | NEW |