spelling_service_client.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// Copyright (c) 2012 The Chromium Authors. All rights reserved.
294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// Use of this source code is governed by a BSD-style license that can be
394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// found in the LICENSE file.
494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "chrome/browser/spellchecker/spelling_service_client.h"
694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/command_line.h"
894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/json/json_reader.h"
994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/json/string_escape.h"
1094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/logging.h"
1194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/prefs/pref_service.h"
1294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/stl_util.h"
1394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/strings/string_util.h"
1494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/strings/stringprintf.h"
1594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/strings/utf_string_conversions.h"
1694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "base/values.h"
17d747129e1e8876f5a50f47156ec50b6969a638e4Nick Kralevich#include "chrome/common/chrome_switches.h"
1894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "chrome/common/pref_names.h"
1994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "chrome/common/spellcheck_common.h"
2094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "chrome/common/spellcheck_result.h"
2194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "components/user_prefs/user_prefs.h"
2294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "content/public/browser/browser_context.h"
2394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "google_apis/google_api_keys.h"
2494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "net/base/load_flags.h"
2594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "net/url_request/url_fetcher.h"
2694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "url/gurl.h"
2794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
2894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodnamespace {
2994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// The URL for requesting spell checking and sending user feedback.
31a2d838a542c34d2887a0ec1fafa5f47566d595e9Nick Kralevichconst char kSpellingServiceURL[] = "https://www.googleapis.com/rpc";
3294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// The location of spellcheck suggestions in JSON response from spelling
3494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// service.
3594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodconst char kMisspellingsPath[] = "result.spellingCheckResponse.misspellings";
3694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// The location of error messages in JSON response from spelling service.
3894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodconst char kErrorPath[] = "error";
3994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}  // namespace
4194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4294afecf4b6f437b3ee9a076242402e421c6c07a6Mike LockwoodSpellingServiceClient::SpellingServiceClient() {
4394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
4494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4594afecf4b6f437b3ee9a076242402e421c6c07a6Mike LockwoodSpellingServiceClient::~SpellingServiceClient() {
4694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  STLDeleteContainerPairPointers(spellcheck_fetchers_.begin(),
4794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                                 spellcheck_fetchers_.end());
4894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
4994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
5094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodbool SpellingServiceClient::RequestTextCheck(
5194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    content::BrowserContext* context,
5294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    ServiceType type,
5394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    const base::string16& text,
5494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    const TextCheckCompleteCallback& callback) {
5594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  DCHECK(type == SUGGEST || type == SPELLCHECK);
5694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (!context || !IsAvailable(context, type)) {
5794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    callback.Run(false, text, std::vector<SpellCheckResult>());
58a2d838a542c34d2887a0ec1fafa5f47566d595e9Nick Kralevich    return false;
5994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  }
6094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
6194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  const PrefService* pref = user_prefs::UserPrefs::Get(context);
62a2d838a542c34d2887a0ec1fafa5f47566d595e9Nick Kralevich  DCHECK(pref);
6394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
6494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::string language_code;
6594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::string country_code;
6694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  chrome::spellcheck_common::GetISOLanguageCountryCodeFromLocale(
6794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      pref->GetString(prefs::kSpellCheckDictionary),
6894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      &language_code,
6994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      &country_code);
7094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
7194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // Format the JSON request to be sent to the Spelling service.
7294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::string encoded_text;
7394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  base::JsonDoubleQuote(text, false, &encoded_text);
7494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
7594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  static const char kSpellingRequest[] =
7694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "{"
7794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"method\":\"spelling.check\","
7894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"apiVersion\":\"v%d\","
7994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"params\":{"
8094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"text\":\"%s\","
8194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"language\":\"%s\","
8294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"originCountry\":\"%s\","
8394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "\"key\":%s"
8494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "}"
8594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      "}";
8694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::string api_key = base::GetDoubleQuotedJson(google_apis::GetAPIKey());
8794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::string request = base::StringPrintf(
8894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      kSpellingRequest,
8994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      type,
9094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      encoded_text.c_str(),
9194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      language_code.c_str(),
9294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      country_code.c_str(),
9394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      api_key.c_str());
9494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
9594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  GURL url = GURL(kSpellingServiceURL);
9694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  net::URLFetcher* fetcher = CreateURLFetcher(url);
9794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  fetcher->SetRequestContext(context->GetRequestContext());
9894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  fetcher->SetUploadData("application/json", request);
9994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  fetcher->SetLoadFlags(
10094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES);
10194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  spellcheck_fetchers_[fetcher] = new TextCheckCallbackData(callback, text);
10294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  fetcher->Start();
10394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  return true;
10494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
10594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
10694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodbool SpellingServiceClient::IsAvailable(
10794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    content::BrowserContext* context,
10894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    ServiceType type) {
10994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  const PrefService* pref = user_prefs::UserPrefs::Get(context);
11094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  DCHECK(pref);
11194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // If prefs don't allow spellchecking or if the context is off the record,
11294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // the spelling service should be unavailable.
11394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (!pref->GetBoolean(prefs::kEnableContinuousSpellcheck) ||
11494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      !pref->GetBoolean(prefs::kSpellCheckUseSpellingService) ||
11594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      context->IsOffTheRecord())
11694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return false;
11794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
11894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // If the locale for spelling has not been set, the user has not decided to
11994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // use spellcheck so we don't do anything remote (suggest or spelling).
12094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::string locale = pref->GetString(prefs::kSpellCheckDictionary);
12194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (locale.empty())
12294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return false;
12394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
12494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // If we do not have the spelling service enabled, then we are only available
12594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // for SUGGEST.
12694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  const CommandLine* command_line = CommandLine::ForCurrentProcess();
12794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (command_line->HasSwitch(switches::kUseSpellingSuggestions))
12894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return type == SUGGEST;
12994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
13094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // Finally, if all options are available, we only enable only SUGGEST
13194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // if SPELLCHECK is not available for our language because SPELLCHECK results
13294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // are a superset of SUGGEST results.
13394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // TODO(rlp): Only available for English right now. Fix this line to include
13494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // all languages SPELLCHECK covers.
13594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  bool language_available = !locale.compare(0, 2, "en");
13694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (language_available) {
13794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return type == SPELLCHECK;
13894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  } else {
13994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // Only SUGGEST is allowed.
14094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return type == SUGGEST;
14194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  }
14294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
14394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
14494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodbool SpellingServiceClient::ParseResponse(
14594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    const std::string& data,
14694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    std::vector<SpellCheckResult>* results) {
14794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // When this JSON-RPC call finishes successfully, the Spelling service returns
14894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // an JSON object listed below.
14994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // * result - an envelope object representing the result from the APIARY
15094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   server, which is the JSON-API front-end for the Spelling service. This
15194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   object consists of the following variable:
15294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   - spellingCheckResponse (SpellingCheckResponse).
15394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // * SpellingCheckResponse - an object representing the result from the
15494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   Spelling service. This object consists of the following variable:
15594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   - misspellings (optional array of Misspelling)
15694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // * Misspelling - an object representing a misspelling region and its
15794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   suggestions. This object consists of the following variables:
15894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   - charStart (number) - the beginning of the misspelled region;
15994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   - charLength (number) - the length of the misspelled region;
16094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   - suggestions (array of string) - the suggestions for the misspelling
16194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     text, and;
16294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   - canAutoCorrect (optional boolean) - whether we can use the first
16394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     suggestion for auto-correction.
16494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // For example, the Spelling service returns the following JSON when we send a
16594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // spelling request for "duck goes quisk" as of 16 August, 2011.
16694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // {
16794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   "result": {
16894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     "spellingCheckResponse": {
16994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //       "misspellings": [{
17094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //           "charStart": 10,
17194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //           "charLength": 5,
17294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //           "suggestions": [{ "suggestion": "quack" }],
17394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //           "canAutoCorrect": false
17494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //       }]
17594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     }
17694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   }
17794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // }
17894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // If the service is not available, the Spelling service returns JSON with an
17994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // error.
18094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // {
18194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   "error": {
18294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     "code": 400,
18394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     "message": "Bad Request",
18494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //     "data": [...]
18594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  //   }
18694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // }
187a2d838a542c34d2887a0ec1fafa5f47566d595e9Nick Kralevich  scoped_ptr<DictionaryValue> value(
18894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      static_cast<DictionaryValue*>(
18994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood          base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS)));
19094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY))
19194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return false;
19294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
19394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // Check for errors from spelling service.
19494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  DictionaryValue* error = NULL;
19594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (value->GetDictionary(kErrorPath, &error))
19694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return false;
19794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
19894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // Retrieve the array of Misspelling objects. When the input text does not
19994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // have misspelled words, it returns an empty JSON. (In this case, its HTTP
20094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  // status is 200.) We just return true for this case.
20194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  ListValue* misspellings = NULL;
20294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (!value->GetList(kMisspellingsPath, &misspellings))
20394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return true;
20494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
20594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  for (size_t i = 0; i < misspellings->GetSize(); ++i) {
20694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // Retrieve the i-th misspelling region and put it to the given vector. When
207a2d838a542c34d2887a0ec1fafa5f47566d595e9Nick Kralevich    // the Spelling service sends two or more suggestions, we read only the
20894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // first one because SpellCheckResult can store only one suggestion.
20994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    DictionaryValue* misspelling = NULL;
21094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!misspellings->GetDictionary(i, &misspelling))
211a2d838a542c34d2887a0ec1fafa5f47566d595e9Nick Kralevich      return false;
21294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
21394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int start = 0;
21494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int length = 0;
21594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    ListValue* suggestions = NULL;
21694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!misspelling->GetInteger("charStart", &start) ||
21794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        !misspelling->GetInteger("charLength", &length) ||
21894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        !misspelling->GetList("suggestions", &suggestions)) {
21994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      return false;
22094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
22194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
22294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    DictionaryValue* suggestion = NULL;
22394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    base::string16 replacement;
22494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!suggestions->GetDictionary(0, &suggestion) ||
22594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        !suggestion->GetString("suggestion", &replacement)) {
22694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      return false;
22794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
22894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    SpellCheckResult result(
22994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        SpellCheckResult::SPELLING, start, length, replacement);
23094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    results->push_back(result);
23194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  }
23294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  return true;
23394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
23494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
23594afecf4b6f437b3ee9a076242402e421c6c07a6Mike LockwoodSpellingServiceClient::TextCheckCallbackData::TextCheckCallbackData(
23694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    TextCheckCompleteCallback callback,
23794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    base::string16 text)
23894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      : callback(callback),
23994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        text(text) {
24094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
24194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
24294afecf4b6f437b3ee9a076242402e421c6c07a6Mike LockwoodSpellingServiceClient::TextCheckCallbackData::~TextCheckCallbackData() {
24394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
24494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
24594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodvoid SpellingServiceClient::OnURLFetchComplete(
24694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    const net::URLFetcher* source) {
24794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  DCHECK(spellcheck_fetchers_[source]);
24894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  scoped_ptr<const net::URLFetcher> fetcher(source);
24994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  scoped_ptr<TextCheckCallbackData>
25094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood      callback_data(spellcheck_fetchers_[fetcher.get()]);
25194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  bool success = false;
25294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  std::vector<SpellCheckResult> results;
25394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  if (fetcher->GetResponseCode() / 100 == 2) {
25494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    std::string data;
25594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fetcher->GetResponseAsString(&data);
25694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    success = ParseResponse(data, &results);
25794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  }
25894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  callback_data->callback.Run(success, callback_data->text, results);
25994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  spellcheck_fetchers_.erase(fetcher.get());
26094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
26194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
26294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodnet::URLFetcher* SpellingServiceClient::CreateURLFetcher(const GURL& url) {
26394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood  return net::URLFetcher::Create(url, net::URLFetcher::POST, this);
26494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
26594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood