blob: f6c142f8683c83c1a7627fc2ea84614a8c08051d [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cobalt/csp/source.h"
#include "base/logging.h"
#include "base/string_util.h"
namespace cobalt {
namespace csp {
Source::Source(ContentSecurityPolicy* policy, const SourceConfig& config)
: policy_(policy) {
// All comparisons require case-insensitivity.
// Lower-case everything here to simplify that.
config_.scheme = StringToLowerASCII(config.scheme);
config_.host = StringToLowerASCII(config.host);
config_.path = StringToLowerASCII(config.path);
config_.port = config.port;
config_.host_wildcard = config.host_wildcard;
config_.port_wildcard = config.port_wildcard;
}
// https://www.w3.org/TR/2015/CR-CSP2-20150721/#match-source-expression
bool Source::Matches(
const GURL& url,
ContentSecurityPolicy::RedirectStatus redirect_status) const {
if (!SchemeMatches(url)) {
return false;
}
if (IsSchemeOnly()) {
return true;
}
if (!HostMatches(url)) {
return false;
}
if (!PortMatches(url)) {
return false;
}
bool paths_match = (redirect_status == ContentSecurityPolicy::kDidRedirect) ||
PathMatches(url);
return paths_match;
}
bool Source::SchemeMatches(const GURL& url) const {
if (config_.scheme.empty()) {
return policy_->SchemeMatchesSelf(url);
}
if (LowerCaseEqualsASCII(config_.scheme, "http")) {
return url.SchemeIs("http") || url.SchemeIs("https");
}
if (LowerCaseEqualsASCII(config_.scheme, "ws")) {
return url.SchemeIs("ws") || url.SchemeIs("wss");
}
return url.SchemeIs(config_.scheme.c_str());
}
bool Source::HostMatches(const GURL& url) const {
const std::string& host = url.host();
bool match;
if (config_.host_wildcard == SourceConfig::kHasWildcard) {
match = EndsWith(host, "." + config_.host, false /* case_sensitive */);
} else {
match = LowerCaseEqualsASCII(host, config_.host.c_str());
}
return match;
}
bool Source::PathMatches(const GURL& url) const {
if (config_.path.empty()) {
return true;
}
std::string path = StringToLowerASCII(url.path());
if (EndsWith(config_.path, "/", true /* case sensitive */)) {
return StartsWithASCII(path, config_.path, true /* case_sensitive */);
} else {
return path == config_.path;
}
}
// https://www.w3.org/TR/2015/CR-CSP2-20150721/#match-source-expression #9-10
bool Source::PortMatches(const GURL& url) const {
if (config_.port_wildcard == SourceConfig::kHasWildcard) {
return true;
}
// Matches if ports are the same. If a port is unspecified, consider it as
// the default port for url's scheme.
const std::string& url_scheme = url.scheme();
int config_port = config_.port;
if (config_port == url_parse::PORT_UNSPECIFIED) {
config_port = url_canon::DefaultPortForScheme(
url_scheme.c_str(), static_cast<int>(url_scheme.length()));
}
int url_port = url.EffectiveIntPort();
if (url_port == config_port) {
return true;
}
return false;
}
bool Source::IsSchemeOnly() const { return config_.host.empty(); }
} // namespace csp
} // namespace cobalt