frame_navigation_state.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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
11namespace extensions {
12
13namespace {
14
15// URL schemes for which we'll send events.
16const char* kValidSchemes[] = {
17  chrome::kChromeUIScheme,
18  content::kHttpScheme,
19  content::kHttpsScheme,
20  chrome::kFileScheme,
21  content::kFtpScheme,
22  content::kJavaScriptScheme,
23  chrome::kDataScheme,
24  chrome::kFileSystemScheme,
25};
26
27}  // namespace
28
29FrameNavigationState::FrameID::FrameID()
30    : frame_num(-1),
31      render_view_host(NULL) {
32}
33
34FrameNavigationState::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
41bool 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
48bool 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
54bool FrameNavigationState::FrameID::operator!=(
55    const FrameNavigationState::FrameID& other) const {
56  return !(*this == other);
57}
58
59FrameNavigationState::FrameState::FrameState() {}
60
61// static
62bool FrameNavigationState::allow_extension_scheme_ = false;
63
64FrameNavigationState::FrameNavigationState() {}
65
66FrameNavigationState::~FrameNavigationState() {}
67
68bool 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
78bool 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() == content::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
93void 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(content::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
118void 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
141void 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
159void 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
168bool 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
174GURL 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
186bool 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
193FrameNavigationState::FrameID FrameNavigationState::GetMainFrameID() const {
194  return main_frame_id_;
195}
196
197FrameNavigationState::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
209void 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
214bool 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
221void 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
226bool 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
233void 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
238bool 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
245void 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
252bool 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
259void 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
264bool 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