spellcheck_hunspell_dictionary.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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) 29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Close the file. 30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid CloseDictionary(base::File file) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch file.Close(); 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Saves |data| to file at |path|. Returns true on successful save, otherwise 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// returns false. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SaveDictionaryData(scoped_ptr<std::string> data, 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path) { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t bytes_written = 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::WriteFile(path, data->data(), data->length()); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_written != data->length()) { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success = false; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath dict_dir; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(chrome::DIR_USER_DATA, &dict_dir); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath fallback_file_path = 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dict_dir.Append(path.BaseName()); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bytes_written = 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::WriteFile(fallback_file_path, data->data(), data->length()); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_written == data->length()) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success = true; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!success) { 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(path, false); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::DictionaryFile::DictionaryFile() { 68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch SpellcheckHunspellDictionary::DictionaryFile::~DictionaryFile() { 71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (file.IsValid()) { 72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BrowserThread::PostTask( 73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BrowserThread::FILE, 74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch FROM_HERE, 75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::Bind(&CloseDictionary, Passed(&file))); 76c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 77c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::DictionaryFile::DictionaryFile(RValue other) 80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch : path(other.object->path), 81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch file(other.object->file.Pass()) { 82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::DictionaryFile& 85c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::DictionaryFile::operator=(RValue other) { 86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (this != other.object) { 87c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch path = other.object->path; 88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch file = other.object->file.Pass(); 89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return *this; 91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 92c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellcheckHunspellDictionary::SpellcheckHunspellDictionary( 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContextGetter* request_context_getter, 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService* spellcheck_service) 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : language_(language), 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_platform_spellchecker_(false), 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getter_(request_context_getter), 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_service_(spellcheck_service), 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_(DOWNLOAD_NONE), 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) weak_ptr_factory_(this) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::Load() { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (spellcheck_mac::SpellCheckerAvailable() && 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spellcheck_mac::PlatformSupportsLanguage(language_)) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_platform_spellchecker_ = true; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spellcheck_mac::SetLanguage(language_); 11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &SpellcheckHunspellDictionary::InformListenersOfInitialization, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // OS_MACOSX 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTaskAndReplyWithResult( 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&InitializeDictionaryLocation, language_), 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::RetryDownloadDictionary( 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequestContextGetter* request_context_getter) { 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_context_getter_ = request_context_getter; 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DownloadDictionary(GetDictionaryURL()); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsReady() const { 14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return GetDictionaryFile().IsValid() || IsUsingPlatformChecker(); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const base::File& SpellcheckHunspellDictionary::GetDictionaryFile() const { 14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return dictionary_file_.file; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string& SpellcheckHunspellDictionary::GetLanguage() const { 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return language_; 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsUsingPlatformChecker() const { 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return use_platform_spellchecker_; 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::AddObserver(Observer* observer) { 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsDownloadInProgress() { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return download_status_ == DOWNLOAD_IN_PROGRESS; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpellcheckHunspellDictionary::IsDownloadFailure() { 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return download_status_ == DOWNLOAD_FAILED; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellcheckHunspellDictionary::OnURLFetchComplete( 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(source); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release()); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((source->GetResponseCode() / 100) != 2) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize will not try to download the file a second time. 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Basic sanity check on the dictionary. There's a small chance of 200 status 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // code for a body that represents some form of failure. 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<std::string> data(new std::string); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source->GetResponseAsString(data.get()); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (data->size() < 4 || data->compare(0, 4, "BDic") != 0) { 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // To prevent corrupted dictionary data from causing a renderer crash, scan 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the dictionary data and verify it is sane before save it to a file. 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rlp): Adding metrics to RecordDictionaryCorruptionStats 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!hunspell::BDict::Verify(data->data(), data->size())) { 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Let PostTaskAndReply caller send to InformListenersOfInitialization 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // through SaveDictionaryDataComplete(). 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SaveDictionaryDataComplete(false); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTaskAndReplyWithResult<bool>( 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::FILE, 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SaveDictionaryData, 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Passed(&data), 210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch dictionary_file_.path), 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SpellcheckHunspellDictionary::SaveDictionaryDataComplete, 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)GURL SpellcheckHunspellDictionary::GetDictionaryURL() { 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static const char kDownloadServerUrl[] = 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://cache.pack.google.com/edgedl/chrome/dict/"; 218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch std::string bdict_file = dictionary_file_.path.BaseName().MaybeAsASCII(); 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!bdict_file.empty()); 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return GURL(std::string(kDownloadServerUrl) + 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) StringToLowerASCII(bdict_file)); 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(request_context_getter_); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_IN_PROGRESS; 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryDownloadBegin()); 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, this)); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->SetRequestContext(request_context_getter_); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->SetLoadFlags( 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher_->Start(); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Attempt downloading the dictionary only once. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getter_ = NULL; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 242c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// The default_dictionary_file can either come from the standard list of 243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// hunspell dictionaries (determined in InitializeDictionaryLocation), or it 244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// can be passed in via an extension. In either case, the file is checked for 245c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// existence so that it's not re-downloaded. 246c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// For systemwide installations on Windows, the default directory may not 247c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// have permissions for download. In that case, the alternate directory for 248c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// download is chrome::DIR_USER_DATA. 249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::DictionaryFile 250c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::OpenDictionaryFile(const base::FilePath& path) { 251c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 252c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DictionaryFile dictionary; 253c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 254c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#if defined(OS_WIN) 255c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Check if the dictionary exists in the fallback location. If so, use it 256c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // rather than downloading anew. 257c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::FilePath user_dir; 258c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch PathService::Get(chrome::DIR_USER_DATA, &user_dir); 259c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::FilePath fallback = user_dir.Append(path.BaseName()); 260c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!base::PathExists(path) && base::PathExists(fallback)) 261c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch dictionary.path = fallback; 262c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch else 263c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch dictionary.path = path; 264c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#else 265c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch dictionary.path = path; 266c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#endif 267c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 268c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Read the dictionary file and scan its data to check for corruption. The 269c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // scoping closes the memory-mapped file before it is opened or deleted. 270c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch bool bdict_is_valid; 271c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch { 272c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::MemoryMappedFile map; 273c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch bdict_is_valid = 274c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::PathExists(dictionary.path) && 275c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch map.Initialize(dictionary.path) && 276c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch hunspell::BDict::Verify(reinterpret_cast<const char*>(map.data()), 277c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch map.length()); 278c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (bdict_is_valid) { 280c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch dictionary.file.Initialize(dictionary.path, 281c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::File::FLAG_READ | base::File::FLAG_OPEN); 282c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } else { 283c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::DeleteFile(dictionary.path, false); 284c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 285c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 286c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return dictionary.Pass(); 287c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 288c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 289c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// The default place where the spellcheck dictionary resides is 290c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// chrome::DIR_APP_DICTIONARIES. 291c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::DictionaryFile 292c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSpellcheckHunspellDictionary::InitializeDictionaryLocation( 293c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& language) { 294c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 295c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Initialize the BDICT path. Initialization should be in the FILE thread 297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // because it checks if there is a "Dictionaries" directory and create it. 298c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::FilePath dict_dir; 299c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); 300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::FilePath dict_path = 301c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch chrome::spellcheck_common::GetVersionedFileName(language, dict_dir); 302c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 303c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return OpenDictionaryFile(dict_path); 304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 305c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete( 307c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DictionaryFile file) { 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dictionary_file_ = file.Pass(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 311c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!dictionary_file_.file.IsValid()) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Notify browser tests that this dictionary is corrupted. Skip downloading 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the dictionary in browser tests. 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rouslan): Remove this test-only case. 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (spellcheck_service_->SignalStatusEvent( 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService::BDICT_CORRUPTED)) { 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_context_getter_ = NULL; 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (request_context_getter_) { 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Download from the UI thread to check that |request_context_getter_| is 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // still valid. 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DownloadDictionary(GetDictionaryURL()); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfInitialization(); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool dictionary_saved) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dictionary_saved) { 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_NONE; 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_, 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnHunspellDictionaryDownloadSuccess()); 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Load(); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfDownloadFailure(); 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InformListenersOfInitialization(); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InformListenersOfInitialization() { 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryInitialized()); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() { 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_status_ = DOWNLOAD_FAILED; 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_, 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnHunspellDictionaryDownloadFailure()); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 358