spellcheck_hunspell_dictionary.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_service.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_platform_mac.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 "googleurl/src/gurl.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/hunspell/google/bdict.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 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// it. The default place where the spellcheck dictionary resides is 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// chrome::DIR_APP_DICTIONARIES. For systemwide installations on Windows. 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// however, this directory may not have permissions for download. In that case, 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the alternate directory for download is chrome::DIR_USER_DATA. Returns a 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// scoped pointer to avoid leaking the file descriptor if the caller has been 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// destroyed. 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<DictionaryFile> InitializeDictionaryLocation( 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& language) { 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DictionaryFile> file(new DictionaryFile); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Initialize the BDICT path. Initialization should be in the FILE thread 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // because it checks if there is a "Dictionaries" directory and create it. 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath dict_dir; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->path = chrome::spellcheck_common::GetVersionedFileName( 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) language, dict_dir); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if the dictionary exists in the fallback location. If so, use it 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // rather than downloading anew. 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath user_dir; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(chrome::DIR_USER_DATA, &user_dir); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath fallback = user_dir.Append(file->path.BaseName()); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!file_util::PathExists(file->path) && file_util::PathExists(fallback)) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->path = fallback; 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Read the dictionary file and scan its data to check for corruption. The 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // scoping closes the memory-mapped file before it is opened or deleted. 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool bdict_is_valid; 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::MemoryMappedFile map; 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bdict_is_valid = file_util::PathExists(file->path) && 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) map.Initialize(file->path) && 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hunspell::BDict::Verify(reinterpret_cast<const char*>(map.data()), 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) map.length()); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bdict_is_valid) { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->descriptor = base::CreatePlatformFile( 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file->path, 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL, 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_util::Delete(file->path, false); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return file.Pass(); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Saves |data| to file at |path|. Returns true on successful save, otherwise 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// returns false. 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SaveDictionaryData(scoped_ptr<std::string> data, 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path) { 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t bytes_written = 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_util::WriteFile(path, data->data(), data->length()); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_written != data->length()) { 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success = false; 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath dict_dir; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(chrome::DIR_USER_DATA, &dict_dir); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath fallback_file_path = 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dict_dir.Append(path.BaseName()); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bytes_written = 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_util::WriteFile(fallback_file_path, data->data(), data->length()); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_written == data->length()) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success = true; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!success) { 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_util::Delete(path, false); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellcheckHunspellDictionary::SpellcheckHunspellDictionary( 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language, 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContextGetter* request_context_getter, 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService* spellcheck_service) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : language_(language), 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_platform_spellchecker_(false), 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getter_(request_context_getter), 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_service_(spellcheck_service), 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_(DOWNLOAD_NONE), 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_(new DictionaryFile) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::Load() { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (spellcheck_mac::SpellCheckerAvailable() && 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spellcheck_mac::PlatformSupportsLanguage(language_)) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_platform_spellchecker_ = true; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spellcheck_mac::SetLanguage(language_); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop::current()->PostTask(FROM_HERE, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &SpellcheckHunspellDictionary::InformListenersOfInitialization, 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // OS_MACOSX 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTaskAndReplyWithResult( 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&InitializeDictionaryLocation, language_), 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::RetryDownloadDictionary( 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequestContextGetter* request_context_getter) { 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_context_getter_ = request_context_getter; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DownloadDictionary(); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsReady() const { 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetDictionaryFile() != 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::kInvalidPlatformFileValue || IsUsingPlatformChecker(); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::PlatformFile& 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpellcheckHunspellDictionary::GetDictionaryFile() const { 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return dictionary_file_->descriptor; 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string& SpellcheckHunspellDictionary::GetLanguage() const { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return language_; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsUsingPlatformChecker() const { 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return use_platform_spellchecker_; 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::AddObserver(Observer* observer) { 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) { 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsDownloadInProgress() { 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return download_status_ == DOWNLOAD_IN_PROGRESS; 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsDownloadFailure() { 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return download_status_ == DOWNLOAD_FAILED; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::OnURLFetchComplete( 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(source); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release()); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((source->GetResponseCode() / 100) != 2) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize will not try to download the file a second time. 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Basic sanity check on the dictionary. There's a small chance of 200 status 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // code for a body that represents some form of failure. 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<std::string> data(new std::string); 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source->GetResponseAsString(data.get()); 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (data->size() < 4 || data->compare(0, 4, "BDic") != 0) { 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // To prevent corrupted dictionary data from causing a renderer crash, scan 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the dictionary data and verify it is sane before save it to a file. 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rlp): Adding metrics to RecordDictionaryCorruptionStats 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!hunspell::BDict::Verify(data->data(), data->size())) { 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Let PostTaskAndReply caller send to InformListenersOfInitialization 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // through SaveDictionaryDataComplete(). 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SaveDictionaryDataComplete(false); 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTaskAndReplyWithResult<bool>( 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SaveDictionaryData, 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Passed(&data), 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_->path), 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SpellcheckHunspellDictionary::SaveDictionaryDataComplete, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::DownloadDictionary() { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(request_context_getter_); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_IN_PROGRESS; 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryDownloadBegin()); 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Determine URL of file to download. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kDownloadServerUrl[] = 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://cache.pack.google.com/edgedl/chrome/dict/"; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string bdict_file = dictionary_file_->path.BaseName().MaybeAsASCII(); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bdict_file.empty()) { 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL url = GURL(std::string(kDownloadServerUrl) + 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringToLowerASCII(bdict_file)); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->SetRequestContext(request_context_getter_); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->SetLoadFlags( 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->Start(); 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Attempt downloading the dictionary only once. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getter_ = NULL; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete( 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DictionaryFile> file) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_ = file.Pass(); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dictionary_file_->descriptor == base::kInvalidPlatformFileValue) { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Notify browser tests that this dictionary is corrupted. Skip downloading 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the dictionary in browser tests. 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rouslan): Remove this test-only case. 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (spellcheck_service_->SignalStatusEvent( 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService::BDICT_CORRUPTED)) { 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_context_getter_ = NULL; 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (request_context_getter_) { 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Download from the UI thread to check that |request_context_getter_| is 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // still valid. 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DownloadDictionary(); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfInitialization(); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool dictionary_saved) { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dictionary_saved) { 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_NONE; 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_, 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnHunspellDictionaryDownloadSuccess()); 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Load(); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfInitialization(); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InformListenersOfInitialization() { 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryInitialized()); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() { 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_FAILED; 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_, 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnHunspellDictionaryDownloadFailure()); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 352