OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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/automation/extension_port_container.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/json/json_reader.h" | |
9 #include "base/json/json_writer.h" | |
10 #include "base/values.h" | |
11 #include "chrome/browser/automation/automation_provider.h" | |
12 #include "chrome/browser/automation/extension_automation_constants.h" | |
13 #include "chrome/browser/extensions/extension_message_service.h" | |
14 #include "chrome/browser/profiles/profile.h" | |
15 #include "chrome/common/automation_messages.h" | |
16 #include "chrome/common/extensions/extension_messages.h" | |
17 #include "content/browser/renderer_host/render_process_host.h" | |
18 #include "content/browser/renderer_host/render_view_host.h" | |
19 | |
20 // TODO(siggi): Find a more structured way to read and write JSON messages. | |
21 | |
22 namespace ext = extension_automation_constants; | |
23 | |
24 ExtensionPortContainer::ExtensionPortContainer(AutomationProvider* automation, | |
25 int tab_handle) : | |
26 automation_(automation), service_(NULL), port_id_(-1), | |
27 tab_handle_(tab_handle) { | |
28 service_ = automation_->profile()->GetExtensionMessageService(); | |
29 DCHECK(service_); | |
30 } | |
31 | |
32 ExtensionPortContainer::~ExtensionPortContainer() { | |
33 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
34 | |
35 if (port_id_ != -1) | |
36 service_->CloseChannel(port_id_); | |
37 } | |
38 | |
39 bool ExtensionPortContainer::PostResponseToExternalPort( | |
40 const std::string& message) { | |
41 return automation_->Send( | |
42 new AutomationMsg_ForwardMessageToExternalHost( | |
43 tab_handle_, message, ext::kAutomationOrigin, | |
44 ext::kAutomationPortResponseTarget)); | |
45 } | |
46 | |
47 bool ExtensionPortContainer::PostMessageToExternalPort( | |
48 const std::string& message) { | |
49 return automation_->Send( | |
50 new AutomationMsg_ForwardMessageToExternalHost( | |
51 tab_handle_, message, | |
52 ext::kAutomationOrigin, | |
53 ext::kAutomationPortRequestTarget)); | |
54 } | |
55 | |
56 void ExtensionPortContainer::PostMessageFromExternalPort( | |
57 const std::string &message) { | |
58 service_->PostMessageFromRenderer(port_id_, message); | |
59 } | |
60 | |
61 bool ExtensionPortContainer::Connect(const std::string &extension_id, | |
62 int process_id, | |
63 int routing_id, | |
64 int connection_id, | |
65 const std::string& channel_name, | |
66 const std::string& tab_json) { | |
67 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
68 | |
69 port_id_ = service_->OpenSpecialChannelToExtension( | |
70 extension_id, channel_name, tab_json, this); | |
71 if (port_id_ == -1) { | |
72 // In this case a disconnect message has been dispatched. | |
73 return false; | |
74 } | |
75 | |
76 SendConnectionResponse(connection_id, port_id_); | |
77 return true; | |
78 } | |
79 | |
80 void ExtensionPortContainer::SendConnectionResponse(int connection_id, | |
81 int port_id) { | |
82 // Compose the reply message. | |
83 scoped_ptr<DictionaryValue> msg_dict(new DictionaryValue()); | |
84 msg_dict->SetInteger(ext::kAutomationRequestIdKey, ext::CHANNEL_OPENED); | |
85 msg_dict->SetInteger(ext::kAutomationConnectionIdKey, connection_id); | |
86 msg_dict->SetInteger(ext::kAutomationPortIdKey, port_id); | |
87 | |
88 std::string msg_json; | |
89 base::JSONWriter::Write(msg_dict.get(), false, &msg_json); | |
90 | |
91 PostResponseToExternalPort(msg_json); | |
92 } | |
93 | |
94 bool ExtensionPortContainer::Send(IPC::Message *message) { | |
95 DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); | |
96 | |
97 IPC_BEGIN_MESSAGE_MAP(ExtensionPortContainer, *message) | |
98 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke) | |
99 IPC_MESSAGE_UNHANDLED_ERROR() | |
100 IPC_END_MESSAGE_MAP() | |
101 | |
102 delete message; | |
103 return true; | |
104 } | |
105 | |
106 void ExtensionPortContainer::OnExtensionMessageInvoke( | |
107 const std::string& extension_id, | |
108 const std::string& function_name, | |
109 const ListValue& args, | |
110 const GURL& event_url) { | |
111 if (function_name == ExtensionMessageService::kDispatchOnMessage) { | |
112 DCHECK_EQ(args.GetSize(), 2u); | |
113 | |
114 std::string message; | |
115 int source_port_id; | |
116 if (args.GetString(0, &message) && args.GetInteger(1, &source_port_id)) | |
117 OnExtensionHandleMessage(message, source_port_id); | |
118 } else if (function_name == ExtensionMessageService::kDispatchOnDisconnect) { | |
119 DCHECK_EQ(args.GetSize(), 2u); | |
120 int port_id; | |
121 if (args.GetInteger(0, &port_id)) | |
122 OnExtensionPortDisconnected(port_id); | |
123 } else if (function_name == ExtensionMessageService::kDispatchOnConnect) { | |
124 // Do nothing. | |
125 // TODO(siggi): implement | |
126 } else { | |
127 NOTREACHED() << function_name << " shouldn't be called."; | |
128 } | |
129 } | |
130 | |
131 void ExtensionPortContainer::OnExtensionHandleMessage( | |
132 const std::string& message, int source_port_id) { | |
133 // Compose the reply message and fire it away. | |
134 DictionaryValue msg_dict; | |
135 msg_dict.SetInteger(ext::kAutomationRequestIdKey, ext::POST_MESSAGE); | |
136 msg_dict.SetInteger(ext::kAutomationPortIdKey, port_id_); | |
137 msg_dict.SetString(ext::kAutomationMessageDataKey, message); | |
138 | |
139 std::string msg_json; | |
140 base::JSONWriter::Write(&msg_dict, false, &msg_json); | |
141 | |
142 PostMessageToExternalPort(msg_json); | |
143 } | |
144 | |
145 void ExtensionPortContainer::OnExtensionPortDisconnected(int source_port_id) { | |
146 // Compose the disconnect message and fire it away. | |
147 DictionaryValue msg_dict; | |
148 msg_dict.SetInteger(ext::kAutomationRequestIdKey, ext::CHANNEL_CLOSED); | |
149 msg_dict.SetInteger(ext::kAutomationPortIdKey, port_id_); | |
150 | |
151 std::string msg_json; | |
152 base::JSONWriter::Write(&msg_dict, false, &msg_json); | |
153 | |
154 PostMessageToExternalPort(msg_json); | |
155 } | |
156 | |
157 bool ExtensionPortContainer::InterceptMessageFromExternalHost( | |
158 const std::string& message, const std::string& origin, | |
159 const std::string& target, AutomationProvider* automation, | |
160 RenderViewHost *view_host, int tab_handle) { | |
161 if (target != ext::kAutomationPortRequestTarget) | |
162 return false; | |
163 | |
164 if (origin != ext::kAutomationOrigin) { | |
165 // TODO(siggi): Should we block the message on wrong origin? | |
166 LOG(WARNING) << "Wrong origin on automation port message " << origin; | |
167 } | |
168 | |
169 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false)); | |
170 DCHECK(message_value->IsType(Value::TYPE_DICTIONARY)); | |
171 if (!message_value->IsType(Value::TYPE_DICTIONARY)) | |
172 return true; | |
173 | |
174 DictionaryValue* message_dict = | |
175 reinterpret_cast<DictionaryValue*>(message_value.get()); | |
176 | |
177 int command = -1; | |
178 bool got_value = message_dict->GetInteger(ext::kAutomationRequestIdKey, | |
179 &command); | |
180 DCHECK(got_value); | |
181 if (!got_value) | |
182 return true; | |
183 | |
184 if (command == ext::OPEN_CHANNEL) { | |
185 // Extract the "extension_id" and "connection_id" parameters. | |
186 std::string extension_id; | |
187 got_value = message_dict->GetString(ext::kAutomationExtensionIdKey, | |
188 &extension_id); | |
189 DCHECK(got_value); | |
190 if (!got_value) | |
191 return true; | |
192 | |
193 int connection_id; | |
194 got_value = message_dict->GetInteger(ext::kAutomationConnectionIdKey, | |
195 &connection_id); | |
196 DCHECK(got_value); | |
197 if (!got_value) | |
198 return true; | |
199 | |
200 std::string channel_name; | |
201 // Channel name is optional. | |
202 message_dict->GetString(ext::kAutomationChannelNameKey, &channel_name); | |
203 | |
204 // Tab information is optional, try to retrieve it | |
205 // and re-flatten it to a string. | |
206 std::string tab_json("null"); | |
207 DictionaryValue* tab = NULL; | |
208 if (message_dict->GetDictionary(ext::kAutomationTabJsonKey, &tab)) | |
209 base::JSONWriter::Write(tab, false, &tab_json); | |
210 | |
211 int routing_id = view_host->routing_id(); | |
212 // Create the extension port and connect it. | |
213 scoped_ptr<ExtensionPortContainer> port( | |
214 new ExtensionPortContainer(automation, tab_handle)); | |
215 | |
216 int process_id = view_host->process()->id(); | |
217 if (port->Connect(extension_id, process_id, routing_id, connection_id, | |
218 channel_name, tab_json)) { | |
219 // We have a successful connection. | |
220 automation->AddPortContainer(port.release()); | |
221 } | |
222 } else if (command == ext::POST_MESSAGE) { | |
223 int port_id = -1; | |
224 got_value = message_dict->GetInteger(ext::kAutomationPortIdKey, &port_id); | |
225 DCHECK(got_value); | |
226 if (!got_value) | |
227 return true; | |
228 | |
229 std::string data; | |
230 got_value = message_dict->GetString(ext::kAutomationMessageDataKey, &data); | |
231 DCHECK(got_value); | |
232 if (!got_value) | |
233 return true; | |
234 | |
235 ExtensionPortContainer* port = automation->GetPortContainer(port_id); | |
236 DCHECK(port); | |
237 if (port) | |
238 port->PostMessageFromExternalPort(data); | |
239 } else if (command == ext::CHANNEL_CLOSED) { | |
240 int port_id = -1; | |
241 got_value = message_dict->GetInteger(ext::kAutomationPortIdKey, &port_id); | |
242 DCHECK(got_value); | |
243 if (!got_value) | |
244 return true; | |
245 | |
246 ExtensionPortContainer* port = automation->GetPortContainer(port_id); | |
247 DCHECK(port); | |
248 if (port) { | |
249 // This will delete the port and notify the other end of the disconnect. | |
250 automation->RemovePortContainer(port); | |
251 } | |
252 } else { | |
253 // We don't expect other messages here. | |
254 NOTREACHED(); | |
255 } | |
256 | |
257 return true; | |
258 } | |
OLD | NEW |