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

Side by Side Diff: chrome/browser/extensions/api/native_message/native_thread_delegate.cc

Issue 10818013: Native Messaging! (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 5 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/native_message/native_thread_delegate.h"
6
7 #include <unistd.h>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/process_util.h"
16 #include "base/values.h"
17 #include "content/public/browser/browser_thread.h"
18
19 namespace {
20
21 // TODO(eriq): Figure out good values for these constants.
22 const int kExitTimeoutMS = 100;
23 const uint32_t kMaxMessageDataLength = 4096;
24
25 } // namespace
26
27 NativeThreadDelegate::NativeThreadDelegate(const DictionaryValue* data,
28 scoped_ptr<FilePath> path,
29 ExecutionFinishedCallback callback)
30 : message_data_(data),
31 path_(path.release()),
32 callback_(callback) {
33 }
34
35 NativeThreadDelegate::~NativeThreadDelegate() {
36 }
37
38 void NativeThreadDelegate::Run() {
39 base::FileHandleMappingVector fd_map;
40
41 int read_pipe_fds[2];
42 if (HANDLE_EINTR(pipe(read_pipe_fds)) != 0) {
43 Finish(false, std::string("Bad read pipe"), scoped_ptr<DictionaryValue>());
44 return;
45 }
46 file_util::ScopedFD read_pipe_read_fd(&read_pipe_fds[0]);
47 file_util::ScopedFD read_pipe_write_fd(&read_pipe_fds[1]);
Matt Perry 2012/07/23 23:47:03 A lot of this stuff is posix only, in which case t
48 fd_map.push_back(std::make_pair(*read_pipe_write_fd, STDOUT_FILENO));
49
50 int write_pipe_fds[2];
51 if (HANDLE_EINTR(pipe(write_pipe_fds)) != 0) {
52 Finish(false, std::string("Bad write pipe"),
53 scoped_ptr<DictionaryValue>());
54 return;
55 }
56 file_util::ScopedFD write_pipe_read_fd(&write_pipe_fds[0]);
57 file_util::ScopedFD write_pipe_write_fd(&write_pipe_fds[1]);
58 fd_map.push_back(std::make_pair(*write_pipe_read_fd, STDIN_FILENO));
59
60 CommandLine line(*path_);
61 base::LaunchOptions options;
62 options.fds_to_remap = &fd_map;
63 if (!base::LaunchProcess(line, options, &handle_)) {
64 Finish(false, std::string("Error launching process"),
65 scoped_ptr<DictionaryValue>());
66 return;
67 }
68
69 // We will not be reading from the write pipe, nor writing from the read pipe.
70 write_pipe_read_fd.reset();
71 read_pipe_write_fd.reset();
72
73 if (!WriteMessage(TYPE_SEND_MESSAGE_REQUEST, *write_pipe_write_fd)) {
74 Finish(false, std::string("Error sending message to the native app"),
75 scoped_ptr<DictionaryValue>());
76 return;
77 }
78 write_pipe_write_fd.reset();
79
80 MessageType response_type;
81 DictionaryValue* response_data;
82 if (!ReadMessage(&response_type, &response_data, *read_pipe_read_fd)) {
83 Finish(false, std::string("Error reading"), scoped_ptr<DictionaryValue>());
84 return;
85 }
86 scoped_ptr<DictionaryValue> scoped_response_data(response_data);
87 read_pipe_read_fd.reset();
88
89 if (response_type != TYPE_SEND_MESSAGE_RESPONSE) {
90 Finish(false, std::string("Incorrect response type."),
91 scoped_ptr<DictionaryValue>());
92 return;
93 }
94
95 Finish(true, std::string(), scoped_response_data.Pass());
96 exit();
97 }
98
99 bool NativeThreadDelegate::WriteMessage(MessageType type,
100 int fd) {
101 std::string json_data;
102 base::JSONWriter::Write(message_data_, &json_data);
103 uint32_t json_length = json_data.length();
104
105 // Write the message type.
106 if (HANDLE_EINTR(write(fd, &type, 1)) < 1) {
Matt Perry 2012/07/23 23:47:03 base::Pickle might be a good cross-platform altern
107 LOG(ERROR) << "Error writing message type to the native client.";
108 return false;
109 }
110
111 // Write the json data length.
112 if (HANDLE_EINTR(write(fd, &json_length, 4)) < 1) {
113 LOG(ERROR) << "Error writing json data length to the native client.";
114 return false;
115 }
116
117 // Write the json data.
118 if (HANDLE_EINTR(write(fd, json_data.data(), json_length)) < 1) {
119 LOG(ERROR) << "Error writing json data to the native client.";
120 return false;
121 }
122
123 return true;
124 }
125
126 bool NativeThreadDelegate::ReadMessage(MessageType* type,
127 DictionaryValue** data,
128 int fd) {
129 char json_data[kMaxMessageDataLength];
130
131 // Get message type.
132 unsigned char byte_type;
133 if (HANDLE_EINTR(read(fd, &byte_type, 1)) < 1) {
134 LOG(ERROR) << "Error reading the message type.";
135 return false;
136 }
137
138 if (byte_type < 0 || byte_type >= NUM_MESSAGE_TYPES) {
139 LOG(ERROR) << byte_type << " is not a valid message type.";
140 return false;
141 }
142 *type = static_cast<MessageType>(byte_type);
143
144 // Read the length of the json data.
145 uint32_t data_length;
146 if (HANDLE_EINTR(read(fd, &data_length, 4)) < 1) {
147 LOG(ERROR) << "Error reading the json data length.";
148 return false;
149 }
150
151 if (data_length > kMaxMessageDataLength) {
152 LOG(ERROR) << data_length << " is too large for the length of a message. "
153 << "Max message size is " << kMaxMessageDataLength;
154 return false;
155 }
156
157 ssize_t bytes_read = HANDLE_EINTR(read(fd, &json_data, data_length));
158 if (bytes_read < 1) {
159 LOG(ERROR) << "Error reading the json data.";
160 return false;
161 } else if (bytes_read != data_length) {
162 LOG(ERROR) << "Advertised length from client differed from actual size. "
163 << "Actual Size: " << bytes_read << ", "
164 << "Advertised Size: " << data_length;
165 return false;
166 }
167 json_data[bytes_read] = '\0';
168
169 std::string json_error_str;
170 int json_error_code;
171 Value* value = base::JSONReader::ReadAndReturnError(json_data, 0,
172 &json_error_code,
173 &json_error_str);
174 if (!value) {
175 LOG(ERROR) << "Error reading JSON data into string. "
176 << "Code: " << json_error_code << ". "
177 << "Message: " << json_error_str;
178 return false;
179 }
180
181 if (!value->GetAsDictionary(data)) {
182 LOG(ERROR) << "Error converting the message to a DictionaryValue.";
183 return false;
184 }
185
186 return true;
187 }
188
189 void NativeThreadDelegate::Finish(bool success,
190 const std::string& error,
191 scoped_ptr<DictionaryValue> result) {
192 scoped_ptr<std::string> scoped_error(new std::string(error));
193 content::BrowserThread::PostTask(
194 content::BrowserThread::UI,
195 FROM_HERE,
196 base::Bind(&NativeThreadDelegate::CallbackOnUIThread,
197 base::Unretained(this),
198 success,
199 base::Passed(&scoped_error),
200 base::Passed(&result)));
201 }
202
203 void NativeThreadDelegate::CallbackOnUIThread(
204 bool success, scoped_ptr<std::string> error,
205 scoped_ptr<DictionaryValue> result) {
206 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
207 callback_.Run(success, error.Pass(), result.Pass());
208 }
209
210 void NativeThreadDelegate::exit() {
211 int exit_code = 0;
212 if (!base::WaitForExitCodeWithTimeout(handle_, &exit_code, kExitTimeoutMS)) {
213 // Kill the process.
214 if (!base::KillProcess(handle_,
215 -1, /* error exit code */
216 false /* Don't wait for the process to exit */)) {
217 // Really kill the process.
218 base::EnsureProcessTerminated(handle_);
219 }
220 }
221 }
222
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698