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.
5 #include "chrome/utility/chrome_content_utility_client.h"
7 #include "base/base64.h"
9 #include "base/command_line.h"
10 #include "base/json/json_reader.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "chrome/common/chrome_utility_messages.h"
14 #include "chrome/common/extensions/chrome_manifest_handlers.h"
15 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_l10n_util.h"
17 #include "chrome/common/extensions/manifest.h"
18 #include "chrome/common/extensions/permissions/chrome_api_permissions.h"
19 #include "chrome/common/extensions/update_manifest.h"
20 #include "chrome/common/safe_browsing/zip_analyzer.h"
21 #include "chrome/utility/extensions/unpacker.h"
22 #include "chrome/utility/profile_import_handler.h"
23 #include "chrome/utility/web_resource_unpacker.h"
24 #include "content/public/child/image_decoder_utils.h"
25 #include "content/public/utility/utility_thread.h"
26 #include "printing/page_range.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "third_party/zlib/google/zip.h"
29 #include "ui/base/ui_base_switches.h"
30 #include "ui/gfx/codec/jpeg_codec.h"
31 #include "ui/gfx/rect.h"
32 #include "ui/gfx/size.h"
35 #include "base/file_util.h"
36 #include "base/path_service.h"
37 #include "base/win/iat_patch_function.h"
38 #include "base/win/scoped_handle.h"
39 #include "chrome/common/chrome_paths.h"
40 #include "chrome/utility/itunes_pref_parser_win.h"
41 #include "printing/emf_win.h"
42 #include "ui/gfx/gdi_util.h"
43 #endif // defined(OS_WIN)
45 #if defined(OS_WIN) || defined(OS_MACOSX)
46 #include "chrome/common/media_galleries/picasa_types.h"
47 #include "chrome/utility/itunes_library_parser.h"
48 #include "chrome/utility/media_galleries/picasa_album_table_reader.h"
49 #endif // defined(OS_WIN) || defined(OS_MACOSX)
51 #if defined(ENABLE_PRINTING)
52 #include "chrome/common/child_process_logging.h"
53 #include "printing/backend/print_backend.h"
56 #if defined(ENABLE_MDNS)
57 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
64 bool Send(IPC::Message
* message
) {
65 return content::UtilityThread::Get()->Send(message
);
68 void ReleaseProcessIfNeeded() {
69 content::UtilityThread::Get()->ReleaseProcessIfNeeded();
74 ChromeContentUtilityClient::ChromeContentUtilityClient() {
75 #if !defined(OS_ANDROID)
76 handlers_
.push_back(new ProfileImportHandler());
79 #if defined(ENABLE_MDNS)
80 handlers_
.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
84 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
87 void ChromeContentUtilityClient::UtilityThreadStarted() {
89 // Load the pdf plugin before the sandbox is turned on. This is for Windows
90 // only because we need this DLL only on Windows.
92 if (PathService::Get(chrome::FILE_PDF_PLUGIN
, &pdf
) &&
93 base::PathExists(pdf
)) {
94 bool rv
= !!LoadLibrary(pdf
.value().c_str());
95 DCHECK(rv
) << "Couldn't load PDF plugin";
99 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
100 std::string lang
= command_line
->GetSwitchValueASCII(switches::kLang
);
102 extension_l10n_util::SetProcessLocale(lang
);
105 bool ChromeContentUtilityClient::OnMessageReceived(
106 const IPC::Message
& message
) {
108 IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient
, message
)
109 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension
, OnUnpackExtension
)
110 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackWebResource
,
112 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseUpdateManifest
,
113 OnParseUpdateManifest
)
114 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage
, OnDecodeImage
)
115 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImageBase64
, OnDecodeImageBase64
)
116 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafile
,
117 OnRenderPDFPagesToMetafile
)
118 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage
,
119 OnRobustJPEGDecodeImage
)
120 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON
, OnParseJSON
)
121 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterCapsAndDefaults
,
122 OnGetPrinterCapsAndDefaults
)
123 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing
, OnStartupPing
)
124 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection
,
125 OnAnalyzeZipFileForDownloadProtection
)
127 #if defined(OS_CHROMEOS)
128 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile
, OnCreateZipFile
)
129 #endif // defined(OS_CHROMEOS)
132 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesPrefXml
,
133 OnParseITunesPrefXml
)
134 #endif // defined(OS_WIN)
136 #if defined(OS_WIN) || defined(OS_MACOSX)
137 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesLibraryXmlFile
,
138 OnParseITunesLibraryXmlFile
)
139 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParsePicasaPMPDatabase
,
140 OnParsePicasaPMPDatabase
)
141 #endif // defined(OS_WIN) || defined(OS_MACOSX)
143 IPC_MESSAGE_UNHANDLED(handled
= false)
144 IPC_END_MESSAGE_MAP()
146 for (Handlers::iterator it
= handlers_
.begin();
147 !handled
&& it
!= handlers_
.end(); ++it
) {
148 handled
= (*it
)->OnMessageReceived(message
);
154 void ChromeContentUtilityClient::OnUnpackExtension(
155 const base::FilePath
& extension_path
,
156 const std::string
& extension_id
,
158 int creation_flags
) {
159 CHECK_GT(location
, extensions::Manifest::INVALID_LOCATION
);
160 CHECK_LT(location
, extensions::Manifest::NUM_LOCATIONS
);
161 extensions::PermissionsInfo::GetInstance()->InitializeWithDelegate(
162 extensions::ChromeAPIPermissions());
163 extensions::RegisterChromeManifestHandlers();
164 extensions::Unpacker
unpacker(
167 static_cast<extensions::Manifest::Location
>(location
),
169 if (unpacker
.Run() && unpacker
.DumpImagesToFile() &&
170 unpacker
.DumpMessageCatalogsToFile()) {
171 Send(new ChromeUtilityHostMsg_UnpackExtension_Succeeded(
172 *unpacker
.parsed_manifest()));
174 Send(new ChromeUtilityHostMsg_UnpackExtension_Failed(
175 unpacker
.error_message()));
178 ReleaseProcessIfNeeded();
181 void ChromeContentUtilityClient::OnUnpackWebResource(
182 const std::string
& resource_data
) {
184 // TODO(mrc): Add the possibility of a template that controls parsing, and
185 // the ability to download and verify images.
186 WebResourceUnpacker
unpacker(resource_data
);
187 if (unpacker
.Run()) {
188 Send(new ChromeUtilityHostMsg_UnpackWebResource_Succeeded(
189 *unpacker
.parsed_json()));
191 Send(new ChromeUtilityHostMsg_UnpackWebResource_Failed(
192 unpacker
.error_message()));
195 ReleaseProcessIfNeeded();
198 void ChromeContentUtilityClient::OnParseUpdateManifest(const std::string
& xml
) {
199 UpdateManifest manifest
;
200 if (!manifest
.Parse(xml
)) {
201 Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Failed(
204 Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded(
205 manifest
.results()));
207 ReleaseProcessIfNeeded();
210 void ChromeContentUtilityClient::OnDecodeImage(
211 const std::vector
<unsigned char>& encoded_data
) {
212 const SkBitmap
& decoded_image
= content::DecodeImage(&encoded_data
[0],
214 encoded_data
.size());
215 if (decoded_image
.empty()) {
216 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
218 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image
));
220 ReleaseProcessIfNeeded();
223 void ChromeContentUtilityClient::OnDecodeImageBase64(
224 const std::string
& encoded_string
) {
225 std::string decoded_string
;
227 if (!base::Base64Decode(encoded_string
, &decoded_string
)) {
228 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
232 std::vector
<unsigned char> decoded_vector(decoded_string
.size());
233 for (size_t i
= 0; i
< decoded_string
.size(); ++i
) {
234 decoded_vector
[i
] = static_cast<unsigned char>(decoded_string
[i
]);
237 OnDecodeImage(decoded_vector
);
240 #if defined(OS_CHROMEOS)
241 void ChromeContentUtilityClient::OnCreateZipFile(
242 const base::FilePath
& src_dir
,
243 const std::vector
<base::FilePath
>& src_relative_paths
,
244 const base::FileDescriptor
& dest_fd
) {
245 bool succeeded
= true;
247 // Check sanity of source relative paths. Reject if path is absolute or
248 // contains any attempt to reference a parent directory ("../" tricks).
249 for (std::vector
<base::FilePath
>::const_iterator iter
=
250 src_relative_paths
.begin(); iter
!= src_relative_paths
.end();
252 if (iter
->IsAbsolute() || iter
->ReferencesParent()) {
259 succeeded
= zip::ZipFiles(src_dir
, src_relative_paths
, dest_fd
.fd
);
262 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
264 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
265 ReleaseProcessIfNeeded();
267 #endif // defined(OS_CHROMEOS)
269 void ChromeContentUtilityClient::OnRenderPDFPagesToMetafile(
270 base::PlatformFile pdf_file
,
271 const base::FilePath
& metafile_path
,
272 const printing::PdfRenderSettings
& pdf_render_settings
,
273 const std::vector
<printing::PageRange
>& page_ranges
) {
274 bool succeeded
= false;
276 int highest_rendered_page_number
= 0;
277 double scale_factor
= 1.0;
278 succeeded
= RenderPDFToWinMetafile(pdf_file
,
280 pdf_render_settings
.area(),
281 pdf_render_settings
.dpi(),
282 pdf_render_settings
.autorotate(),
284 &highest_rendered_page_number
,
287 Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded(
288 highest_rendered_page_number
, scale_factor
));
290 #endif // defined(OS_WIN)
292 Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed());
294 ReleaseProcessIfNeeded();
298 // Exported by pdf.dll
299 typedef bool (*RenderPDFPageToDCProc
)(
300 const unsigned char* pdf_buffer
, int buffer_size
, int page_number
, HDC dc
,
301 int dpi_x
, int dpi_y
, int bounds_origin_x
, int bounds_origin_y
,
302 int bounds_width
, int bounds_height
, bool fit_to_bounds
,
303 bool stretch_to_bounds
, bool keep_aspect_ratio
, bool center_in_bounds
,
306 typedef bool (*GetPDFDocInfoProc
)(const unsigned char* pdf_buffer
,
307 int buffer_size
, int* page_count
,
308 double* max_page_width
);
310 // The 2 below IAT patch functions are almost identical to the code in
311 // render_process_impl.cc. This is needed to work around specific Windows APIs
312 // used by the Chrome PDF plugin that will fail in the sandbox.
313 static base::win::IATPatchFunction g_iat_patch_createdca
;
314 HDC WINAPI
UtilityProcess_CreateDCAPatch(LPCSTR driver_name
,
317 const DEVMODEA
* init_data
) {
319 (std::string("DISPLAY") == std::string(driver_name
)))
320 // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
321 return CreateCompatibleDC(NULL
);
324 return CreateDCA(driver_name
, device_name
, output
, init_data
);
327 static base::win::IATPatchFunction g_iat_patch_get_font_data
;
328 DWORD WINAPI
UtilityProcess_GetFontDataPatch(
329 HDC hdc
, DWORD table
, DWORD offset
, LPVOID buffer
, DWORD length
) {
330 int rv
= GetFontData(hdc
, table
, offset
, buffer
, length
);
331 if (rv
== GDI_ERROR
&& hdc
) {
332 HFONT font
= static_cast<HFONT
>(GetCurrentObject(hdc
, OBJ_FONT
));
335 if (GetObject(font
, sizeof(LOGFONT
), &logfont
)) {
336 std::vector
<char> font_data
;
337 content::UtilityThread::Get()->PreCacheFont(logfont
);
338 rv
= GetFontData(hdc
, table
, offset
, buffer
, length
);
339 content::UtilityThread::Get()->ReleaseCachedFonts();
345 bool ChromeContentUtilityClient::RenderPDFToWinMetafile(
346 base::PlatformFile pdf_file
,
347 const base::FilePath
& metafile_path
,
348 const gfx::Rect
& render_area
,
351 const std::vector
<printing::PageRange
>& page_ranges
,
352 int* highest_rendered_page_number
,
353 double* scale_factor
) {
354 *highest_rendered_page_number
= -1;
356 base::win::ScopedHandle
file(pdf_file
);
357 base::FilePath pdf_module_path
;
358 PathService::Get(chrome::FILE_PDF_PLUGIN
, &pdf_module_path
);
359 HMODULE pdf_module
= GetModuleHandle(pdf_module_path
.value().c_str());
363 RenderPDFPageToDCProc render_proc
=
364 reinterpret_cast<RenderPDFPageToDCProc
>(
365 GetProcAddress(pdf_module
, "RenderPDFPageToDC"));
369 GetPDFDocInfoProc get_info_proc
= reinterpret_cast<GetPDFDocInfoProc
>(
370 GetProcAddress(pdf_module
, "GetPDFDocInfo"));
374 // Patch the IAT for handling specific APIs known to fail in the sandbox.
375 if (!g_iat_patch_createdca
.is_patched())
376 g_iat_patch_createdca
.Patch(pdf_module_path
.value().c_str(),
377 "gdi32.dll", "CreateDCA",
378 UtilityProcess_CreateDCAPatch
);
380 if (!g_iat_patch_get_font_data
.is_patched())
381 g_iat_patch_get_font_data
.Patch(pdf_module_path
.value().c_str(),
382 "gdi32.dll", "GetFontData",
383 UtilityProcess_GetFontDataPatch
);
385 // TODO(sanjeevr): Add a method to the PDF DLL that takes in a file handle
386 // and a page range array. That way we don't need to read the entire PDF into
388 DWORD length
= ::GetFileSize(file
, NULL
);
389 if (length
== INVALID_FILE_SIZE
)
392 std::vector
<uint8
> buffer
;
393 buffer
.resize(length
);
394 DWORD bytes_read
= 0;
395 if (!ReadFile(pdf_file
, &buffer
.front(), length
, &bytes_read
, NULL
) ||
396 (bytes_read
!= length
))
399 int total_page_count
= 0;
400 if (!get_info_proc(&buffer
.front(), buffer
.size(), &total_page_count
, NULL
))
403 printing::Emf metafile
;
404 metafile
.InitToFile(metafile_path
);
405 // We need to scale down DC to fit an entire page into DC available area.
406 // Current metafile is based on screen DC and have current screen size.
407 // Writing outside of those boundaries will result in the cut-off output.
408 // On metafiles (this is the case here), scaling down will still record
409 // original coordinates and we'll be able to print in full resolution.
410 // Before playback we'll need to counter the scaling up that will happen
411 // in the service (print_system_win.cc).
412 *scale_factor
= gfx::CalculatePageScale(metafile
.context(),
414 render_area
.bottom());
415 gfx::ScaleDC(metafile
.context(), *scale_factor
);
418 std::vector
<printing::PageRange
>::const_iterator iter
;
419 for (iter
= page_ranges
.begin(); iter
!= page_ranges
.end(); ++iter
) {
420 for (int page_number
= iter
->from
; page_number
<= iter
->to
; ++page_number
) {
421 if (page_number
>= total_page_count
)
423 // The underlying metafile is of type Emf and ignores the arguments passed
425 metafile
.StartPage(gfx::Size(), gfx::Rect(), 1);
426 if (render_proc(&buffer
.front(), buffer
.size(), page_number
,
427 metafile
.context(), render_dpi
, render_dpi
,
428 render_area
.x(), render_area
.y(), render_area
.width(),
429 render_area
.height(), true, false, true, true,
431 if (*highest_rendered_page_number
< page_number
)
432 *highest_rendered_page_number
= page_number
;
434 metafile
.FinishPage();
437 metafile
.FinishDocument();
440 #endif // defined(OS_WIN)
442 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
443 const std::vector
<unsigned char>& encoded_data
) {
444 // Our robust jpeg decoding is using IJG libjpeg.
445 if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG
) {
446 scoped_ptr
<SkBitmap
> decoded_image(gfx::JPEGCodec::Decode(
447 &encoded_data
[0], encoded_data
.size()));
448 if (!decoded_image
.get() || decoded_image
->empty()) {
449 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
451 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image
));
454 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
456 ReleaseProcessIfNeeded();
459 void ChromeContentUtilityClient::OnParseJSON(const std::string
& json
) {
462 base::Value
* value
= base::JSONReader::ReadAndReturnError(
463 json
, base::JSON_PARSE_RFC
, &error_code
, &error
);
465 base::ListValue wrapper
;
466 wrapper
.Append(value
);
467 Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper
));
469 Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error
));
471 ReleaseProcessIfNeeded();
474 void ChromeContentUtilityClient::OnGetPrinterCapsAndDefaults(
475 const std::string
& printer_name
) {
476 #if defined(ENABLE_PRINTING)
477 scoped_refptr
<printing::PrintBackend
> print_backend
=
478 printing::PrintBackend::CreateInstance(NULL
);
479 printing::PrinterCapsAndDefaults printer_info
;
481 child_process_logging::ScopedPrinterInfoSetter
prn_info(
482 print_backend
->GetPrinterDriverInfo(printer_name
));
484 if (print_backend
->GetPrinterCapsAndDefaults(printer_name
, &printer_info
)) {
485 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded(
486 printer_name
, printer_info
));
490 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed(
493 ReleaseProcessIfNeeded();
496 void ChromeContentUtilityClient::OnStartupPing() {
497 Send(new ChromeUtilityHostMsg_ProcessStarted
);
498 // Don't release the process, we assume further messages are on the way.
501 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
502 IPC::PlatformFileForTransit zip_file
) {
503 safe_browsing::zip_analyzer::Results results
;
504 safe_browsing::zip_analyzer::AnalyzeZipFile(
505 IPC::PlatformFileForTransitToPlatformFile(zip_file
), &results
);
506 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
508 ReleaseProcessIfNeeded();
512 void ChromeContentUtilityClient::OnParseITunesPrefXml(
513 const std::string
& itunes_xml_data
) {
514 base::FilePath
library_path(
515 itunes::FindLibraryLocationInPrefXml(itunes_xml_data
));
516 Send(new ChromeUtilityHostMsg_GotITunesDirectory(library_path
));
517 ReleaseProcessIfNeeded();
519 #endif // defined(OS_WIN)
521 #if defined(OS_WIN) || defined(OS_MACOSX)
522 void ChromeContentUtilityClient::OnParseITunesLibraryXmlFile(
523 IPC::PlatformFileForTransit itunes_library_file
) {
524 itunes::ITunesLibraryParser parser
;
525 base::PlatformFile file
=
526 IPC::PlatformFileForTransitToPlatformFile(itunes_library_file
);
527 bool result
= parser
.Parse(
528 itunes::ITunesLibraryParser::ReadITunesLibraryXmlFile(file
));
529 Send(new ChromeUtilityHostMsg_GotITunesLibrary(result
, parser
.library()));
530 ReleaseProcessIfNeeded();
533 void ChromeContentUtilityClient::OnParsePicasaPMPDatabase(
534 const picasa::AlbumTableFilesForTransit
& album_table_files
) {
535 picasa::AlbumTableFiles files
;
536 files
.indicator_file
= IPC::PlatformFileForTransitToPlatformFile(
537 album_table_files
.indicator_file
);
538 files
.category_file
= IPC::PlatformFileForTransitToPlatformFile(
539 album_table_files
.category_file
);
540 files
.date_file
= IPC::PlatformFileForTransitToPlatformFile(
541 album_table_files
.date_file
);
542 files
.filename_file
= IPC::PlatformFileForTransitToPlatformFile(
543 album_table_files
.filename_file
);
544 files
.name_file
= IPC::PlatformFileForTransitToPlatformFile(
545 album_table_files
.name_file
);
546 files
.token_file
= IPC::PlatformFileForTransitToPlatformFile(
547 album_table_files
.token_file
);
548 files
.uid_file
= IPC::PlatformFileForTransitToPlatformFile(
549 album_table_files
.uid_file
);
551 picasa::PicasaAlbumTableReader
reader(files
);
552 bool parse_success
= reader
.Init();
553 Send(new ChromeUtilityHostMsg_ParsePicasaPMPDatabase_Finished(
557 ReleaseProcessIfNeeded();
559 #endif // defined(OS_WIN) || defined(OS_MACOSX)
561 } // namespace chrome