<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/webstore_inline_installer.h"

#include <vector>

#include "base/bind.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_dialog.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/url_pattern.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/utility_process_host.h"
#include "content/public/common/url_fetcher.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_status.h"

using content::BrowserThread;

const char kManifestKey[] = "manifest";
const char kIconUrlKey[] = "icon_url";
const char kLocalizedNameKey[] = "localized_name";
const char kLocalizedDescriptionKey[] = "localized_description";
const char kUsersKey[] = "users";
const char kAverageRatingKey[] = "average_rating";
const char kRatingCountKey[] = "rating_count";
const char kVerifiedSiteKey[] = "verified_site";
const char kInlineInstallNotSupportedKey[] = "inline_install_not_supported";
const char kRedirectUrlKey[] = "redirect_url";

const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
const char kWebstoreRequestError[] =
    "Could not fetch data from the Chrome Web Store";
const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
const char kInvalidManifestError[] = "Invalid manifest";
const char kUserCancelledError[] = "User cancelled install";
const char kNoVerifiedSiteError[] =
    "Inline installs can only be initiated for Chrome Web Store items that "
    "have a verified site";
const char kNotFromVerifiedSiteError[] =
    "Installs can only be initiated by the Chrome Web Store item's verified "
    "site";
const char kInlineInstallSupportedError[] =
    "Inline installation is not supported for this item. The user will be "
    "redirected to the Chrome Web Store.";

class SafeWebstoreResponseParser : public UtilityProcessHost::Client {
 public:
  SafeWebstoreResponseParser(WebstoreInlineInstaller *client,
                             const std::string& webstore_data)
      : client_(client),
        webstore_data_(webstore_data),
        utility_host_(NULL) {}

  void Start() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&SafeWebstoreResponseParser::StartWorkOnIOThread, this));
  }

  void StartWorkOnIOThread() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    utility_host_ = new UtilityProcessHost(this, BrowserThread::IO);
    utility_host_->Send(new ChromeUtilityMsg_ParseJSON(webstore_data_));
  }

  // Implementing pieces of the UtilityProcessHost::Client interface.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(SafeWebstoreResponseParser, message)
      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
                          OnJSONParseSucceeded)
      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
                          OnJSONParseFailed)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
  }

  void OnJSONParseSucceeded(const ListValue& wrapper) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    Value* value = NULL;
    CHECK(wrapper.Get(0, &value));
    if (value->IsType(Value::TYPE_DICTIONARY)) {
      parsed_webstore_data_.reset(
          static_cast<DictionaryValue*>(value)->DeepCopy());
    } else {
      error_ = kInvalidWebstoreResponseError;
    }

    ReportResults();
  }

  virtual void OnJSONParseFailed(const std::string& error_message) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    error_ = error_message;
    ReportResults();
  }

  void ReportResults() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

    // The utility_host_ will take care of deleting itself after this call.
    utility_host_ = NULL;

    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(&SafeWebstoreResponseParser::ReportResultOnUIThread, this));
  }

  void ReportResultOnUIThread() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    if (error_.empty() && parsed_webstore_data_.get()) {
      client_->OnWebstoreResponseParseSuccess(parsed_webstore_data_.release());
    } else {
      client_->OnWebstoreResponseParseFailure(error_);
    }
  }

 private:
  virtual ~SafeWebstoreResponseParser() {}

  WebstoreInlineInstaller* client_;

  std::string webstore_data_;

  UtilityProcessHost* utility_host_;

  std::string error_;
  scoped_ptr<DictionaryValue> parsed_webstore_data_;
};

WebstoreInlineInstaller::WebstoreInlineInstaller(TabContents* tab_contents,
                                                 int install_id,
                                                 std::string webstore_item_id,
                                                 GURL requestor_url,
                                                 Delegate* delegate)
    : TabContentsObserver(tab_contents),
      install_id_(install_id),
      id_(webstore_item_id),
      requestor_url_(requestor_url),
      delegate_(delegate),
      average_rating_(0.0),
      rating_count_(0) {}

WebstoreInlineInstaller::~WebstoreInlineInstaller() {
}

void WebstoreInlineInstaller::BeginInstall() {
  AddRef(); // Balanced in CompleteInstall or TabContentsDestroyed.

  if (!Extension::IdIsValid(id_)) {
    CompleteInstall(kInvalidWebstoreItemId);
    return;
  }

  GURL webstore_data_url(extension_urls::GetWebstoreItemJsonDataURL(id_));

  webstore_data_url_fetcher_.reset(content::URLFetcher::Create(
      webstore_data_url, content::URLFetcher::GET, this));
  Profile* profile = Profile::FromBrowserContext(
      tab_contents()->browser_context());
  webstore_data_url_fetcher_->SetRequestContext(
      profile->GetRequestContext());
  webstore_data_url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
                                           net::LOAD_DO_NOT_SAVE_COOKIES |
                                           net::LOAD_DISABLE_CACHE);
  webstore_data_url_fetcher_->Start();
}

void WebstoreInlineInstaller::OnURLFetchComplete(
    const content::URLFetcher* source) {
  CHECK_EQ(webstore_data_url_fetcher_.get(), source);
  // We shouldn't be getting UrlFetcher callbacks if the TabContents has gone
  // away; we stop any in in-progress fetches in TabContentsDestroyed.
  CHECK(tab_contents());<commit_msg>Set referrer for webstore inline install requests, so we can see what the top pages that use it are<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/webstore_inline_installer.h"

#include <vector>

#include "base/bind.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_dialog.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/url_pattern.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/utility_process_host.h"
#include "content/public/common/url_fetcher.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_status.h"

using content::BrowserThread;

const char kManifestKey[] = "manifest";
const char kIconUrlKey[] = "icon_url";
const char kLocalizedNameKey[] = "localized_name";
const char kLocalizedDescriptionKey[] = "localized_description";
const char kUsersKey[] = "users";
const char kAverageRatingKey[] = "average_rating";
const char kRatingCountKey[] = "rating_count";
const char kVerifiedSiteKey[] = "verified_site";
const char kInlineInstallNotSupportedKey[] = "inline_install_not_supported";
const char kRedirectUrlKey[] = "redirect_url";

const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
const char kWebstoreRequestError[] =
    "Could not fetch data from the Chrome Web Store";
const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
const char kInvalidManifestError[] = "Invalid manifest";
const char kUserCancelledError[] = "User cancelled install";
const char kNoVerifiedSiteError[] =
    "Inline installs can only be initiated for Chrome Web Store items that "
    "have a verified site";
const char kNotFromVerifiedSiteError[] =
    "Installs can only be initiated by the Chrome Web Store item's verified "
    "site";
const char kInlineInstallSupportedError[] =
    "Inline installation is not supported for this item. The user will be "
    "redirected to the Chrome Web Store.";

class SafeWebstoreResponseParser : public UtilityProcessHost::Client {
 public:
  SafeWebstoreResponseParser(WebstoreInlineInstaller *client,
                             const std::string& webstore_data)
      : client_(client),
        webstore_data_(webstore_data),
        utility_host_(NULL) {}

  void Start() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&SafeWebstoreResponseParser::StartWorkOnIOThread, this));
  }

  void StartWorkOnIOThread() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    utility_host_ = new UtilityProcessHost(this, BrowserThread::IO);
    utility_host_->Send(new ChromeUtilityMsg_ParseJSON(webstore_data_));
  }

  // Implementing pieces of the UtilityProcessHost::Client interface.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(SafeWebstoreResponseParser, message)
      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
                          OnJSONParseSucceeded)
      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
                          OnJSONParseFailed)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
  }

  void OnJSONParseSucceeded(const ListValue& wrapper) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    Value* value = NULL;
    CHECK(wrapper.Get(0, &value));
    if (value->IsType(Value::TYPE_DICTIONARY)) {
      parsed_webstore_data_.reset(
          static_cast<DictionaryValue*>(value)->DeepCopy());
    } else {
      error_ = kInvalidWebstoreResponseError;
    }

    ReportResults();
  }

  virtual void OnJSONParseFailed(const std::string& error_message) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    error_ = error_message;
    ReportResults();
  }

  void ReportResults() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

    // The utility_host_ will take care of deleting itself after this call.
    utility_host_ = NULL;

    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(&SafeWebstoreResponseParser::ReportResultOnUIThread, this));
  }

  void ReportResultOnUIThread() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    if (error_.empty() && parsed_webstore_data_.get()) {
      client_->OnWebstoreResponseParseSuccess(parsed_webstore_data_.release());
    } else {
      client_->OnWebstoreResponseParseFailure(error_);
    }
  }

 private:
  virtual ~SafeWebstoreResponseParser() {}

  WebstoreInlineInstaller* client_;

  std::string webstore_data_;

  UtilityProcessHost* utility_host_;

  std::string error_;
  scoped_ptr<DictionaryValue> parsed_webstore_data_;
};

WebstoreInlineInstaller::WebstoreInlineInstaller(TabContents* tab_contents,
                                                 int install_id,
                                                 std::string webstore_item_id,
                                                 GURL requestor_url,
                                                 Delegate* delegate)
    : TabContentsObserver(tab_contents),
      install_id_(install_id),
      id_(webstore_item_id),
      requestor_url_(requestor_url),
      delegate_(delegate),
      average_rating_(0.0),
      rating_count_(0) {}

WebstoreInlineInstaller::~WebstoreInlineInstaller() {
}

void WebstoreInlineInstaller::BeginInstall() {
  AddRef(); // Balanced in CompleteInstall or TabContentsDestroyed.

  if (!Extension::IdIsValid(id_)) {
    CompleteInstall(kInvalidWebstoreItemId);
    return;
  }

  GURL webstore_data_url(extension_urls::GetWebstoreItemJsonDataURL(id_));

  webstore_data_url_fetcher_.reset(content::URLFetcher::Create(
      webstore_data_url, content::URLFetcher::GET, this));
  Profile* profile = Profile::FromBrowserContext(
      tab_contents()->browser_context());
  webstore_data_url_fetcher_->SetRequestContext(
      profile->GetRequestContext());
  // Use the requesting page as the referrer both since that is more correct
  // (it is the page that caused this request to happen) and so that we can
  // track top sites that trigger inline install requests.
  webstore_data_url_fetcher_->SetReferrer(requestor_url_.spec());
  webstore_data_url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
                                           net::LOAD_DO_NOT_SAVE_COOKIES |
                                           net::LOAD_DISABLE_CACHE);
  webstore_data_url_fetcher_->Start();
}

void WebstoreInlineInstaller::OnURLFetchComplete(
    const content::URLFetcher* source) {
  CHECK_EQ(webstore_data_url_fetcher_.get(), source);
  // We shouldn't be getting UrlFetcher callbacks if the TabContents has gone
  // away; we stop any in in-progress fetches in TabContentsDestroyed.
  CHECK(tab_contents());
{'fraction_non_alphanumeric': 0.09806094182825485, 'fraction_numerical': 0.00110803324099723, 'mean_word_length': 4.08128078817734, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7655743', 'n_tokens_mistral': 4170, 'n_tokens_neox': 4126, 'n_words': 868}