e2f9c45a1a7294673391088a78b1179a96c304e7
[platform/framework/web/crosswalk.git] / src / chrome / utility / chrome_content_utility_client.cc
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/utility/chrome_content_utility_client.h"
6
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/time/time.h"
11 #include "chrome/common/chrome_utility_messages.h"
12 #include "chrome/common/safe_browsing/zip_analyzer.h"
13 #include "chrome/utility/chrome_content_utility_ipc_whitelist.h"
14 #include "chrome/utility/utility_message_handler.h"
15 #include "chrome/utility/web_resource_unpacker.h"
16 #include "content/public/child/image_decoder_utils.h"
17 #include "content/public/common/content_switches.h"
18 #include "content/public/utility/utility_thread.h"
19 #include "courgette/courgette.h"
20 #include "courgette/third_party/bsdiff.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "third_party/zlib/google/zip.h"
23 #include "ui/gfx/codec/jpeg_codec.h"
24 #include "ui/gfx/size.h"
25
26 #if !defined(OS_ANDROID)
27 #include "chrome/utility/profile_import_handler.h"
28 #endif
29
30 #if defined(OS_WIN)
31 #include "chrome/utility/shell_handler_win.h"
32 #endif
33
34 #if defined(ENABLE_EXTENSIONS)
35 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
36 #include "chrome/utility/extensions/extensions_handler.h"
37 #include "chrome/utility/image_writer/image_writer_handler.h"
38 #include "chrome/utility/media_galleries/ipc_data_source.h"
39 #include "chrome/utility/media_galleries/media_metadata_parser.h"
40 #endif
41
42 #if defined(ENABLE_FULL_PRINTING)
43 #include "chrome/utility/printing_handler.h"
44 #endif
45
46 #if defined(ENABLE_MDNS)
47 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
48 #endif
49
50 namespace {
51
52 bool Send(IPC::Message* message) {
53   return content::UtilityThread::Get()->Send(message);
54 }
55
56 void ReleaseProcessIfNeeded() {
57   content::UtilityThread::Get()->ReleaseProcessIfNeeded();
58 }
59
60 #if defined(ENABLE_EXTENSIONS)
61 void FinishParseMediaMetadata(
62     metadata::MediaMetadataParser* /* parser */,
63     const extensions::api::media_galleries::MediaMetadata& metadata,
64     const std::vector<metadata::AttachedImage>& attached_images) {
65   Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
66       true, *metadata.ToValue(), attached_images));
67   ReleaseProcessIfNeeded();
68 }
69 #endif
70
71 }  // namespace
72
73 ChromeContentUtilityClient::ChromeContentUtilityClient()
74     : filter_messages_(false) {
75 #if !defined(OS_ANDROID)
76   handlers_.push_back(new ProfileImportHandler());
77 #endif
78
79 #if defined(ENABLE_EXTENSIONS)
80   handlers_.push_back(new extensions::ExtensionsHandler());
81   handlers_.push_back(new image_writer::ImageWriterHandler());
82 #endif
83
84 #if defined(ENABLE_FULL_PRINTING)
85   handlers_.push_back(new PrintingHandler());
86 #endif
87
88 #if defined(ENABLE_MDNS)
89   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
90           switches::kUtilityProcessEnableMDns)) {
91     handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
92   }
93 #endif
94
95 #if defined(OS_WIN)
96   handlers_.push_back(new ShellHandler());
97 #endif
98 }
99
100 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
101 }
102
103 void ChromeContentUtilityClient::UtilityThreadStarted() {
104 #if defined(ENABLE_EXTENSIONS)
105   extensions::ExtensionsHandler::UtilityThreadStarted();
106 #endif
107
108   if (kMessageWhitelistSize > 0) {
109     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
110     if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) {
111       message_id_whitelist_.insert(kMessageWhitelist,
112                                    kMessageWhitelist + kMessageWhitelistSize);
113       filter_messages_ = true;
114     }
115   }
116 }
117
118 bool ChromeContentUtilityClient::OnMessageReceived(
119     const IPC::Message& message) {
120   if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type()))
121     return false;
122
123   bool handled = true;
124   IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
125     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackWebResource,
126                         OnUnpackWebResource)
127     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
128     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
129                         OnRobustJPEGDecodeImage)
130     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff,
131                         OnPatchFileBsdiff)
132     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette,
133                         OnPatchFileCourgette)
134     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
135 #if defined(FULL_SAFE_BROWSING)
136     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
137                         OnAnalyzeZipFileForDownloadProtection)
138 #endif
139 #if defined(ENABLE_EXTENSIONS)
140     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
141                         OnParseMediaMetadata)
142 #endif
143 #if defined(OS_CHROMEOS)
144     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
145 #endif
146     IPC_MESSAGE_UNHANDLED(handled = false)
147   IPC_END_MESSAGE_MAP()
148
149   for (Handlers::iterator it = handlers_.begin();
150        !handled && it != handlers_.end(); ++it) {
151     handled = (*it)->OnMessageReceived(message);
152   }
153
154   return handled;
155 }
156
157 // static
158 void ChromeContentUtilityClient::PreSandboxStartup() {
159 #if defined(ENABLE_EXTENSIONS)
160   extensions::ExtensionsHandler::PreSandboxStartup();
161 #endif
162
163 #if defined(ENABLE_FULL_PRINTING)
164   PrintingHandler::PreSandboxStartup();
165 #endif
166
167 #if defined(ENABLE_MDNS)
168   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
169           switches::kUtilityProcessEnableMDns)) {
170     local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
171   }
172 #endif  // ENABLE_MDNS
173 }
174
175 // static
176 void ChromeContentUtilityClient::DecodeImage(
177     const std::vector<unsigned char>& encoded_data) {
178   const SkBitmap& decoded_image = content::DecodeImage(&encoded_data[0],
179                                                        gfx::Size(),
180                                                        encoded_data.size());
181   if (decoded_image.empty()) {
182     Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
183   } else {
184     Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image));
185   }
186   ReleaseProcessIfNeeded();
187 }
188
189 void ChromeContentUtilityClient::OnUnpackWebResource(
190     const std::string& resource_data) {
191   // Parse json data.
192   // TODO(mrc): Add the possibility of a template that controls parsing, and
193   // the ability to download and verify images.
194   WebResourceUnpacker unpacker(resource_data);
195   if (unpacker.Run()) {
196     Send(new ChromeUtilityHostMsg_UnpackWebResource_Succeeded(
197         *unpacker.parsed_json()));
198   } else {
199     Send(new ChromeUtilityHostMsg_UnpackWebResource_Failed(
200         unpacker.error_message()));
201   }
202
203   ReleaseProcessIfNeeded();
204 }
205
206 void ChromeContentUtilityClient::OnDecodeImage(
207     const std::vector<unsigned char>& encoded_data) {
208   DecodeImage(encoded_data);
209 }
210
211 #if defined(OS_CHROMEOS)
212 void ChromeContentUtilityClient::OnCreateZipFile(
213     const base::FilePath& src_dir,
214     const std::vector<base::FilePath>& src_relative_paths,
215     const base::FileDescriptor& dest_fd) {
216   bool succeeded = true;
217
218   // Check sanity of source relative paths. Reject if path is absolute or
219   // contains any attempt to reference a parent directory ("../" tricks).
220   for (std::vector<base::FilePath>::const_iterator iter =
221            src_relative_paths.begin(); iter != src_relative_paths.end();
222        ++iter) {
223     if (iter->IsAbsolute() || iter->ReferencesParent()) {
224       succeeded = false;
225       break;
226     }
227   }
228
229   if (succeeded)
230     succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
231
232   if (succeeded)
233     Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
234   else
235     Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
236   ReleaseProcessIfNeeded();
237 }
238 #endif  // defined(OS_CHROMEOS)
239
240 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
241     const std::vector<unsigned char>& encoded_data) {
242   // Our robust jpeg decoding is using IJG libjpeg.
243   if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG &&
244       !encoded_data.empty()) {
245     scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodec::Decode(
246         &encoded_data[0], encoded_data.size()));
247     if (!decoded_image.get() || decoded_image->empty()) {
248       Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
249     } else {
250       Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image));
251     }
252   } else {
253     Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
254   }
255   ReleaseProcessIfNeeded();
256 }
257
258 void ChromeContentUtilityClient::OnPatchFileBsdiff(
259     const base::FilePath& input_file,
260     const base::FilePath& patch_file,
261     const base::FilePath& output_file) {
262   if (input_file.empty() || patch_file.empty() || output_file.empty()) {
263     Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
264   } else {
265     const int patch_status = courgette::ApplyBinaryPatch(input_file,
266                                                          patch_file,
267                                                          output_file);
268     Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
269   }
270   ReleaseProcessIfNeeded();
271 }
272
273 void ChromeContentUtilityClient::OnPatchFileCourgette(
274     const base::FilePath& input_file,
275     const base::FilePath& patch_file,
276     const base::FilePath& output_file) {
277   if (input_file.empty() || patch_file.empty() || output_file.empty()) {
278     Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
279   } else {
280     const int patch_status = courgette::ApplyEnsemblePatch(
281         input_file.value().c_str(),
282         patch_file.value().c_str(),
283         output_file.value().c_str());
284     Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
285   }
286   ReleaseProcessIfNeeded();
287 }
288
289 void ChromeContentUtilityClient::OnStartupPing() {
290   Send(new ChromeUtilityHostMsg_ProcessStarted);
291   // Don't release the process, we assume further messages are on the way.
292 }
293
294 #if defined(FULL_SAFE_BROWSING)
295 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
296     const IPC::PlatformFileForTransit& zip_file) {
297   safe_browsing::zip_analyzer::Results results;
298   safe_browsing::zip_analyzer::AnalyzeZipFile(
299       IPC::PlatformFileForTransitToFile(zip_file), &results);
300   Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
301       results));
302   ReleaseProcessIfNeeded();
303 }
304 #endif
305
306 #if defined(ENABLE_EXTENSIONS)
307 // TODO(thestig): Try to move this to
308 // chrome/utility/extensions/extensions_handler.cc.
309 void ChromeContentUtilityClient::OnParseMediaMetadata(
310     const std::string& mime_type, int64 total_size, bool get_attached_images) {
311   // Only one IPCDataSource may be created and added to the list of handlers.
312   metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
313   handlers_.push_back(source);
314
315   metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
316       source, mime_type, get_attached_images);
317   parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
318 }
319 #endif