Spellchecker: Always destruct url request context getter on io thread.

To do this, we have to initiate downloads on the UI thread and don't hold onto a reference in the file thread.

BUG=27667

Review URL: http://codereview.chromium.org/387055

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32129 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/spellcheck_host.cc b/chrome/browser/spellcheck_host.cc
index e276473..446d19d 100644
--- a/chrome/browser/spellcheck_host.cc
+++ b/chrome/browser/spellcheck_host.cc
@@ -169,6 +169,8 @@
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
 
   observer_ = NULL;
+  request_context_getter_ = NULL;
+  fetcher_.reset();
 }
 
 void SpellCheckHost::AddWord(const std::string& word) {
@@ -210,11 +212,17 @@
       NULL);
 
   // File didn't exist. Download it.
-  if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_) {
-    DownloadDictionary();
+  if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ &&
+      request_context_getter_) {
+    // We download from the ui thread because we need to know that
+    // |request_context_getter_| is still valid before initiating the download.
+    ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+        NewRunnableMethod(this, &SpellCheckHost::DownloadDictionary));
     return;
   }
 
+  request_context_getter_ = NULL;
+
   if (file_ != base::kInvalidPlatformFileValue) {
     // Load custom dictionary.
     std::string contents;
@@ -230,6 +238,13 @@
           &SpellCheckHost::InformObserverOfInitialization));
 }
 
+void SpellCheckHost::InitializeOnFileThread() {
+  DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+  ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+      NewRunnableMethod(this, &SpellCheckHost::Initialize));
+}
+
 void SpellCheckHost::InformObserverOfInitialization() {
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
 
@@ -238,7 +253,12 @@
 }
 
 void SpellCheckHost::DownloadDictionary() {
-  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+  if (!request_context_getter_) {
+    InitializeOnFileThread();
+    return;
+  }
 
   // Determine URL of file to download.
   static const char kDownloadServerUrl[] =
@@ -246,9 +266,10 @@
   GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8(
       l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack())));
   fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
-  fetcher_->set_request_context(request_context_getter_.get());
+  fetcher_->set_request_context(request_context_getter_);
   tried_to_download_ = true;
   fetcher_->Start();
+  request_context_getter_ = NULL;
 }
 
 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) {
@@ -269,12 +290,13 @@
                                         const ResponseCookies& cookies,
                                         const std::string& data) {
   DCHECK(source);
-  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+  fetcher_.reset();
 
   if ((response_code / 100) != 2) {
     // Initialize will not try to download the file a second time.
     LOG(ERROR) << "Failure to download dictionary.";
-    Initialize();
+    InitializeOnFileThread();
     return;
   }
 
@@ -284,25 +306,35 @@
   if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' ||
       data[3] != 'c') {
     LOG(ERROR) << "Failure to download dictionary.";
-    Initialize();
+    InitializeOnFileThread();
     return;
   }
 
+  data_ = data;
+  ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+      NewRunnableMethod(this, &SpellCheckHost::SaveDictionaryData));
+}
+
+void SpellCheckHost::SaveDictionaryData() {
+  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
   size_t bytes_written =
-      file_util::WriteFile(bdict_file_path_, data.data(), data.length());
-  if (bytes_written != data.length()) {
+      file_util::WriteFile(bdict_file_path_, data_.data(), data_.length());
+  if (bytes_written != data_.length()) {
     bool success = false;
 #if defined(OS_WIN)
     bdict_file_path_ = GetFallbackFilePath(bdict_file_path_);
     bytes_written =
         file_util::WriteFile(GetFallbackFilePath(bdict_file_path_),
-                                                 data.data(), data.length());
-    if (bytes_written == data.length())
+                                                 data_.data(), data_.length());
+    if (bytes_written == data_.length())
       success = true;
 #endif
+    data_.clear();
 
     if (!success) {
       LOG(ERROR) << "Failure to save dictionary.";
+      file_util::Delete(bdict_file_path_, false);
       // To avoid trying to load a partially saved dictionary, shortcut the
       // Initialize() call.
       ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
@@ -312,5 +344,6 @@
     }
   }
 
+  data_.clear();
   Initialize();
 }