root/chrome/common/extensions/manifest_url_handler.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetManifestURL
  2. GetDevToolsPage
  3. GetHomepageURL
  4. GetUpdateURL
  5. UpdatesFromGallery
  6. UpdatesFromGallery
  7. GetOptionsPage
  8. GetDetailsURL
  9. GetChromeURLOverrides
  10. Parse
  11. Keys
  12. Parse
  13. Keys
  14. Parse
  15. Keys
  16. Parse
  17. Validate
  18. Keys
  19. Parse
  20. Keys

// Copyright (c) 2012 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/common/extensions/manifest_url_handler.h"

#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/url_constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/file_util.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

#if defined(USE_AURA)
#include "ui/keyboard/keyboard_constants.h"
#endif

namespace extensions {

namespace keys = manifest_keys;
namespace errors = manifest_errors;

namespace {

const char kOverrideExtentUrlPatternFormat[] = "chrome://%s/*";

const GURL& GetManifestURL(const Extension* extension,
                           const std::string& key) {
  ManifestURL* manifest_url =
      static_cast<ManifestURL*>(extension->GetManifestData(key));
  return manifest_url ? manifest_url->url_ : GURL::EmptyGURL();
}

}  // namespace

// static
const GURL& ManifestURL::GetDevToolsPage(const Extension* extension) {
  return GetManifestURL(extension, keys::kDevToolsPage);
}

// static
const GURL ManifestURL::GetHomepageURL(const Extension* extension) {
  const GURL& homepage_url = GetManifestURL(extension, keys::kHomepageURL);
  if (homepage_url.is_valid())
    return homepage_url;
  return UpdatesFromGallery(extension) ?
      GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
      GURL::EmptyGURL();
}

// static
const GURL& ManifestURL::GetUpdateURL(const Extension* extension) {
  return GetManifestURL(extension, keys::kUpdateURL);
}

// static
bool ManifestURL::UpdatesFromGallery(const Extension* extension) {
  return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension));
}

// static
bool  ManifestURL::UpdatesFromGallery(const base::DictionaryValue* manifest) {
  std::string url;
  if (!manifest->GetString(keys::kUpdateURL, &url))
    return false;
  return extension_urls::IsWebstoreUpdateUrl(GURL(url));
}

// static
const GURL& ManifestURL::GetOptionsPage(const Extension* extension) {
  return GetManifestURL(extension, keys::kOptionsPage);
}

// static
const GURL ManifestURL::GetDetailsURL(const Extension* extension) {
  return extension->from_webstore() ?
      GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
      GURL::EmptyGURL();
}

URLOverrides::URLOverrides() {
}

URLOverrides::~URLOverrides() {
}

static base::LazyInstance<URLOverrides::URLOverrideMap> g_empty_url_overrides =
    LAZY_INSTANCE_INITIALIZER;

// static
const URLOverrides::URLOverrideMap&
    URLOverrides::GetChromeURLOverrides(const Extension* extension) {
  URLOverrides* url_overrides = static_cast<URLOverrides*>(
      extension->GetManifestData(keys::kChromeURLOverrides));
  return url_overrides ?
         url_overrides->chrome_url_overrides_ :
         g_empty_url_overrides.Get();
}

DevToolsPageHandler::DevToolsPageHandler() {
}

DevToolsPageHandler::~DevToolsPageHandler() {
}

bool DevToolsPageHandler::Parse(Extension* extension, base::string16* error) {
  scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
  std::string devtools_str;
  if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
    *error = base::ASCIIToUTF16(errors::kInvalidDevToolsPage);
    return false;
  }
  manifest_url->url_ = extension->GetResourceURL(devtools_str);
  extension->SetManifestData(keys::kDevToolsPage, manifest_url.release());
  PermissionsData::GetInitialAPIPermissions(extension)->insert(
      APIPermission::kDevtools);
  return true;
}

const std::vector<std::string> DevToolsPageHandler::Keys() const {
  return SingleKey(keys::kDevToolsPage);
}

HomepageURLHandler::HomepageURLHandler() {
}

HomepageURLHandler::~HomepageURLHandler() {
}

bool HomepageURLHandler::Parse(Extension* extension, base::string16* error) {
  scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
  std::string homepage_url_str;
  if (!extension->manifest()->GetString(keys::kHomepageURL,
                                        &homepage_url_str)) {
    *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidHomepageURL,
                                                 std::string());
    return false;
  }
  manifest_url->url_ = GURL(homepage_url_str);
  if (!manifest_url->url_.is_valid() ||
      !manifest_url->url_.SchemeIsHTTPOrHTTPS()) {
    *error = ErrorUtils::FormatErrorMessageUTF16(
        errors::kInvalidHomepageURL, homepage_url_str);
    return false;
  }
  extension->SetManifestData(keys::kHomepageURL, manifest_url.release());
  return true;
}

const std::vector<std::string> HomepageURLHandler::Keys() const {
  return SingleKey(keys::kHomepageURL);
}

UpdateURLHandler::UpdateURLHandler() {
}

UpdateURLHandler::~UpdateURLHandler() {
}

bool UpdateURLHandler::Parse(Extension* extension, base::string16* error) {
  scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
  std::string tmp_update_url;

  if (!extension->manifest()->GetString(keys::kUpdateURL, &tmp_update_url)) {
    *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL,
                                                 std::string());
    return false;
  }

  manifest_url->url_ = GURL(tmp_update_url);
  if (!manifest_url->url_.is_valid() ||
      manifest_url->url_.has_ref()) {
    *error = ErrorUtils::FormatErrorMessageUTF16(
        errors::kInvalidUpdateURL, tmp_update_url);
    return false;
  }

  extension->SetManifestData(keys::kUpdateURL, manifest_url.release());
  return true;
}

const std::vector<std::string> UpdateURLHandler::Keys() const {
  return SingleKey(keys::kUpdateURL);
}

OptionsPageHandler::OptionsPageHandler() {
}

OptionsPageHandler::~OptionsPageHandler() {
}

bool OptionsPageHandler::Parse(Extension* extension, base::string16* error) {
  scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
  std::string options_str;
  if (!extension->manifest()->GetString(keys::kOptionsPage, &options_str)) {
    *error = base::ASCIIToUTF16(errors::kInvalidOptionsPage);
    return false;
  }

  if (extension->is_hosted_app()) {
    // hosted apps require an absolute URL.
    GURL options_url(options_str);
    if (!options_url.is_valid() ||
        !options_url.SchemeIsHTTPOrHTTPS()) {
      *error = base::ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
      return false;
    }
    manifest_url->url_ = options_url;
  } else {
    GURL absolute(options_str);
    if (absolute.is_valid()) {
      *error =
          base::ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
      return false;
    }
    manifest_url->url_ = extension->GetResourceURL(options_str);
    if (!manifest_url->url_.is_valid()) {
      *error = base::ASCIIToUTF16(errors::kInvalidOptionsPage);
      return false;
    }
  }

  extension->SetManifestData(keys::kOptionsPage, manifest_url.release());
  return true;
}

bool OptionsPageHandler::Validate(const Extension* extension,
                                  std::string* error,
                                  std::vector<InstallWarning>* warnings) const {
  // Validate path to the options page.  Don't check the URL for hosted apps,
  // because they are expected to refer to an external URL.
  if (!extensions::ManifestURL::GetOptionsPage(extension).is_empty() &&
      !extension->is_hosted_app()) {
    const base::FilePath options_path =
        extensions::file_util::ExtensionURLToRelativeFilePath(
            extensions::ManifestURL::GetOptionsPage(extension));
    const base::FilePath path =
        extension->GetResource(options_path).GetFilePath();
    if (path.empty() || !base::PathExists(path)) {
      *error =
          l10n_util::GetStringFUTF8(
              IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED,
              options_path.LossyDisplayName());
      return false;
    }
  }
  return true;
}

const std::vector<std::string> OptionsPageHandler::Keys() const {
  return SingleKey(keys::kOptionsPage);
}

URLOverridesHandler::URLOverridesHandler() {
}

URLOverridesHandler::~URLOverridesHandler() {
}

bool URLOverridesHandler::Parse(Extension* extension, base::string16* error) {
  const base::DictionaryValue* overrides = NULL;
  if (!extension->manifest()->GetDictionary(keys::kChromeURLOverrides,
                                            &overrides)) {
    *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
    return false;
  }
  scoped_ptr<URLOverrides> url_overrides(new URLOverrides);
  // Validate that the overrides are all strings
  for (base::DictionaryValue::Iterator iter(*overrides); !iter.IsAtEnd();
         iter.Advance()) {
    std::string page = iter.key();
    std::string val;
    // Restrict override pages to a list of supported URLs.
    bool is_override = (page != chrome::kChromeUINewTabHost &&
                        page != chrome::kChromeUIBookmarksHost &&
                        page != chrome::kChromeUIHistoryHost);
#if defined(OS_CHROMEOS)
    is_override = (is_override &&
                   page != chrome::kChromeUIActivationMessageHost);
#endif
#if defined(OS_CHROMEOS)
    is_override = (is_override && page != keyboard::kKeyboardHost);
#endif

    if (is_override || !iter.value().GetAsString(&val)) {
      *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
      return false;
    }
    // Replace the entry with a fully qualified chrome-extension:// URL.
    url_overrides->chrome_url_overrides_[page] = extension->GetResourceURL(val);

    // For component extensions, add override URL to extent patterns.
    if (extension->is_legacy_packaged_app() &&
        extension->location() == Manifest::COMPONENT) {
      URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
      std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
                                           page.c_str());
      if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
        *error = ErrorUtils::FormatErrorMessageUTF16(
            errors::kInvalidURLPatternError, url);
        return false;
      }
      extension->AddWebExtentPattern(pattern);
    }
  }

  // An extension may override at most one page.
  if (overrides->size() > 1) {
    *error = base::ASCIIToUTF16(errors::kMultipleOverrides);
    return false;
  }
  extension->SetManifestData(keys::kChromeURLOverrides,
                             url_overrides.release());
  return true;
}

const std::vector<std::string> URLOverridesHandler::Keys() const {
  return SingleKey(keys::kChromeURLOverrides);
}

}  // namespace extensions

/* [<][>][^][v][top][bottom][index][help] */