spellcheck_hunspell_dictionary.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/memory_mapped_file.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_platform_mac.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/spellchecker/spellcheck_service.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_common.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_messages.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/hunspell/google/bdict.h" 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Close the platform file. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloseDictionary(base::PlatformFile file) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ClosePlatformFile(file); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Dictionary file information to be passed between the FILE and UI threads. 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct DictionaryFile { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DictionaryFile() : descriptor(base::kInvalidPlatformFileValue) { 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~DictionaryFile() { 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (descriptor != base::kInvalidPlatformFileValue) { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTask( 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&CloseDictionary, descriptor)); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) descriptor = base::kInvalidPlatformFileValue; 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The desired location of the dictionary file, whether or not it exists. 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The file descriptor/handle for the dictionary file. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PlatformFile descriptor; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DictionaryFile); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Figures out the location for the dictionary, verifies its contents, and opens 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// it. The default_dictionary_file can either come from the standard list of 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// hunspell dictionaries (determined in InitializeDictionaryLocation), or it 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// can be passed in via an extension. In either case, the file is checked for 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// existence so that it's not re-downloaded. 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// For systemwide installations on Windows, the default directory may not 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// have permissions for download. In that case, the alternate directory for 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// download is chrome::DIR_USER_DATA. 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns a scoped pointer to avoid leaking the file descriptor if the caller 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// has been destroyed. 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<DictionaryFile> OpenDictionaryFile( 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<DictionaryFile> file) { 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if the dictionary exists in the fallback location. If so, use it 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // rather than downloading anew. 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath user_dir; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(chrome::DIR_USER_DATA, &user_dir); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath fallback = user_dir.Append(file->path.BaseName()); 837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!base::PathExists(file->path) && base::PathExists(fallback)) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->path = fallback; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Read the dictionary file and scan its data to check for corruption. The 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // scoping closes the memory-mapped file before it is opened or deleted. 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool bdict_is_valid; 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::MemoryMappedFile map; 927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bdict_is_valid = base::PathExists(file->path) && 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) map.Initialize(file->path) && 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hunspell::BDict::Verify(reinterpret_cast<const char*>(map.data()), 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) map.length()); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bdict_is_valid) { 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->descriptor = base::CreatePlatformFile( 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->path, 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL, 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(file->path, false); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return file.Pass(); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Gets the default location for the dictionary file. The default place where 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the spellcheck dictionary resides is chrome::DIR_APP_DICTIONARIES. 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns a scoped pointer to avoid leaking the file descriptor if the caller 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// has been destroyed. 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<DictionaryFile> InitializeDictionaryLocation( 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& language) { 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<DictionaryFile> file(new DictionaryFile); 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Initialize the BDICT path. Initialization should be in the FILE thread 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // because it checks if there is a "Dictionaries" directory and create it. 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath dict_dir; 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) file->path = chrome::spellcheck_common::GetVersionedFileName( 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) language, dict_dir); 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return OpenDictionaryFile(file.Pass()); 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Saves |data| to file at |path|. Returns true on successful save, otherwise 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// returns false. 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SaveDictionaryData(scoped_ptr<std::string> data, 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path) { 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t bytes_written = 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_util::WriteFile(path, data->data(), data->length()); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_written != data->length()) { 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success = false; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath dict_dir; 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(chrome::DIR_USER_DATA, &dict_dir); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath fallback_file_path = 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dict_dir.Append(path.BaseName()); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bytes_written = 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_util::WriteFile(fallback_file_path, data->data(), data->length()); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_written == data->length()) 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success = true; 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!success) { 1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(path, false); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellcheckHunspellDictionary::SpellcheckHunspellDictionary( 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language, 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContextGetter* request_context_getter, 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService* spellcheck_service) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : language_(language), 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_platform_spellchecker_(false), 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getter_(request_context_getter), 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this), 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_service_(spellcheck_service), 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_(DOWNLOAD_NONE), 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_(new DictionaryFile) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::Load() { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (spellcheck_mac::SpellCheckerAvailable() && 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spellcheck_mac::PlatformSupportsLanguage(language_)) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_platform_spellchecker_ = true; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spellcheck_mac::SetLanguage(language_); 18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &SpellcheckHunspellDictionary::InformListenersOfInitialization, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // OS_MACOSX 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTaskAndReplyWithResult( 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&InitializeDictionaryLocation, language_), 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete, 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::RetryDownloadDictionary( 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequestContextGetter* request_context_getter) { 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_context_getter_ = request_context_getter; 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DownloadDictionary(GetDictionaryURL()); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsReady() const { 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetDictionaryFile() != 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::kInvalidPlatformFileValue || IsUsingPlatformChecker(); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::PlatformFile& 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpellcheckHunspellDictionary::GetDictionaryFile() const { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return dictionary_file_->descriptor; 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string& SpellcheckHunspellDictionary::GetLanguage() const { 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return language_; 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsUsingPlatformChecker() const { 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return use_platform_spellchecker_; 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::AddObserver(Observer* observer) { 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) { 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsDownloadInProgress() { 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return download_status_ == DOWNLOAD_IN_PROGRESS; 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsDownloadFailure() { 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return download_status_ == DOWNLOAD_FAILED; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::OnURLFetchComplete( 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(source); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release()); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((source->GetResponseCode() / 100) != 2) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize will not try to download the file a second time. 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Basic sanity check on the dictionary. There's a small chance of 200 status 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // code for a body that represents some form of failure. 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<std::string> data(new std::string); 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source->GetResponseAsString(data.get()); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (data->size() < 4 || data->compare(0, 4, "BDic") != 0) { 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // To prevent corrupted dictionary data from causing a renderer crash, scan 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the dictionary data and verify it is sane before save it to a file. 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rlp): Adding metrics to RecordDictionaryCorruptionStats 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!hunspell::BDict::Verify(data->data(), data->size())) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Let PostTaskAndReply caller send to InformListenersOfInitialization 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // through SaveDictionaryDataComplete(). 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SaveDictionaryDataComplete(false); 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTaskAndReplyWithResult<bool>( 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SaveDictionaryData, 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Passed(&data), 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_->path), 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SpellcheckHunspellDictionary::SaveDictionaryDataComplete, 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)GURL SpellcheckHunspellDictionary::GetDictionaryURL() { 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static const char kDownloadServerUrl[] = 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://cache.pack.google.com/edgedl/chrome/dict/"; 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string bdict_file = dictionary_file_->path.BaseName().MaybeAsASCII(); 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!bdict_file.empty()); 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return GURL(std::string(kDownloadServerUrl) + 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) StringToLowerASCII(bdict_file)); 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(request_context_getter_); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_IN_PROGRESS; 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryDownloadBegin()); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, this)); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->SetRequestContext(request_context_getter_); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->SetLoadFlags( 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->Start(); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Attempt downloading the dictionary only once. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getter_ = NULL; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete( 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DictionaryFile> file) { 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_ = file.Pass(); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dictionary_file_->descriptor == base::kInvalidPlatformFileValue) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Notify browser tests that this dictionary is corrupted. Skip downloading 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the dictionary in browser tests. 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rouslan): Remove this test-only case. 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (spellcheck_service_->SignalStatusEvent( 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService::BDICT_CORRUPTED)) { 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_context_getter_ = NULL; 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (request_context_getter_) { 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Download from the UI thread to check that |request_context_getter_| is 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // still valid. 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DownloadDictionary(GetDictionaryURL()); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfInitialization(); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool dictionary_saved) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dictionary_saved) { 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_NONE; 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_, 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnHunspellDictionaryDownloadSuccess()); 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Load(); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfInitialization(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InformListenersOfInitialization() { 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryInitialized()); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() { 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_FAILED; 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_, 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnHunspellDictionaryDownloadFailure()); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365