OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "content/public/test/web_contents_observer_sanity_checker.h" | |
6 | |
7 #include "base/strings/stringprintf.h" | |
8 #include "content/common/frame_messages.h" | |
9 #include "content/public/browser/render_frame_host.h" | |
10 #include "content/public/browser/render_process_host.h" | |
11 #include "content/public/browser/site_instance.h" | |
12 #include "content/public/browser/web_contents.h" | |
13 #include "content/public/browser/web_contents_observer.h" | |
14 | |
15 namespace content { | |
16 | |
17 namespace { | |
18 | |
19 const char kWebContentsObserverSanityCheckerKey[] = | |
20 "WebContentsObserverSanityChecker"; | |
21 | |
22 } // namespace | |
23 | |
24 // static | |
25 void WebContentsObserverSanityChecker::Enable(WebContents* web_contents) { | |
26 if (web_contents->GetUserData(&kWebContentsObserverSanityCheckerKey)) | |
27 return; | |
28 web_contents->SetUserData(&kWebContentsObserverSanityCheckerKey, | |
29 new WebContentsObserverSanityChecker(web_contents)); | |
30 } | |
31 | |
32 void WebContentsObserverSanityChecker::RenderFrameCreated( | |
33 RenderFrameHost* render_frame_host) { | |
34 CHECK(!web_contents_destroyed_); | |
35 std::pair<int, int> routing_pair = | |
36 std::make_pair(render_frame_host->GetProcess()->GetID(), | |
37 render_frame_host->GetRoutingID()); | |
38 bool frame_exists = !live_routes_.insert(routing_pair).second; | |
39 deleted_routes_.erase(routing_pair); | |
40 | |
41 if (frame_exists) { | |
42 CHECK(false) << "RenderFrameCreated called more than once for routing pair:" | |
43 << Format(render_frame_host); | |
44 } | |
45 } | |
46 | |
47 void WebContentsObserverSanityChecker::RenderFrameDeleted( | |
48 RenderFrameHost* render_frame_host) { | |
49 CHECK(!web_contents_destroyed_); | |
50 std::pair<int, int> routing_pair = | |
51 std::make_pair(render_frame_host->GetProcess()->GetID(), | |
52 render_frame_host->GetRoutingID()); | |
53 bool was_live = !!live_routes_.erase(routing_pair); | |
54 bool was_dead_already = !deleted_routes_.insert(routing_pair).second; | |
55 | |
56 if (was_dead_already) { | |
57 CHECK(false) << "RenderFrameDeleted called more than once for routing pair " | |
58 << Format(render_frame_host); | |
59 } else if (!was_live) { | |
60 // TODO(nick): Clients can easily ignore an unrecognized object, but it | |
61 // would be useful from a finding-bugs perspective if we could enable this | |
62 // check. | |
63 #if 0 | |
64 CHECK(false) << "RenderFrameDeleted called for routing pair " | |
65 << Format(render_frame_host) | |
66 << " for which RenderFrameCreated was never called"; | |
67 #endif | |
68 } | |
69 } | |
70 | |
71 void WebContentsObserverSanityChecker::RenderFrameForInterstitialPageCreated( | |
72 RenderFrameHost* render_frame_host) { | |
73 // TODO(nick): Record this. | |
74 } | |
75 | |
76 void WebContentsObserverSanityChecker::RenderFrameHostChanged( | |
77 RenderFrameHost* old_host, | |
78 RenderFrameHost* new_host) { | |
79 CHECK(new_host); | |
80 CHECK_NE(new_host, old_host); | |
81 | |
82 if (old_host) { | |
83 std::pair<int, int> routing_pair = | |
84 std::make_pair(old_host->GetProcess()->GetID(), | |
85 old_host->GetRoutingID()); | |
86 bool old_did_exist = !!current_hosts_.erase(routing_pair); | |
87 if (!old_did_exist) { | |
88 CHECK(false) | |
89 << "RenderFrameHostChanged called with old host that did not exist:" | |
90 << Format(old_host); | |
91 } | |
92 } | |
93 | |
94 std::pair<int, int> routing_pair = | |
95 std::make_pair(new_host->GetProcess()->GetID(), | |
96 new_host->GetRoutingID()); | |
97 bool host_exists = !current_hosts_.insert(routing_pair).second; | |
98 if (host_exists) { | |
99 CHECK(false) | |
100 << "RenderFrameHostChanged called more than once for routing pair:" | |
101 << Format(new_host); | |
102 } | |
103 } | |
104 | |
105 void WebContentsObserverSanityChecker::FrameDeleted( | |
106 RenderFrameHost* render_frame_host) { | |
107 // A frame can be deleted before RenderFrame in the renderer process is | |
108 // created, so there is not much that can be enforced here. | |
109 CHECK(!web_contents_destroyed_); | |
110 } | |
111 | |
112 void WebContentsObserverSanityChecker::DidStartProvisionalLoadForFrame( | |
113 RenderFrameHost* render_frame_host, | |
114 const GURL& validated_url, | |
115 bool is_error_page, | |
116 bool is_iframe_srcdoc) { | |
117 AssertRenderFrameExists(render_frame_host); | |
118 } | |
119 | |
120 void WebContentsObserverSanityChecker::DidCommitProvisionalLoadForFrame( | |
121 RenderFrameHost* render_frame_host, | |
122 const GURL& url, | |
123 ui::PageTransition transition_type) { | |
124 AssertRenderFrameExists(render_frame_host); | |
125 } | |
126 | |
127 void WebContentsObserverSanityChecker::DidFailProvisionalLoad( | |
128 RenderFrameHost* render_frame_host, | |
129 const GURL& validated_url, | |
130 int error_code, | |
131 const base::string16& error_description) { | |
132 AssertRenderFrameExists(render_frame_host); | |
133 } | |
134 | |
135 void WebContentsObserverSanityChecker::DidNavigateMainFrame( | |
136 const LoadCommittedDetails& details, | |
137 const FrameNavigateParams& params) { | |
138 AssertMainFrameExists(); | |
139 } | |
140 | |
141 void WebContentsObserverSanityChecker::DidNavigateAnyFrame( | |
142 RenderFrameHost* render_frame_host, | |
143 const LoadCommittedDetails& details, | |
144 const FrameNavigateParams& params) { | |
145 AssertRenderFrameExists(render_frame_host); | |
146 } | |
147 | |
148 void WebContentsObserverSanityChecker::DocumentAvailableInMainFrame() { | |
149 AssertMainFrameExists(); | |
150 } | |
151 | |
152 void WebContentsObserverSanityChecker::DocumentOnLoadCompletedInMainFrame() { | |
153 AssertMainFrameExists(); | |
154 } | |
155 | |
156 void WebContentsObserverSanityChecker::DocumentLoadedInFrame( | |
157 RenderFrameHost* render_frame_host) { | |
158 AssertRenderFrameExists(render_frame_host); | |
159 } | |
160 | |
161 void WebContentsObserverSanityChecker::DidFinishLoad( | |
162 RenderFrameHost* render_frame_host, | |
163 const GURL& validated_url) { | |
164 AssertRenderFrameExists(render_frame_host); | |
165 } | |
166 | |
167 void WebContentsObserverSanityChecker::DidFailLoad( | |
168 RenderFrameHost* render_frame_host, | |
169 const GURL& validated_url, | |
170 int error_code, | |
171 const base::string16& error_description) { | |
172 AssertRenderFrameExists(render_frame_host); | |
173 } | |
174 | |
175 void WebContentsObserverSanityChecker::DidGetRedirectForResourceRequest( | |
176 RenderFrameHost* render_frame_host, | |
177 const ResourceRedirectDetails& details) { | |
178 AssertRenderFrameExists(render_frame_host); | |
179 } | |
180 | |
181 void WebContentsObserverSanityChecker::DidOpenRequestedURL( | |
182 WebContents* new_contents, | |
183 RenderFrameHost* source_render_frame_host, | |
184 const GURL& url, | |
185 const Referrer& referrer, | |
186 WindowOpenDisposition disposition, | |
187 ui::PageTransition transition) { | |
188 AssertRenderFrameExists(source_render_frame_host); | |
189 } | |
190 | |
191 bool WebContentsObserverSanityChecker::OnMessageReceived( | |
192 const IPC::Message& message, | |
193 RenderFrameHost* render_frame_host) { | |
194 // TODO(nasko): FrameHostMsg_RenderProcessGone is delivered to | |
195 // WebContentsObserver since RenderFrameHost allows the delegate to handle | |
196 // the message first. This shouldn't happen, but for now handle it here. | |
197 // https://crbug.com/450799 | |
198 if (message.type() == FrameHostMsg_RenderProcessGone::ID) | |
199 return false; | |
200 | |
201 #if !defined(OS_MACOSX) | |
202 // TODO(avi): Disabled because of http://crbug.com/445054 | |
203 AssertRenderFrameExists(render_frame_host); | |
204 #endif | |
205 return false; | |
206 } | |
207 | |
208 void WebContentsObserverSanityChecker::WebContentsDestroyed() { | |
209 CHECK(!web_contents_destroyed_); | |
210 web_contents_destroyed_ = true; | |
211 } | |
212 | |
213 WebContentsObserverSanityChecker::WebContentsObserverSanityChecker( | |
214 WebContents* web_contents) | |
215 : WebContentsObserver(web_contents), web_contents_destroyed_(false) { | |
216 // Prime the pump with the initial objects. | |
217 // TODO(nasko): Investigate why this is needed. | |
218 RenderViewCreated(web_contents->GetRenderViewHost()); | |
219 } | |
220 | |
221 WebContentsObserverSanityChecker::~WebContentsObserverSanityChecker() { | |
222 CHECK(web_contents_destroyed_); | |
223 } | |
224 | |
225 void WebContentsObserverSanityChecker::AssertRenderFrameExists( | |
226 RenderFrameHost* render_frame_host) { | |
227 CHECK(!web_contents_destroyed_); | |
228 std::pair<int, int> routing_pair = | |
229 std::make_pair(render_frame_host->GetProcess()->GetID(), | |
230 render_frame_host->GetRoutingID()); | |
231 | |
232 bool render_frame_created_happened = live_routes_.count(routing_pair) != 0; | |
233 bool render_frame_deleted_happened = deleted_routes_.count(routing_pair) != 0; | |
234 | |
235 CHECK(render_frame_created_happened) | |
236 << "A RenderFrameHost pointer was passed to a WebContentsObserver " | |
237 << "method, but WebContentsObserver::RenderFrameCreated was never called " | |
238 << "for that RenderFrameHost: " << Format(render_frame_host); | |
239 CHECK(!render_frame_deleted_happened) | |
240 << "A RenderFrameHost pointer was passed to a WebContentsObserver " | |
241 << "method, but WebContentsObserver::RenderFrameDeleted had already been " | |
242 << "called on that frame:" << Format(render_frame_host); | |
243 } | |
244 | |
245 void WebContentsObserverSanityChecker::AssertMainFrameExists() { | |
246 AssertRenderFrameExists(web_contents()->GetMainFrame()); | |
247 } | |
248 | |
249 std::string WebContentsObserverSanityChecker::Format( | |
250 RenderFrameHost* render_frame_host) { | |
251 return base::StringPrintf( | |
252 "(%d, %d -> %s)", render_frame_host->GetProcess()->GetID(), | |
253 render_frame_host->GetRoutingID(), | |
254 render_frame_host->GetSiteInstance()->GetSiteURL().spec().c_str()); | |
255 } | |
256 | |
257 } // namespace content | |
OLD | NEW |