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
FrameID()29 FrameNavigationState::FrameID::FrameID()
30 : frame_num(-1),
31 render_view_host(NULL) {
32 }
33
FrameID(int64 frame_num,content::RenderViewHost * render_view_host)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
operator <(const FrameNavigationState::FrameID & other) const41 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
operator ==(const FrameNavigationState::FrameID & other) const48 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
operator !=(const FrameNavigationState::FrameID & other) const54 bool FrameNavigationState::FrameID::operator!=(
55 const FrameNavigationState::FrameID& other) const {
56 return !(*this == other);
57 }
58
FrameState()59 FrameNavigationState::FrameState::FrameState() {}
60
61 // static
62 bool FrameNavigationState::allow_extension_scheme_ = false;
63
FrameNavigationState()64 FrameNavigationState::FrameNavigationState() {}
65
~FrameNavigationState()66 FrameNavigationState::~FrameNavigationState() {}
67
CanSendEvents(FrameID frame_id) const68 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
IsValidUrl(const GURL & url) const78 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
TrackFrame(FrameID frame_id,FrameID parent_frame_id,const GURL & url,bool is_main_frame,bool is_error_page,bool is_iframe_srcdoc)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
FrameDetached(FrameID frame_id)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
StopTrackingFramesInRVH(content::RenderViewHost * render_view_host,FrameID id_to_skip)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
UpdateFrame(FrameID frame_id,const GURL & url)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
IsValidFrame(FrameID frame_id) const168 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
GetUrl(FrameID frame_id) const174 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
IsMainFrame(FrameID frame_id) const186 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
GetMainFrameID() const193 FrameNavigationState::FrameID FrameNavigationState::GetMainFrameID() const {
194 return main_frame_id_;
195 }
196
GetParentFrameID(FrameID frame_id) const197 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
SetErrorOccurredInFrame(FrameID frame_id)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
GetErrorOccurredInFrame(FrameID frame_id) const214 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
SetNavigationCompleted(FrameID frame_id)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
GetNavigationCompleted(FrameID frame_id) const226 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
SetParsingFinished(FrameID frame_id)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
GetParsingFinished(FrameID frame_id) const238 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
SetNavigationCommitted(FrameID frame_id)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
GetNavigationCommitted(FrameID frame_id) const252 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
SetIsServerRedirected(FrameID frame_id)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
GetIsServerRedirected(FrameID frame_id) const264 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