1// Copyright 2013 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_view_host_factory.h"
6
7#include "chrome/browser/extensions/extension_service.h"
8#include "chrome/browser/extensions/extension_util.h"
9#include "chrome/browser/extensions/extension_view_host.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/common/url_constants.h"
13#include "extensions/browser/extension_system.h"
14#include "extensions/browser/process_manager.h"
15#include "extensions/common/manifest_handlers/incognito_info.h"
16#include "extensions/common/view_type.h"
17
18#if defined(OS_MACOSX)
19#include "chrome/browser/extensions/extension_view_host_mac.h"
20#endif
21
22namespace extensions {
23
24namespace {
25
26// Creates a new ExtensionHost with its associated view, grouping it in the
27// appropriate SiteInstance (and therefore process) based on the URL and
28// profile.
29ExtensionViewHost* CreateViewHostForExtension(const Extension* extension,
30                                              const GURL& url,
31                                              Profile* profile,
32                                              Browser* browser,
33                                              ViewType view_type) {
34  DCHECK(profile);
35  // A NULL browser may only be given for dialogs.
36  DCHECK(browser || view_type == VIEW_TYPE_EXTENSION_DIALOG);
37  ProcessManager* pm =
38      ExtensionSystem::Get(profile)->process_manager();
39  content::SiteInstance* site_instance = pm->GetSiteInstanceForURL(url);
40  ExtensionViewHost* host =
41#if defined(OS_MACOSX)
42      new ExtensionViewHostMac(extension, site_instance, url, view_type);
43#else
44      new ExtensionViewHost(extension, site_instance, url, view_type);
45#endif
46  host->CreateView(browser);
47  return host;
48}
49
50// Creates a view host for an extension in an incognito window. Returns NULL
51// if the extension is not allowed to run in incognito.
52ExtensionViewHost* CreateViewHostForIncognito(const Extension* extension,
53                                              const GURL& url,
54                                              Profile* profile,
55                                              Browser* browser,
56                                              ViewType view_type) {
57  DCHECK(extension);
58  DCHECK(profile->IsOffTheRecord());
59
60  if (!IncognitoInfo::IsSplitMode(extension)) {
61    // If it's not split-mode the host is associated with the original profile.
62    Profile* original_profile = profile->GetOriginalProfile();
63    return CreateViewHostForExtension(
64        extension, url, original_profile, browser, view_type);
65  }
66
67  // Create the host if the extension can run in incognito.
68  if (util::IsIncognitoEnabled(extension->id(), profile)) {
69    return CreateViewHostForExtension(
70        extension, url, profile, browser, view_type);
71  }
72  NOTREACHED() <<
73      "We shouldn't be trying to create an incognito extension view unless "
74      "it has been enabled for incognito.";
75  return NULL;
76}
77
78// Returns the extension associated with |url| in |profile|. Returns NULL if
79// the extension does not exist.
80const Extension* GetExtensionForUrl(Profile* profile, const GURL& url) {
81  ExtensionService* service =
82      ExtensionSystem::Get(profile)->extension_service();
83  if (!service)
84    return NULL;
85  std::string extension_id = url.host();
86  if (url.SchemeIs(content::kChromeUIScheme) &&
87      url.host() == chrome::kChromeUIExtensionInfoHost)
88    extension_id = url.path().substr(1);
89  return service->extensions()->GetByID(extension_id);
90}
91
92// Creates and initializes an ExtensionViewHost for the extension with |url|.
93ExtensionViewHost* CreateViewHost(const GURL& url,
94                                  Profile* profile,
95                                  Browser* browser,
96                                  extensions::ViewType view_type) {
97  DCHECK(profile);
98  // A NULL browser may only be given for dialogs.
99  DCHECK(browser || view_type == VIEW_TYPE_EXTENSION_DIALOG);
100
101  const Extension* extension = GetExtensionForUrl(profile, url);
102  if (!extension)
103    return NULL;
104  if (profile->IsOffTheRecord()) {
105    return CreateViewHostForIncognito(
106        extension, url, profile, browser, view_type);
107  }
108  return CreateViewHostForExtension(
109      extension, url, profile, browser, view_type);
110}
111
112}  // namespace
113
114// static
115ExtensionViewHost* ExtensionViewHostFactory::CreatePopupHost(const GURL& url,
116                                                             Browser* browser) {
117  DCHECK(browser);
118  return CreateViewHost(
119      url, browser->profile(), browser, VIEW_TYPE_EXTENSION_POPUP);
120}
121
122// static
123ExtensionViewHost* ExtensionViewHostFactory::CreateInfobarHost(
124    const GURL& url,
125    Browser* browser) {
126  DCHECK(browser);
127  return CreateViewHost(
128      url, browser->profile(), browser, VIEW_TYPE_EXTENSION_INFOBAR);
129}
130
131// static
132ExtensionViewHost* ExtensionViewHostFactory::CreateDialogHost(
133    const GURL& url,
134    Profile* profile) {
135  DCHECK(profile);
136  return CreateViewHost(url, profile, NULL, VIEW_TYPE_EXTENSION_DIALOG);
137}
138
139}  // namespace extensions
140