1// Copyright 2014 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 "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
6
7#include "base/strings/stringprintf.h"
8#include "content/public/browser/browser_thread.h"
9#include "content/public/browser/render_process_host.h"
10#include "content/public/common/url_constants.h"
11#include "extensions/browser/api/extensions_api_client.h"
12#include "extensions/browser/extension_registry.h"
13#include "extensions/browser/extension_system.h"
14#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h"
15#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h"
16#include "extensions/browser/process_manager.h"
17#include "extensions/common/extension_messages.h"
18#include "extensions/common/feature_switch.h"
19#include "extensions/common/guest_view/guest_view_constants.h"
20#include "extensions/strings/grit/extensions_strings.h"
21#include "ipc/ipc_message_macros.h"
22#include "net/base/url_util.h"
23
24using content::WebContents;
25
26namespace extensions {
27
28// static
29const char MimeHandlerViewGuest::Type[] = "mimehandler";
30
31// static
32GuestViewBase* MimeHandlerViewGuest::Create(
33    content::BrowserContext* browser_context,
34    int guest_instance_id) {
35  if (!extensions::FeatureSwitch::mime_handler_view()->IsEnabled())
36    return NULL;
37
38  return new MimeHandlerViewGuest(browser_context, guest_instance_id);
39}
40
41MimeHandlerViewGuest::MimeHandlerViewGuest(
42    content::BrowserContext* browser_context,
43    int guest_instance_id)
44    : GuestView<MimeHandlerViewGuest>(browser_context, guest_instance_id),
45      delegate_(ExtensionsAPIClient::Get()->CreateMimeHandlerViewGuestDelegate(
46          this)) {
47}
48
49MimeHandlerViewGuest::~MimeHandlerViewGuest() {
50}
51
52WindowController* MimeHandlerViewGuest::GetExtensionWindowController() const {
53  return NULL;
54}
55
56WebContents* MimeHandlerViewGuest::GetAssociatedWebContents() const {
57  return web_contents();
58}
59
60const char* MimeHandlerViewGuest::GetAPINamespace() const {
61  return "mimeHandlerViewGuestInternal";
62}
63
64int MimeHandlerViewGuest::GetTaskPrefix() const {
65  return IDS_EXTENSION_TASK_MANAGER_MIMEHANDLERVIEW_TAG_PREFIX;
66}
67
68// |embedder_extension_id| is empty for mime handler view.
69void MimeHandlerViewGuest::CreateWebContents(
70    const std::string& embedder_extension_id,
71    int embedder_render_process_id,
72    const GURL& embedder_site_url,
73    const base::DictionaryValue& create_params,
74    const WebContentsCreatedCallback& callback) {
75  std::string orig_mime_type;
76  create_params.GetString(mime_handler_view::kMimeType, &orig_mime_type);
77  DCHECK(!orig_mime_type.empty());
78
79  std::string extension_src;
80  create_params.GetString(mime_handler_view::kSrc, &extension_src);
81  DCHECK(!extension_src.empty());
82
83  GURL mime_handler_extension_url(extension_src);
84  if (!mime_handler_extension_url.is_valid()) {
85    callback.Run(NULL);
86    return;
87  }
88
89  const Extension* mime_handler_extension =
90      // TODO(lazyboy): Do we need handle the case where the extension is
91      // terminated (ExtensionRegistry::TERMINATED)?
92      ExtensionRegistry::Get(browser_context())->enabled_extensions().GetByID(
93          mime_handler_extension_url.host());
94  if (!mime_handler_extension) {
95    LOG(ERROR) << "Extension for mime_type not found, mime_type = "
96               << orig_mime_type;
97    callback.Run(NULL);
98    return;
99  }
100
101  ProcessManager* process_manager =
102      ExtensionSystem::Get(browser_context())->process_manager();
103  DCHECK(process_manager);
104
105  // Use the mime handler extension's SiteInstance to create the guest so it
106  // goes under the same process as the extension.
107  content::SiteInstance* guest_site_instance =
108      process_manager->GetSiteInstanceForURL(
109          Extension::GetBaseURLFromExtensionId(embedder_extension_id));
110
111  WebContents::CreateParams params(browser_context(), guest_site_instance);
112  params.guest_delegate = this;
113  callback.Run(WebContents::Create(params));
114}
115
116void MimeHandlerViewGuest::DidAttachToEmbedder() {
117  std::string src;
118  bool success = attach_params()->GetString(mime_handler_view::kSrc, &src);
119  DCHECK(success && !src.empty());
120  web_contents()->GetController().LoadURL(
121      GURL(src),
122      content::Referrer(),
123      ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
124      std::string());
125}
126
127void MimeHandlerViewGuest::DidInitialize() {
128  extension_function_dispatcher_.reset(
129      new ExtensionFunctionDispatcher(browser_context(), this));
130  if (delegate_)
131    delegate_->AttachHelpers();
132}
133
134void MimeHandlerViewGuest::ContentsZoomChange(bool zoom_in) {
135  if (delegate_)
136    delegate_->ChangeZoom(zoom_in);
137}
138
139void MimeHandlerViewGuest::HandleKeyboardEvent(
140    WebContents* source,
141    const content::NativeWebKeyboardEvent& event) {
142  if (!attached())
143    return;
144
145  // Send the keyboard events back to the embedder to reprocess them.
146  // TODO(fsamuel): This introduces the possibility of out-of-order keyboard
147  // events because the guest may be arbitrarily delayed when responding to
148  // keyboard events. In that time, the embedder may have received and processed
149  // additional key events. This needs to be fixed as soon as possible.
150  // See http://crbug.com/229882.
151  embedder_web_contents()->GetDelegate()->HandleKeyboardEvent(web_contents(),
152                                                              event);
153}
154
155bool MimeHandlerViewGuest::OnMessageReceived(const IPC::Message& message) {
156  bool handled = true;
157  IPC_BEGIN_MESSAGE_MAP(MimeHandlerViewGuest, message)
158    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
159    IPC_MESSAGE_UNHANDLED(handled = false)
160  IPC_END_MESSAGE_MAP()
161  return handled;
162}
163
164void MimeHandlerViewGuest::OnRequest(
165    const ExtensionHostMsg_Request_Params& params) {
166  if (extension_function_dispatcher_) {
167    extension_function_dispatcher_->Dispatch(
168        params, web_contents()->GetRenderViewHost());
169  }
170}
171
172}  // namespace extensions
173