1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h" 6 7 #include "base/logging.h" 8 #include "chrome/common/url_constants.h" 9 #include "extensions/common/constants.h" 10 11 namespace extensions { 12 13 namespace { 14 15 // URL schemes for which we'll send events. 16 const char* kValidSchemes[] = { 17 content::kChromeUIScheme, 18 url::kHttpScheme, 19 url::kHttpsScheme, 20 url::kFileScheme, 21 url::kFtpScheme, 22 url::kJavaScriptScheme, 23 url::kDataScheme, 24 url::kFileSystemScheme, 25 }; 26 27 } // namespace 28 29 FrameNavigationState::FrameID::FrameID() 30 : frame_num(-1), 31 render_view_host(NULL) { 32 } 33 34 FrameNavigationState::FrameID::FrameID( 35 int64 frame_num, 36 content::RenderViewHost* render_view_host) 37 : frame_num(frame_num), 38 render_view_host(render_view_host) { 39 } 40 41 bool FrameNavigationState::FrameID::operator<( 42 const FrameNavigationState::FrameID& other) const { 43 return frame_num < other.frame_num || 44 (frame_num == other.frame_num && 45 render_view_host < other.render_view_host); 46 } 47 48 bool FrameNavigationState::FrameID::operator==( 49 const FrameNavigationState::FrameID& other) const { 50 return frame_num == other.frame_num && 51 render_view_host == other.render_view_host; 52 } 53 54 bool FrameNavigationState::FrameID::operator!=( 55 const FrameNavigationState::FrameID& other) const { 56 return !(*this == other); 57 } 58 59 FrameNavigationState::FrameState::FrameState() {} 60 61 // static 62 bool FrameNavigationState::allow_extension_scheme_ = false; 63 64 FrameNavigationState::FrameNavigationState() {} 65 66 FrameNavigationState::~FrameNavigationState() {} 67 68 bool FrameNavigationState::CanSendEvents(FrameID frame_id) const { 69 FrameIdToStateMap::const_iterator frame_state = 70 frame_state_map_.find(frame_id); 71 if (frame_state == frame_state_map_.end() || 72 frame_state->second.error_occurred) { 73 return false; 74 } 75 return IsValidUrl(frame_state->second.url); 76 } 77 78 bool FrameNavigationState::IsValidUrl(const GURL& url) const { 79 for (unsigned i = 0; i < arraysize(kValidSchemes); ++i) { 80 if (url.scheme() == kValidSchemes[i]) 81 return true; 82 } 83 // Allow about:blank and about:srcdoc. 84 if (url.spec() == url::kAboutBlankURL || 85 url.spec() == content::kAboutSrcDocURL) { 86 return true; 87 } 88 if (allow_extension_scheme_ && url.scheme() == extensions::kExtensionScheme) 89 return true; 90 return false; 91 } 92 93 void FrameNavigationState::TrackFrame(FrameID frame_id, 94 FrameID parent_frame_id, 95 const GURL& url, 96 bool is_main_frame, 97 bool is_error_page, 98 bool is_iframe_srcdoc) { 99 FrameState& frame_state = frame_state_map_[frame_id]; 100 frame_state.error_occurred = is_error_page; 101 frame_state.url = url; 102 frame_state.is_main_frame = is_main_frame; 103 frame_state.is_iframe_srcdoc = is_iframe_srcdoc; 104 DCHECK(!is_iframe_srcdoc || url == GURL(url::kAboutBlankURL)); 105 frame_state.is_navigating = true; 106 frame_state.is_committed = false; 107 frame_state.is_server_redirected = false; 108 frame_state.is_parsing = true; 109 if (!is_main_frame) { 110 frame_state.parent_frame_num = parent_frame_id.frame_num; 111 } else { 112 DCHECK(parent_frame_id.frame_num == -1); 113 frame_state.parent_frame_num = -1; 114 } 115 frame_ids_.insert(frame_id); 116 } 117 118 void FrameNavigationState::FrameDetached(FrameID frame_id) { 119 FrameIdToStateMap::const_iterator frame_state = 120 frame_state_map_.find(frame_id); 121 if (frame_state == frame_state_map_.end()) 122 return; 123 if (frame_id == main_frame_id_) 124 main_frame_id_ = FrameID(); 125 frame_state_map_.erase(frame_id); 126 frame_ids_.erase(frame_id); 127 #ifndef NDEBUG 128 // Check that the deleted frame was not the parent of any other frame. WebKit 129 // should always detach frames starting with the children. 130 for (FrameIdToStateMap::const_iterator frame = frame_state_map_.begin(); 131 frame != frame_state_map_.end(); ++frame) { 132 if (frame->first.render_view_host != frame_id.render_view_host) 133 continue; 134 if (frame->second.parent_frame_num != frame_id.frame_num) 135 continue; 136 NOTREACHED(); 137 } 138 #endif 139 } 140 141 void FrameNavigationState::StopTrackingFramesInRVH( 142 content::RenderViewHost* render_view_host, 143 FrameID id_to_skip) { 144 for (std::set<FrameID>::iterator frame = frame_ids_.begin(); 145 frame != frame_ids_.end();) { 146 if (frame->render_view_host != render_view_host || *frame == id_to_skip) { 147 ++frame; 148 continue; 149 } 150 FrameID frame_id = *frame; 151 ++frame; 152 if (frame_id == main_frame_id_) 153 main_frame_id_ = FrameID(); 154 frame_state_map_.erase(frame_id); 155 frame_ids_.erase(frame_id); 156 } 157 } 158 159 void FrameNavigationState::UpdateFrame(FrameID frame_id, const GURL& url) { 160 FrameIdToStateMap::iterator frame_state = frame_state_map_.find(frame_id); 161 if (frame_state == frame_state_map_.end()) { 162 NOTREACHED(); 163 return; 164 } 165 frame_state->second.url = url; 166 } 167 168 bool FrameNavigationState::IsValidFrame(FrameID frame_id) const { 169 FrameIdToStateMap::const_iterator frame_state = 170 frame_state_map_.find(frame_id); 171 return (frame_state != frame_state_map_.end()); 172 } 173 174 GURL FrameNavigationState::GetUrl(FrameID frame_id) const { 175 FrameIdToStateMap::const_iterator frame_state = 176 frame_state_map_.find(frame_id); 177 if (frame_state == frame_state_map_.end()) { 178 NOTREACHED(); 179 return GURL(); 180 } 181 if (frame_state->second.is_iframe_srcdoc) 182 return GURL(content::kAboutSrcDocURL); 183 return frame_state->second.url; 184 } 185 186 bool FrameNavigationState::IsMainFrame(FrameID frame_id) const { 187 FrameIdToStateMap::const_iterator frame_state = 188 frame_state_map_.find(frame_id); 189 return (frame_state != frame_state_map_.end() && 190 frame_state->second.is_main_frame); 191 } 192 193 FrameNavigationState::FrameID FrameNavigationState::GetMainFrameID() const { 194 return main_frame_id_; 195 } 196 197 FrameNavigationState::FrameID FrameNavigationState::GetParentFrameID( 198 FrameID frame_id) const { 199 FrameIdToStateMap::const_iterator frame_state = 200 frame_state_map_.find(frame_id); 201 if (frame_state == frame_state_map_.end()) { 202 NOTREACHED(); 203 return FrameID(); 204 } 205 return FrameID(frame_state->second.parent_frame_num, 206 frame_id.render_view_host); 207 } 208 209 void FrameNavigationState::SetErrorOccurredInFrame(FrameID frame_id) { 210 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); 211 frame_state_map_[frame_id].error_occurred = true; 212 } 213 214 bool FrameNavigationState::GetErrorOccurredInFrame(FrameID frame_id) const { 215 FrameIdToStateMap::const_iterator frame_state = 216 frame_state_map_.find(frame_id); 217 return (frame_state == frame_state_map_.end() || 218 frame_state->second.error_occurred); 219 } 220 221 void FrameNavigationState::SetNavigationCompleted(FrameID frame_id) { 222 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); 223 frame_state_map_[frame_id].is_navigating = false; 224 } 225 226 bool FrameNavigationState::GetNavigationCompleted(FrameID frame_id) const { 227 FrameIdToStateMap::const_iterator frame_state = 228 frame_state_map_.find(frame_id); 229 return (frame_state == frame_state_map_.end() || 230 !frame_state->second.is_navigating); 231 } 232 233 void FrameNavigationState::SetParsingFinished(FrameID frame_id) { 234 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); 235 frame_state_map_[frame_id].is_parsing = false; 236 } 237 238 bool FrameNavigationState::GetParsingFinished(FrameID frame_id) const { 239 FrameIdToStateMap::const_iterator frame_state = 240 frame_state_map_.find(frame_id); 241 return (frame_state == frame_state_map_.end() || 242 !frame_state->second.is_parsing); 243 } 244 245 void FrameNavigationState::SetNavigationCommitted(FrameID frame_id) { 246 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); 247 frame_state_map_[frame_id].is_committed = true; 248 if (frame_state_map_[frame_id].is_main_frame) 249 main_frame_id_ = frame_id; 250 } 251 252 bool FrameNavigationState::GetNavigationCommitted(FrameID frame_id) const { 253 FrameIdToStateMap::const_iterator frame_state = 254 frame_state_map_.find(frame_id); 255 return (frame_state != frame_state_map_.end() && 256 frame_state->second.is_committed); 257 } 258 259 void FrameNavigationState::SetIsServerRedirected(FrameID frame_id) { 260 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); 261 frame_state_map_[frame_id].is_server_redirected = true; 262 } 263 264 bool FrameNavigationState::GetIsServerRedirected(FrameID frame_id) const { 265 FrameIdToStateMap::const_iterator frame_state = 266 frame_state_map_.find(frame_id); 267 return (frame_state != frame_state_map_.end() && 268 frame_state->second.is_server_redirected); 269 } 270 271 } // namespace extensions 272