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

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

Powered by Google App Engine
This is Rietveld 408576698