| 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 |