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

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

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

Powered by Google App Engine
This is Rietveld 408576698