This source file includes following definitions.
- Sorted
- Parse
- Keys
- Get
- FromValue
- accepts_tls_channel_id
- IdCanConnect
#include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
#include <algorithm>
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/extensions/api/manifest_types.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/url_pattern.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "url/gurl.h"
namespace rcd = net::registry_controlled_domains;
namespace extensions {
namespace externally_connectable_errors {
const char kErrorInvalidMatchPattern[] = "Invalid match pattern '*'";
const char kErrorInvalidId[] = "Invalid ID '*'";
const char kErrorNothingSpecified[] =
"'externally_connectable' specifies neither 'matches' nor 'ids'; "
"nothing will be able to connect";
const char kErrorTopLevelDomainsNotAllowed[] =
"\"*\" is an effective top level domain for which wildcard subdomains such "
"as \"*\" are not allowed";
const char kErrorWildcardHostsNotAllowed[] =
"Wildcard domain patterns such as \"*\" are not allowed";
}
namespace keys = extensions::manifest_keys;
namespace errors = externally_connectable_errors;
using api::manifest_types::ExternallyConnectable;
namespace {
const char kAllIds[] = "*";
template <typename T>
std::vector<T> Sorted(const std::vector<T>& in) {
std::vector<T> out = in;
std::sort(out.begin(), out.end());
return out;
}
}
ExternallyConnectableHandler::ExternallyConnectableHandler() {}
ExternallyConnectableHandler::~ExternallyConnectableHandler() {}
bool ExternallyConnectableHandler::Parse(Extension* extension,
base::string16* error) {
const base::Value* externally_connectable = NULL;
CHECK(extension->manifest()->Get(keys::kExternallyConnectable,
&externally_connectable));
std::vector<InstallWarning> install_warnings;
scoped_ptr<ExternallyConnectableInfo> info =
ExternallyConnectableInfo::FromValue(*externally_connectable,
&install_warnings,
error);
if (!info)
return false;
if (!info->matches.is_empty()) {
PermissionsData::GetInitialAPIPermissions(extension)->insert(
APIPermission::kWebConnectable);
}
extension->AddInstallWarnings(install_warnings);
extension->SetManifestData(keys::kExternallyConnectable, info.release());
return true;
}
const std::vector<std::string> ExternallyConnectableHandler::Keys() const {
return SingleKey(keys::kExternallyConnectable);
}
ExternallyConnectableInfo* ExternallyConnectableInfo::Get(
const Extension* extension) {
return static_cast<ExternallyConnectableInfo*>(
extension->GetManifestData(keys::kExternallyConnectable));
}
scoped_ptr<ExternallyConnectableInfo> ExternallyConnectableInfo::FromValue(
const base::Value& value,
std::vector<InstallWarning>* install_warnings,
base::string16* error) {
scoped_ptr<ExternallyConnectable> externally_connectable =
ExternallyConnectable::FromValue(value, error);
if (!externally_connectable)
return scoped_ptr<ExternallyConnectableInfo>();
URLPatternSet matches;
if (externally_connectable->matches) {
for (std::vector<std::string>::iterator it =
externally_connectable->matches->begin();
it != externally_connectable->matches->end(); ++it) {
URLPattern pattern(URLPattern::SCHEME_ALL);
if (pattern.Parse(*it) != URLPattern::PARSE_SUCCESS) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kErrorInvalidMatchPattern, *it);
return scoped_ptr<ExternallyConnectableInfo>();
}
if (pattern.host().empty()) {
install_warnings->push_back(InstallWarning(
ErrorUtils::FormatErrorMessage(
errors::kErrorWildcardHostsNotAllowed, *it),
keys::kExternallyConnectable,
*it));
continue;
}
size_t registry_length = rcd::GetRegistryLength(
pattern.host(),
rcd::INCLUDE_UNKNOWN_REGISTRIES,
rcd::INCLUDE_PRIVATE_REGISTRIES);
if (registry_length == std::string::npos) {
NOTREACHED() << *it;
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kErrorInvalidMatchPattern, *it);
return scoped_ptr<ExternallyConnectableInfo>();
}
if (registry_length == 0 && pattern.match_subdomains()) {
install_warnings->push_back(InstallWarning(
ErrorUtils::FormatErrorMessage(
errors::kErrorTopLevelDomainsNotAllowed,
pattern.host().c_str(),
*it),
keys::kExternallyConnectable,
*it));
continue;
}
matches.AddPattern(pattern);
}
}
std::vector<std::string> ids;
bool all_ids = false;
if (externally_connectable->ids) {
for (std::vector<std::string>::iterator it =
externally_connectable->ids->begin();
it != externally_connectable->ids->end(); ++it) {
if (*it == kAllIds) {
all_ids = true;
} else if (Extension::IdIsValid(*it)) {
ids.push_back(*it);
} else {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kErrorInvalidId, *it);
return scoped_ptr<ExternallyConnectableInfo>();
}
}
}
if (!externally_connectable->matches &&
!externally_connectable->ids) {
install_warnings->push_back(InstallWarning(
errors::kErrorNothingSpecified,
keys::kExternallyConnectable));
}
bool accepts_tls_channel_id =
externally_connectable->accepts_tls_channel_id.get() &&
*externally_connectable->accepts_tls_channel_id;
return make_scoped_ptr(
new ExternallyConnectableInfo(matches, ids, all_ids,
accepts_tls_channel_id));
}
ExternallyConnectableInfo::~ExternallyConnectableInfo() {}
ExternallyConnectableInfo::ExternallyConnectableInfo(
const URLPatternSet& matches,
const std::vector<std::string>& ids,
bool all_ids,
bool accepts_tls_channel_id)
: matches(matches), ids(Sorted(ids)), all_ids(all_ids),
accepts_tls_channel_id(accepts_tls_channel_id) {}
bool ExternallyConnectableInfo::IdCanConnect(const std::string& id) {
if (all_ids)
return true;
DCHECK(base::STLIsSorted(ids));
return std::binary_search(ids.begin(), ids.end(), id);
}
}