Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: chrome/browser/extensions/api/messaging/native_message_process_host.cc

Issue 10818013: Native Messaging! (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: nit Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/messaging/native_message_process_host.h"
6
7 #include "base/file_path.h"
8 #include "base/logging.h"
9 #include "base/path_service.h"
10 #include "base/pickle.h"
11 #include "base/process_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
14 #include "chrome/common/chrome_paths.h"
15 #include "chrome/common/chrome_version_info.h"
16 #include "chrome/common/extensions/features/feature.h"
17 #include "content/public/common/result_codes.h"
18
19 namespace {
20
21 const int kExitTimeoutMS = 5000;
22 const uint32 kMaxMessageDataLength = 10 * 1024 * 1024;
23 const char kNativeHostsDirectoryName[] = "Native Hosts";
24
25 } // namespace
26
27 namespace extensions {
28
29 NativeMessageProcessHost::NativeMessageProcessHost(
30 base::WeakPtr<Client> weak_client_ui,
31 int destination_port,
32 base::ProcessHandle native_process_handle,
33 FileHandle read_file,
34 FileHandle write_file,
35 bool is_send_message)
36 : weak_client_ui_(weak_client_ui),
37 destination_port_(destination_port),
38 native_process_handle_(native_process_handle),
39 read_file_(read_file),
40 write_file_(write_file),
41 scoped_read_file_(&read_file_),
42 scoped_write_file_(&write_file_),
43 is_send_message_(is_send_message) {
44 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
45 InitIO();
46 }
47
48 NativeMessageProcessHost::~NativeMessageProcessHost() {
49 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
50 // Give the process some time to shutdown, then try and kill it.
51 content::BrowserThread::PostDelayedTask(
52 content::BrowserThread::FILE,
53 FROM_HERE,
54 base::Bind(base::IgnoreResult(&base::KillProcess),
55 native_process_handle_,
56 content::RESULT_CODE_NORMAL_EXIT,
57 false /* don't wait for exit */),
58 base::TimeDelta::FromMilliseconds(kExitTimeoutMS));
59 }
60
61 // static
62 void NativeMessageProcessHost::Create(base::WeakPtr<Client> weak_client_ui,
63 const std::string& native_app_name,
64 const std::string& connection_message,
65 int destination_port,
66 MessageType type,
67 CreateCallback callback) {
68 NativeProcessLauncher launcher;
69 CreateWithLauncher(weak_client_ui, native_app_name, connection_message,
70 destination_port, type, callback, launcher);
71 }
72
73 // static
74 void NativeMessageProcessHost::CreateWithLauncher(
75 base::WeakPtr<Client> weak_client_ui,
76 const std::string& native_app_name,
77 const std::string& connection_message,
78 int destination_port,
79 MessageType type,
80 CreateCallback callback,
81 const NativeProcessLauncher& launcher) {
82 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
83 DCHECK(type == TYPE_SEND_MESSAGE_REQUEST || type == TYPE_CONNECT);
84
85 ScopedHost process;
86 if (Feature::GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV) {
87 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
88 base::Bind(callback,
89 base::Passed(&process)));
90 return;
91 }
92
93 FilePath native_host_program;
94 FilePath native_host_registry;
95 CHECK(PathService::Get(chrome::DIR_USER_DATA, &native_host_registry));
96 native_host_registry =
97 native_host_registry.AppendASCII(kNativeHostsDirectoryName);
98 native_host_program = native_host_registry.AppendASCII(native_app_name);
99
100 // Make sure that the client is not trying to invoke something outside of the
101 // proper directory. Eg. '../../dangerous_something.exe'.
102 if (!file_util::ContainsPath(native_host_registry, native_host_program)) {
103 LOG(ERROR) << "Could not find native host: " << native_app_name;
104 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
105 base::Bind(callback,
106 base::Passed(&process)));
107 return;
108 }
109
110 FileHandle read_handle;
111 FileHandle write_handle;
112 base::ProcessHandle native_process_handle;
113
114 if (!launcher.LaunchNativeProcess(native_host_program,
115 &native_process_handle,
116 &read_handle,
117 &write_handle)) {
118 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
119 base::Bind(callback,
120 base::Passed(&process)));
121 return;
122 }
123
124 process.reset(new NativeMessageProcessHost(
125 weak_client_ui, destination_port, native_process_handle, read_handle,
126 write_handle, type == TYPE_SEND_MESSAGE_REQUEST));
127
128 process->SendImpl(type, connection_message);
129
130 content::BrowserThread::PostTask(
131 content::BrowserThread::UI, FROM_HERE,
132 base::Bind(callback, base::Passed(&process)));
133 }
134
135 void NativeMessageProcessHost::SendImpl(MessageType type,
136 const std::string& json) {
137 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
138
139 // Make sure that the process has not died.
140 if (base::GetTerminationStatus(native_process_handle_, NULL) !=
141 base::TERMINATION_STATUS_STILL_RUNNING) {
142 // Notify the message service that the channel should close.
143 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
144 base::Bind(&Client::CloseChannel, weak_client_ui_,
145 destination_port_, true));
146 }
147
148 WriteMessage(type, json);
149 }
150
151 bool NativeMessageProcessHost::WriteMessage(MessageType type,
152 const std::string& message) {
153 Pickle pickle;
154
155 // Pickles will always pad bytes to 32-bit alignment, so just use a unit32.
156 pickle.WriteUInt32(type);
157
158 // Pickles write the length of a string before it as a uint32.
159 pickle.WriteString(message);
160
161 // Make sure that the pickle doesn't do any unexpected padding.
162 CHECK(8 + message.length() == pickle.payload_size());
163
164 if (!WriteData(write_file_, const_cast<const Pickle*>(&pickle)->payload(),
165 pickle.payload_size())) {
166 LOG(ERROR) << "Error writing message to the native client.";
167 return false;
168 }
169
170 return true;
171 }
172
173 bool NativeMessageProcessHost::ReadMessage(MessageType* type,
174 std::string* message) {
175 // Read the type (uint32) and length (uint32).
176 char message_meta_data[8];
177 if (!ReadData(read_file_, message_meta_data, 8)) {
178 LOG(ERROR) << "Error reading the message type and length.";
179 return false;
180 }
181
182 Pickle pickle;
183 pickle.WriteBytes(message_meta_data, 8);
184 PickleIterator pickle_it(pickle);
185 uint32 uint_type;
186 uint32 data_length;
187 if (!pickle_it.ReadUInt32(&uint_type) ||
188 !pickle_it.ReadUInt32(&data_length)) {
189 LOG(ERROR) << "Error getting the message type and length from the pickle.";
190 return false;
191 }
192
193 if (uint_type >= NUM_MESSAGE_TYPES) {
194 LOG(ERROR) << type << " is not a valid message type.";
195 return false;
196 }
197
198 if ((is_send_message_ && (uint_type != TYPE_SEND_MESSAGE_RESPONSE)) ||
199 (!is_send_message_ && (uint_type != TYPE_CONNECT_MESSAGE))) {
200 LOG(ERROR) << "Recieved a message of type " << uint_type << ". "
201 << "Expecting a message of type "
202 << (is_send_message_ ? TYPE_SEND_MESSAGE_RESPONSE :
203 TYPE_CONNECT_MESSAGE);
204 return false;
205 }
206 *type = static_cast<MessageType>(uint_type);
207
208 if (data_length > kMaxMessageDataLength) {
209 LOG(ERROR) << data_length << " is too large for the length of a message. "
210 << "Max message size is " << kMaxMessageDataLength;
211 return false;
212 }
213
214 message->resize(data_length, '\0');
215 if (!ReadData(read_file_, &(*message)[0], data_length)) {
216 LOG(ERROR) << "Error reading the json data.";
217 return false;
218 }
219
220 return true;
221 }
222
223 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698