extension_tab_util.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/extension_tab_util.h"
6
7#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
8#include "chrome/browser/extensions/tab_helper.h"
9#include "chrome/browser/extensions/window_controller.h"
10#include "chrome/browser/net/url_fixer_upper.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/sessions/session_id.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/browser_finder.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/browser/ui/browser_tabstrip.h"
17#include "chrome/browser/ui/browser_window.h"
18#include "chrome/browser/ui/tab_contents/tab_contents.h"
19#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
20#include "chrome/browser/ui/tabs/tab_strip_model.h"
21#include "chrome/common/extensions/extension.h"
22#include "chrome/common/extensions/extension_manifest_constants.h"
23#include "chrome/common/extensions/permissions/api_permission.h"
24#include "chrome/common/url_constants.h"
25#include "content/public/browser/favicon_status.h"
26#include "content/public/browser/navigation_entry.h"
27#include "content/public/browser/web_contents.h"
28#include "googleurl/src/gurl.h"
29
30namespace keys = extensions::tabs_constants;
31
32using content::NavigationEntry;
33using content::WebContents;
34using extensions::APIPermission;
35using extensions::Extension;
36
37int ExtensionTabUtil::GetWindowId(const Browser* browser) {
38  return browser->session_id().id();
39}
40
41int ExtensionTabUtil::GetWindowIdOfTabStripModel(
42    const TabStripModel* tab_strip_model) {
43  for (BrowserList::const_iterator it = BrowserList::begin();
44       it != BrowserList::end(); ++it) {
45    if ((*it)->tab_strip_model() == tab_strip_model)
46      return GetWindowId(*it);
47  }
48  return -1;
49}
50
51int ExtensionTabUtil::GetTabId(const WebContents* web_contents) {
52  return SessionID::IdForTab(web_contents);
53}
54
55std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
56  return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
57}
58
59int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) {
60  return SessionID::IdForWindowContainingTab(web_contents);
61}
62
63DictionaryValue* ExtensionTabUtil::CreateTabValue(
64    const WebContents* contents,
65    TabStripModel* tab_strip,
66    int tab_index,
67    const Extension* extension) {
68  // Only add privacy-sensitive data if the requesting extension has the tabs
69  // permission.
70  bool has_permission = extension && extension->HasAPIPermissionForTab(
71      GetTabId(contents), APIPermission::kTab);
72
73  return CreateTabValue(contents, tab_strip, tab_index,
74                        has_permission ? INCLUDE_PRIVACY_SENSITIVE_FIELDS :
75                            OMIT_PRIVACY_SENSITIVE_FIELDS);
76}
77
78ListValue* ExtensionTabUtil::CreateTabList(
79    const Browser* browser,
80    const Extension* extension) {
81  ListValue* tab_list = new ListValue();
82  TabStripModel* tab_strip = browser->tab_strip_model();
83  for (int i = 0; i < tab_strip->count(); ++i) {
84    tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i),
85                                    tab_strip,
86                                    i,
87                                    extension));
88  }
89
90  return tab_list;
91}
92
93DictionaryValue* ExtensionTabUtil::CreateTabValue(
94    const WebContents* contents,
95    TabStripModel* tab_strip,
96    int tab_index,
97    IncludePrivacySensitiveFields include_privacy_sensitive_fields) {
98  if (!tab_strip)
99    ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
100
101  DictionaryValue* result = new DictionaryValue();
102  bool is_loading = contents->IsLoading();
103  result->SetInteger(keys::kIdKey, GetTabId(contents));
104  result->SetInteger(keys::kIndexKey, tab_index);
105  result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents));
106  result->SetString(keys::kStatusKey, GetTabStatusText(is_loading));
107  result->SetBoolean(keys::kActiveKey,
108                     tab_strip && tab_index == tab_strip->active_index());
109  result->SetBoolean(keys::kSelectedKey,
110                     tab_strip && tab_index == tab_strip->active_index());
111  result->SetBoolean(keys::kHighlightedKey,
112                   tab_strip && tab_strip->IsTabSelected(tab_index));
113  result->SetBoolean(keys::kPinnedKey,
114                     tab_strip && tab_strip->IsTabPinned(tab_index));
115  result->SetBoolean(keys::kIncognitoKey,
116                     contents->GetBrowserContext()->IsOffTheRecord());
117
118  if (include_privacy_sensitive_fields == INCLUDE_PRIVACY_SENSITIVE_FIELDS) {
119    result->SetString(keys::kUrlKey, contents->GetURL().spec());
120    result->SetString(keys::kTitleKey, contents->GetTitle());
121    if (!is_loading) {
122      NavigationEntry* entry = contents->GetController().GetActiveEntry();
123      if (entry && entry->GetFavicon().valid)
124        result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
125    }
126  }
127
128  if (tab_strip) {
129    WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index);
130    if (opener)
131      result->SetInteger(keys::kOpenerTabIdKey, GetTabId(opener));
132  }
133
134  return result;
135}
136
137bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents,
138                                        TabStripModel** tab_strip_model,
139                                        int* tab_index) {
140  DCHECK(web_contents);
141  DCHECK(tab_strip_model);
142  DCHECK(tab_index);
143
144  for (BrowserList::const_iterator it = BrowserList::begin();
145      it != BrowserList::end(); ++it) {
146    TabStripModel* tab_strip = (*it)->tab_strip_model();
147    int index = tab_strip->GetIndexOfWebContents(web_contents);
148    if (index != -1) {
149      *tab_strip_model = tab_strip;
150      *tab_index = index;
151      return true;
152    }
153  }
154
155  return false;
156}
157
158bool ExtensionTabUtil::GetDefaultTab(Browser* browser,
159                                     WebContents** contents,
160                                     int* tab_id) {
161  DCHECK(browser);
162  DCHECK(contents);
163
164  *contents = chrome::GetActiveWebContents(browser);
165  if (*contents) {
166    if (tab_id)
167      *tab_id = GetTabId(*contents);
168    return true;
169  }
170
171  return false;
172}
173
174bool ExtensionTabUtil::GetTabById(int tab_id,
175                                  Profile* profile,
176                                  bool include_incognito,
177                                  Browser** browser,
178                                  TabStripModel** tab_strip,
179                                  WebContents** contents,
180                                  int* tab_index) {
181  Profile* incognito_profile =
182      include_incognito && profile->HasOffTheRecordProfile() ?
183          profile->GetOffTheRecordProfile() : NULL;
184  for (BrowserList::const_iterator iter = BrowserList::begin();
185       iter != BrowserList::end(); ++iter) {
186    Browser* target_browser = *iter;
187    if (target_browser->profile() == profile ||
188        target_browser->profile() == incognito_profile) {
189      TabStripModel* target_tab_strip = target_browser->tab_strip_model();
190      for (int i = 0; i < target_tab_strip->count(); ++i) {
191        WebContents* target_contents = target_tab_strip->GetWebContentsAt(i);
192        if (SessionID::IdForTab(target_contents) == tab_id) {
193          if (browser)
194            *browser = target_browser;
195          if (tab_strip)
196            *tab_strip = target_tab_strip;
197          if (contents)
198            *contents = target_contents;
199          if (tab_index)
200            *tab_index = i;
201          return true;
202        }
203      }
204    }
205  }
206  return false;
207}
208
209GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string,
210    const extensions::Extension* extension) {
211  GURL url = GURL(url_string);
212  if (!url.is_valid())
213    url = extension->GetResourceURL(url_string);
214
215  return url;
216}
217
218bool ExtensionTabUtil::IsCrashURL(const GURL& url) {
219  // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
220  GURL fixed_url =
221      URLFixerUpper::FixupURL(url.possibly_invalid_spec(), std::string());
222  return (fixed_url.SchemeIs(chrome::kChromeUIScheme) &&
223          (fixed_url.host() == chrome::kChromeUIBrowserCrashHost ||
224           fixed_url.host() == chrome::kChromeUICrashHost));
225}
226
227void ExtensionTabUtil::CreateTab(WebContents* web_contents,
228                                 const std::string& extension_id,
229                                 WindowOpenDisposition disposition,
230                                 const gfx::Rect& initial_pos,
231                                 bool user_gesture) {
232  Profile* profile =
233      Profile::FromBrowserContext(web_contents->GetBrowserContext());
234  Browser* browser = browser::FindTabbedBrowserDeprecated(profile, false);
235  const bool browser_created = !browser;
236  if (!browser)
237    browser = new Browser(Browser::CreateParams(profile));
238  TabContents* tab_contents =
239      TabContents::Factory::CreateTabContents(web_contents);
240  chrome::NavigateParams params(browser, tab_contents);
241
242  // The extension_app_id parameter ends up as app_name in the Browser
243  // which causes the Browser to return true for is_app().  This affects
244  // among other things, whether the location bar gets displayed.
245  // TODO(mpcomplete): This seems wrong. What if the extension content is hosted
246  // in a tab?
247  if (disposition == NEW_POPUP)
248    params.extension_app_id = extension_id;
249
250  params.disposition = disposition;
251  params.window_bounds = initial_pos;
252  params.window_action = chrome::NavigateParams::SHOW_WINDOW;
253  params.user_gesture = user_gesture;
254  chrome::Navigate(&params);
255
256  // Close the browser if chrome::Navigate created a new one.
257  if (browser_created && (browser != params.browser))
258    browser->window()->Close();
259}
260
261// static
262void ExtensionTabUtil::ForEachTab(
263    const base::Callback<void(WebContents*)>& callback) {
264  for (TabContentsIterator iterator; !iterator.done(); ++iterator)
265    callback.Run((*iterator)->web_contents());
266}
267
268// static
269extensions::WindowController* ExtensionTabUtil::GetWindowControllerOfTab(
270    const WebContents* web_contents) {
271  Browser* browser = browser::FindBrowserWithWebContents(web_contents);
272  if (browser != NULL)
273    return browser->extension_window_controller();
274
275  return NULL;
276}
277