Index: content/common/content_security_policy/csp_source_list.cc |
diff --git a/content/common/content_security_policy/csp_source_list.cc b/content/common/content_security_policy/csp_source_list.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..19f2b23c2a5c4c3afd1c44f15619bdc3468ec693 |
--- /dev/null |
+++ b/content/common/content_security_policy/csp_source_list.cc |
@@ -0,0 +1,134 @@ |
+// Copyright 2017 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 <algorithm> |
+ |
+#include "base/strings/string_split.h" |
+#include "content/common/content_security_policy/csp_context.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+void ReportInvalidSourceExpression(CSPContext* context, |
+ const base::StringPiece& directive_name, |
+ const base::StringPiece& source_expression) { |
+ std::string message = |
+ "The source list for Content Security Policy directive '" + |
+ directive_name.as_string() + "' contains an invalid source: '" + |
+ source_expression.as_string() + "'. It will be ignored."; |
+ |
+ if (source_expression == "'none'") |
+ message += |
+ " Note that 'none' has no effect unless it is the only expression in " |
+ "the source list."; |
+ |
+ context->LogToConsole(message); |
+} |
+ |
+} // namespace; |
+ |
+CSPSourceList::CSPSourceList() |
+ : allow_self(false), allow_star(false), source_list() {} |
+ |
+CSPSourceList::CSPSourceList(bool allow_self, |
+ bool allow_star, |
+ std::vector<CSPSource> source_list) |
+ : allow_self(allow_self), allow_star(allow_star), source_list(source_list) { |
+ DCHECK(!allow_star || (allow_self || source_list.empty())); |
+} |
+ |
+CSPSourceList::CSPSourceList(const CSPSourceList&) = default; |
+CSPSourceList::~CSPSourceList() = default; |
+ |
+// static |
+CSPSourceList CSPSourceList::Parse(CSPContext* context, |
+ const base::StringPiece& directive_name, |
+ const base::StringPiece& directive_value) { |
+ CSPSourceList source_list; |
+ // serialized-source-list = ( source-expression *( RWS source-expression ) ) |
+ // / "'none'" |
+ std::vector<base::StringPiece> source_expressions = base::SplitStringPiece( |
+ directive_value, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
+ |
+ if (source_expressions.size() == 1 && source_expressions[0] == "'none'") |
+ return source_list; |
+ |
+ for (const base::StringPiece& source_expression : source_expressions) { |
+ if (source_expression == "'none'") { |
+ ReportInvalidSourceExpression(context, directive_name, source_expression); |
+ } else if (source_expression == "'self'") { |
+ source_list.allow_self = true; |
+ } else if (source_expression == "*") { |
+ source_list.allow_star = true; |
+ } else { |
+ if (auto source = CSPSource::Parse(source_expression.as_string())) { |
+ source_list.source_list.push_back(*source); |
+ } else { |
+ ReportInvalidSourceExpression(context, directive_name, |
+ source_expression); |
+ } |
+ } |
+ } |
+ return source_list; |
+} |
+ |
+bool CSPSourceList::Allow(CSPContext* context, |
+ const GURL& url, |
+ bool is_redirect) const { |
+ // Wildcards match network schemes ('http', 'https', 'ftp', 'ws', 'wss'), and |
+ // the scheme of the protected resource: |
+ // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other |
+ // schemes, including custom schemes, must be explicitly listed in a source |
+ // list. |
+ if (allow_star) { |
+ if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsSuborigin() || |
+ url.SchemeIsWSOrWSS() || url.SchemeIs("ftp") || |
+ context->ProtocolMatchesSelf(url)) |
+ return true; |
+ |
+ return AllowFromSources(context, url, is_redirect); |
+ } |
+ |
+ // TODO(arthursonzogni): compute the effectiveURL in the same way it is done |
+ // in SourceListDirective.cpp |
+ |
+ if (allow_self && context->AllowSelf(url)) |
+ return true; |
+ |
+ return AllowFromSources(context, url, is_redirect); |
+} |
+ |
+bool CSPSourceList::AllowFromSources(CSPContext* context, |
+ const GURL& url, |
+ bool is_redirect) const { |
+ for (const CSPSource& source : source_list) { |
+ if (source.Allow(context, url, is_redirect)) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+std::string CSPSourceList::ToString() const { |
+ if (allow_star) |
+ return "*"; |
+ |
+ bool is_empty = true; |
+ std::stringstream text; |
+ if (allow_self) { |
+ text << "'self'"; |
+ is_empty = false; |
+ } |
+ |
+ for (const auto& source : source_list) { |
+ if (!is_empty) |
+ text << " "; |
+ text << source.ToString(); |
+ is_empty = false; |
+ } |
+ |
+ return text.str(); |
+} |
+ |
+} // namespace content |