summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/frame/csp
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/core/frame/csp
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/frame/csp')
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPDirective.h38
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp679
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h141
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp93
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.h39
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp485
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h65
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp786
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h203
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.cpp86
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.h31
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp62
-rw-r--r--chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h38
13 files changed, 2746 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirective.h b/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirective.h
new file mode 100644
index 00000000000..e870ccb9c94
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirective.h
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+#ifndef CSPDirective_h
+#define CSPDirective_h
+
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ContentSecurityPolicy;
+class KURL;
+
+class CSPDirective {
+ WTF_MAKE_NONCOPYABLE(CSPDirective);
+public:
+ CSPDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
+ : m_name(name)
+ , m_text(name + ' ' + value)
+ , m_policy(policy)
+ {
+ }
+
+ const String& text() const { return m_text; }
+
+protected:
+ const ContentSecurityPolicy* policy() const { return m_policy; }
+
+private:
+ String m_name;
+ String m_text;
+ ContentSecurityPolicy* m_policy;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
new file mode 100644
index 00000000000..a453dfdeb6c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -0,0 +1,679 @@
+// Copyright 2014 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 "config.h"
+#include "core/frame/csp/CSPDirectiveList.h"
+
+#include "core/frame/LocalFrame.h"
+#include "platform/ParsingUtilities.h"
+#include "platform/weborigin/KURL.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
+ : m_policy(policy)
+ , m_headerType(type)
+ , m_headerSource(source)
+ , m_reportOnly(false)
+ , m_haveSandboxPolicy(false)
+ , m_reflectedXSSDisposition(ReflectedXSSUnset)
+ , m_didSetReferrerPolicy(false)
+ , m_referrerPolicy(ReferrerPolicyDefault)
+{
+ m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport;
+}
+
+PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* policy, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
+{
+ OwnPtr<CSPDirectiveList> directives = adoptPtr(new CSPDirectiveList(policy, type, source));
+ directives->parse(begin, end);
+
+ if (!directives->checkEval(directives->operativeDirective(directives->m_scriptSrc.get()))) {
+ String message = "Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"" + directives->operativeDirective(directives->m_scriptSrc.get())->text() + "\".\n";
+ directives->setEvalDisabledErrorMessage(message);
+ }
+
+ if (directives->isReportOnly() && directives->reportURIs().isEmpty())
+ policy->reportMissingReportURI(String(begin, end - begin));
+
+ return directives.release();
+}
+
+void CSPDirectiveList::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const
+{
+ String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
+ m_policy->executionContext()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
+ m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
+}
+
+void CSPDirectiveList::reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
+{
+ String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
+ m_policy->executionContext()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt());
+ m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
+}
+
+void CSPDirectiveList::reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptState* scriptState) const
+{
+ String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
+ m_policy->executionContext()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, scriptState);
+ m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
+}
+
+bool CSPDirectiveList::checkEval(SourceListDirective* directive) const
+{
+ return !directive || directive->allowEval();
+}
+
+bool CSPDirectiveList::checkInline(SourceListDirective* directive) const
+{
+ return !directive || (directive->allowInline() && !directive->isHashOrNoncePresent());
+}
+
+bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String& nonce) const
+{
+ return !directive || directive->allowNonce(nonce);
+}
+
+bool CSPDirectiveList::checkHash(SourceListDirective* directive, const CSPHashValue& hashValue) const
+{
+ return !directive || directive->allowHash(hashValue);
+}
+
+bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& url) const
+{
+ return !directive || directive->allows(url);
+}
+
+bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, LocalFrame* frame) const
+{
+ if (!frame || !directive)
+ return true;
+
+ for (Frame* current = frame->tree().parent(); current; current = current->tree().parent()) {
+ // FIXME: To make this work for out-of-process iframes, we need to propagate URL information of ancestor frames across processes.
+ if (!current->isLocalFrame() || !directive->allows(toLocalFrame(current)->document()->url()))
+ return false;
+ }
+ return true;
+}
+
+bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
+{
+ if (!directive)
+ return true;
+ if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
+ return false;
+ return directive->allows(type);
+}
+
+SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive) const
+{
+ return directive ? directive : m_defaultSrc.get();
+}
+
+SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive, SourceListDirective* override) const
+{
+ return directive ? directive : override;
+}
+
+bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, ScriptState* scriptState) const
+{
+ if (checkEval(directive))
+ return true;
+
+ String suffix = String();
+ if (directive == m_defaultSrc)
+ suffix = " Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.";
+
+ reportViolationWithState(directive->text(), ContentSecurityPolicy::ScriptSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), scriptState);
+ if (!m_reportOnly) {
+ m_policy->reportBlockedScriptExecutionToInspector(directive->text());
+ return false;
+ }
+ return true;
+}
+
+bool CSPDirectiveList::checkMediaTypeAndReportViolation(MediaListDirective* directive, const String& type, const String& typeAttribute, const String& consoleMessage) const
+{
+ if (checkMediaType(directive, type, typeAttribute))
+ return true;
+
+ String message = consoleMessage + "\'" + directive->text() + "\'.";
+ if (typeAttribute.isEmpty())
+ message = message + " When enforcing the 'plugin-types' directive, the plugin's media type must be explicitly declared with a 'type' attribute on the containing element (e.g. '<object type=\"[TYPE GOES HERE]\" ...>').";
+
+ reportViolation(directive->text(), ContentSecurityPolicy::PluginTypes, message + "\n", KURL());
+ return denyIfEnforcingPolicy();
+}
+
+bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const
+{
+ if (checkInline(directive))
+ return true;
+
+ String suffix = String();
+ if (directive->allowInline() && directive->isHashOrNoncePresent()) {
+ // If inline is allowed, but a hash or nonce is present, we ignore 'unsafe-inline'. Throw a reasonable error.
+ suffix = " Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.";
+ } else {
+ suffix = " Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.";
+ if (directive == m_defaultSrc)
+ suffix = suffix + " Note also that '" + String(isScript ? "script" : "style") + "-src' was not explicitly set, so 'default-src' is used as a fallback.";
+ }
+
+ reportViolationWithLocation(directive->text(), isScript ? ContentSecurityPolicy::ScriptSrc : ContentSecurityPolicy::StyleSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine);
+
+ if (!m_reportOnly) {
+ if (isScript)
+ m_policy->reportBlockedScriptExecutionToInspector(directive->text());
+ return false;
+ }
+ return true;
+}
+
+bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& effectiveDirective) const
+{
+ if (checkSource(directive, url))
+ return true;
+
+ String prefix;
+ if (ContentSecurityPolicy::BaseURI == effectiveDirective)
+ prefix = "Refused to set the document's base URI to '";
+ else if (ContentSecurityPolicy::ChildSrc == effectiveDirective)
+ prefix = "Refused to create a child context containing '";
+ else if (ContentSecurityPolicy::ConnectSrc == effectiveDirective)
+ prefix = "Refused to connect to '";
+ else if (ContentSecurityPolicy::FontSrc == effectiveDirective)
+ prefix = "Refused to load the font '";
+ else if (ContentSecurityPolicy::FormAction == effectiveDirective)
+ prefix = "Refused to send form data to '";
+ else if (ContentSecurityPolicy::FrameSrc == effectiveDirective)
+ prefix = "Refused to frame '";
+ else if (ContentSecurityPolicy::ImgSrc == effectiveDirective)
+ prefix = "Refused to load the image '";
+ else if (ContentSecurityPolicy::MediaSrc == effectiveDirective)
+ prefix = "Refused to load media from '";
+ else if (ContentSecurityPolicy::ObjectSrc == effectiveDirective)
+ prefix = "Refused to load plugin data from '";
+ else if (ContentSecurityPolicy::ScriptSrc == effectiveDirective)
+ prefix = "Refused to load the script '";
+ else if (ContentSecurityPolicy::StyleSrc == effectiveDirective)
+ prefix = "Refused to load the stylesheet '";
+
+ String suffix = String();
+ if (directive == m_defaultSrc)
+ suffix = " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback.";
+
+ reportViolation(directive->text(), effectiveDirective, prefix + url.elidedString() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url);
+ return denyIfEnforcingPolicy();
+}
+
+bool CSPDirectiveList::checkAncestorsAndReportViolation(SourceListDirective* directive, LocalFrame* frame) const
+{
+ if (checkAncestors(directive, frame))
+ return true;
+
+ reportViolation(directive->text(), "frame-ancestors", "Refused to display '" + frame->document()->url().elidedString() + " in a frame because an ancestor violates the following Content Security Policy directive: \"" + directive->text() + "\".", frame->document()->url());
+ return denyIfEnforcingPolicy();
+}
+
+bool CSPDirectiveList::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "));
+ if (reportingStatus == ContentSecurityPolicy::SendReport)
+ return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
+
+ return checkInline(operativeDirective(m_scriptSrc.get()));
+}
+
+bool CSPDirectiveList::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline event handler because it violates the following Content Security Policy directive: "));
+ if (reportingStatus == ContentSecurityPolicy::SendReport)
+ return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
+ return checkInline(operativeDirective(m_scriptSrc.get()));
+}
+
+bool CSPDirectiveList::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline script because it violates the following Content Security Policy directive: "));
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true) :
+ checkInline(operativeDirective(m_scriptSrc.get()));
+}
+
+bool CSPDirectiveList::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to apply inline style because it violates the following Content Security Policy directive: "));
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkInlineAndReportViolation(operativeDirective(m_styleSrc.get()), consoleMessage, contextURL, contextLine, false) :
+ checkInline(operativeDirective(m_styleSrc.get()));
+}
+
+bool CSPDirectiveList::allowEval(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "));
+
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, scriptState) :
+ checkEval(operativeDirective(m_scriptSrc.get()));
+}
+
+bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.elidedString() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") :
+ checkMediaType(m_pluginTypes.get(), type, typeAttribute);
+}
+
+bool CSPDirectiveList::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, ContentSecurityPolicy::ScriptSrc) :
+ checkSource(operativeDirective(m_scriptSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (url.protocolIsAbout())
+ return true;
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, ContentSecurityPolicy::ObjectSrc) :
+ checkSource(operativeDirective(m_objectSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (url.protocolIsAbout())
+ return true;
+
+ // 'frame-src' is the only directive which overrides something other than the default sources.
+ // It overrides 'child-src', which overrides the default sources. So, we do this nested set
+ // of calls to 'operativeDirective()' to grab 'frame-src' if it exists, 'child-src' if it
+ // doesn't, and 'defaut-src' if neither are available.
+ //
+ // All of this only applies, of course, if we're in CSP 1.1. In CSP 1.0, 'frame-src'
+ // overrides 'default-src' directly.
+ SourceListDirective* whichDirective = m_policy->experimentalFeaturesEnabled() ?
+ operativeDirective(m_frameSrc.get(), operativeDirective(m_childSrc.get())) :
+ operativeDirective(m_frameSrc.get());
+
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(whichDirective, url, ContentSecurityPolicy::FrameSrc) :
+ checkSource(whichDirective, url);
+}
+
+bool CSPDirectiveList::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, ContentSecurityPolicy::ImgSrc) :
+ checkSource(operativeDirective(m_imgSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, ContentSecurityPolicy::StyleSrc) :
+ checkSource(operativeDirective(m_styleSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, ContentSecurityPolicy::FontSrc) :
+ checkSource(operativeDirective(m_fontSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, ContentSecurityPolicy::MediaSrc) :
+ checkSource(operativeDirective(m_mediaSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, ContentSecurityPolicy::ConnectSrc) :
+ checkSource(operativeDirective(m_connectSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(m_formAction.get(), url, ContentSecurityPolicy::FormAction) :
+ checkSource(m_formAction.get(), url);
+}
+
+bool CSPDirectiveList::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(m_baseURI.get(), url, ContentSecurityPolicy::BaseURI) :
+ checkSource(m_baseURI.get(), url);
+}
+
+bool CSPDirectiveList::allowAncestors(LocalFrame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkAncestorsAndReportViolation(m_frameAncestors.get(), frame) :
+ checkAncestors(m_frameAncestors.get(), frame);
+}
+
+bool CSPDirectiveList::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return reportingStatus == ContentSecurityPolicy::SendReport ?
+ checkSourceAndReportViolation(operativeDirective(m_childSrc.get()), url, ContentSecurityPolicy::ChildSrc) :
+ checkSource(operativeDirective(m_childSrc.get()), url);
+}
+
+bool CSPDirectiveList::allowScriptNonce(const String& nonce) const
+{
+ return checkNonce(operativeDirective(m_scriptSrc.get()), nonce);
+}
+
+bool CSPDirectiveList::allowStyleNonce(const String& nonce) const
+{
+ return checkNonce(operativeDirective(m_styleSrc.get()), nonce);
+}
+
+bool CSPDirectiveList::allowScriptHash(const CSPHashValue& hashValue) const
+{
+ return checkHash(operativeDirective(m_scriptSrc.get()), hashValue);
+}
+
+bool CSPDirectiveList::allowStyleHash(const CSPHashValue& hashValue) const
+{
+ return checkHash(operativeDirective(m_styleSrc.get()), hashValue);
+}
+
+// policy = directive-list
+// directive-list = [ directive *( ";" [ directive ] ) ]
+//
+void CSPDirectiveList::parse(const UChar* begin, const UChar* end)
+{
+ m_header = String(begin, end - begin);
+
+ if (begin == end)
+ return;
+
+ const UChar* position = begin;
+ while (position < end) {
+ const UChar* directiveBegin = position;
+ skipUntil<UChar>(position, end, ';');
+
+ String name, value;
+ if (parseDirective(directiveBegin, position, name, value)) {
+ ASSERT(!name.isEmpty());
+ addDirective(name, value);
+ }
+
+ ASSERT(position == end || *position == ';');
+ skipExactly<UChar>(position, end, ';');
+ }
+}
+
+// directive = *WSP [ directive-name [ WSP directive-value ] ]
+// directive-name = 1*( ALPHA / DIGIT / "-" )
+// directive-value = *( WSP / <VCHAR except ";"> )
+//
+bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, String& name, String& value)
+{
+ ASSERT(name.isEmpty());
+ ASSERT(value.isEmpty());
+
+ const UChar* position = begin;
+ skipWhile<UChar, isASCIISpace>(position, end);
+
+ // Empty directive (e.g. ";;;"). Exit early.
+ if (position == end)
+ return false;
+
+ const UChar* nameBegin = position;
+ skipWhile<UChar, isCSPDirectiveNameCharacter>(position, end);
+
+ // The directive-name must be non-empty.
+ if (nameBegin == position) {
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+ m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
+ return false;
+ }
+
+ name = String(nameBegin, position - nameBegin);
+
+ if (position == end)
+ return true;
+
+ if (!skipExactly<UChar, isASCIISpace>(position, end)) {
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+ m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
+ return false;
+ }
+
+ skipWhile<UChar, isASCIISpace>(position, end);
+
+ const UChar* valueBegin = position;
+ skipWhile<UChar, isCSPDirectiveValueCharacter>(position, end);
+
+ if (position != end) {
+ m_policy->reportInvalidDirectiveValueCharacter(name, String(valueBegin, end - valueBegin));
+ return false;
+ }
+
+ // The directive-value may be empty.
+ if (valueBegin == position)
+ return true;
+
+ value = String(valueBegin, position - valueBegin);
+ return true;
+}
+
+void CSPDirectiveList::parseReportURI(const String& name, const String& value)
+{
+ if (!m_reportURIs.isEmpty()) {
+ m_policy->reportDuplicateDirective(name);
+ return;
+ }
+
+ Vector<UChar> characters;
+ value.appendTo(characters);
+
+ const UChar* position = characters.data();
+ const UChar* end = position + characters.size();
+
+ while (position < end) {
+ skipWhile<UChar, isASCIISpace>(position, end);
+
+ const UChar* urlBegin = position;
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+
+ if (urlBegin < position) {
+ String url = String(urlBegin, position - urlBegin);
+ m_reportURIs.append(m_policy->completeURL(url));
+ }
+ }
+}
+
+
+template<class CSPDirectiveType>
+void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>& directive)
+{
+ if (directive) {
+ m_policy->reportDuplicateDirective(name);
+ return;
+ }
+ directive = adoptPtr(new CSPDirectiveType(name, value, m_policy));
+}
+
+void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sandboxPolicy)
+{
+ if (m_reportOnly) {
+ m_policy->reportInvalidInReportOnly(name);
+ return;
+ }
+ if (m_haveSandboxPolicy) {
+ m_policy->reportDuplicateDirective(name);
+ return;
+ }
+ m_haveSandboxPolicy = true;
+ String invalidTokens;
+ m_policy->enforceSandboxFlags(parseSandboxPolicy(sandboxPolicy, invalidTokens));
+ if (!invalidTokens.isNull())
+ m_policy->reportInvalidSandboxFlags(invalidTokens);
+}
+
+void CSPDirectiveList::parseReflectedXSS(const String& name, const String& value)
+{
+ if (m_reflectedXSSDisposition != ReflectedXSSUnset) {
+ m_policy->reportDuplicateDirective(name);
+ m_reflectedXSSDisposition = ReflectedXSSInvalid;
+ return;
+ }
+
+ if (value.isEmpty()) {
+ m_reflectedXSSDisposition = ReflectedXSSInvalid;
+ m_policy->reportInvalidReflectedXSS(value);
+ return;
+ }
+
+ Vector<UChar> characters;
+ value.appendTo(characters);
+
+ const UChar* position = characters.data();
+ const UChar* end = position + characters.size();
+
+ skipWhile<UChar, isASCIISpace>(position, end);
+ const UChar* begin = position;
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+
+ // value1
+ // ^
+ if (equalIgnoringCase("allow", begin, position - begin)) {
+ m_reflectedXSSDisposition = AllowReflectedXSS;
+ } else if (equalIgnoringCase("filter", begin, position - begin)) {
+ m_reflectedXSSDisposition = FilterReflectedXSS;
+ } else if (equalIgnoringCase("block", begin, position - begin)) {
+ m_reflectedXSSDisposition = BlockReflectedXSS;
+ } else {
+ m_reflectedXSSDisposition = ReflectedXSSInvalid;
+ m_policy->reportInvalidReflectedXSS(value);
+ return;
+ }
+
+ skipWhile<UChar, isASCIISpace>(position, end);
+ if (position == end && m_reflectedXSSDisposition != ReflectedXSSUnset)
+ return;
+
+ // value1 value2
+ // ^
+ m_reflectedXSSDisposition = ReflectedXSSInvalid;
+ m_policy->reportInvalidReflectedXSS(value);
+}
+
+void CSPDirectiveList::parseReferrer(const String& name, const String& value)
+{
+ if (m_didSetReferrerPolicy) {
+ m_policy->reportDuplicateDirective(name);
+ m_referrerPolicy = ReferrerPolicyNever;
+ return;
+ }
+
+ m_didSetReferrerPolicy = true;
+
+ if (value.isEmpty()) {
+ m_policy->reportInvalidReferrer(value);
+ m_referrerPolicy = ReferrerPolicyNever;
+ return;
+ }
+
+ Vector<UChar> characters;
+ value.appendTo(characters);
+
+ const UChar* position = characters.data();
+ const UChar* end = position + characters.size();
+
+ skipWhile<UChar, isASCIISpace>(position, end);
+ const UChar* begin = position;
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+
+ // value1
+ // ^
+ if (equalIgnoringCase("always", begin, position - begin)) {
+ m_referrerPolicy = ReferrerPolicyAlways;
+ } else if (equalIgnoringCase("default", begin, position - begin)) {
+ m_referrerPolicy = ReferrerPolicyDefault;
+ } else if (equalIgnoringCase("never", begin, position - begin)) {
+ m_referrerPolicy = ReferrerPolicyNever;
+ } else if (equalIgnoringCase("origin", begin, position - begin)) {
+ m_referrerPolicy = ReferrerPolicyOrigin;
+ } else {
+ m_referrerPolicy = ReferrerPolicyNever;
+ m_policy->reportInvalidReferrer(value);
+ return;
+ }
+
+ skipWhile<UChar, isASCIISpace>(position, end);
+ if (position == end)
+ return;
+
+ // value1 value2
+ // ^
+ m_referrerPolicy = ReferrerPolicyNever;
+ m_policy->reportInvalidReferrer(value);
+
+}
+
+void CSPDirectiveList::addDirective(const String& name, const String& value)
+{
+ ASSERT(!name.isEmpty());
+
+ if (equalIgnoringCase(name, ContentSecurityPolicy::DefaultSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_defaultSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::ScriptSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_scriptSrc);
+ m_policy->usesScriptHashAlgorithms(m_scriptSrc->hashAlgorithmsUsed());
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::ObjectSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_objectSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::FrameAncestors)) {
+ setCSPDirective<SourceListDirective>(name, value, m_frameAncestors);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::FrameSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_frameSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::ImgSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_imgSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::StyleSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_styleSrc);
+ m_policy->usesStyleHashAlgorithms(m_styleSrc->hashAlgorithmsUsed());
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::FontSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_fontSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::MediaSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_mediaSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::ConnectSrc)) {
+ setCSPDirective<SourceListDirective>(name, value, m_connectSrc);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::Sandbox)) {
+ applySandboxPolicy(name, value);
+ } else if (equalIgnoringCase(name, ContentSecurityPolicy::ReportURI)) {
+ parseReportURI(name, value);
+ } else if (m_policy->experimentalFeaturesEnabled()) {
+ if (equalIgnoringCase(name, ContentSecurityPolicy::BaseURI))
+ setCSPDirective<SourceListDirective>(name, value, m_baseURI);
+ else if (equalIgnoringCase(name, ContentSecurityPolicy::ChildSrc))
+ setCSPDirective<SourceListDirective>(name, value, m_childSrc);
+ else if (equalIgnoringCase(name, ContentSecurityPolicy::FormAction))
+ setCSPDirective<SourceListDirective>(name, value, m_formAction);
+ else if (equalIgnoringCase(name, ContentSecurityPolicy::PluginTypes))
+ setCSPDirective<MediaListDirective>(name, value, m_pluginTypes);
+ else if (equalIgnoringCase(name, ContentSecurityPolicy::ReflectedXSS))
+ parseReflectedXSS(name, value);
+ else if (equalIgnoringCase(name, ContentSecurityPolicy::Referrer))
+ parseReferrer(name, value);
+ else
+ m_policy->reportUnsupportedDirective(name);
+ } else {
+ m_policy->reportUnsupportedDirective(name);
+ }
+}
+
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h b/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
new file mode 100644
index 00000000000..b33b18693ad
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
@@ -0,0 +1,141 @@
+// Copyright 2014 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.
+
+#ifndef CSPDirectiveList_h
+#define CSPDirectiveList_h
+
+#include "core/frame/csp/ContentSecurityPolicy.h"
+#include "core/frame/csp/MediaListDirective.h"
+#include "core/frame/csp/SourceListDirective.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "platform/network/HTTPParsers.h"
+#include "platform/weborigin/KURL.h"
+#include "platform/weborigin/ReferrerPolicy.h"
+#include "wtf/OwnPtr.h"
+#include "wtf/Vector.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ContentSecurityPolicy;
+
+class CSPDirectiveList {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(CSPDirectiveList);
+public:
+ static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
+
+ void parse(const UChar* begin, const UChar* end);
+
+ const String& header() const { return m_header; }
+ ContentSecurityPolicyHeaderType headerType() const { return m_headerType; }
+ ContentSecurityPolicyHeaderSource headerSource() const { return m_headerSource; }
+
+ bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowEval(ScriptState*, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+
+ bool allowScriptFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowObjectFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowAncestors(LocalFrame*, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowChildContextFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
+ bool allowScriptNonce(const String&) const;
+ bool allowStyleNonce(const String&) const;
+ bool allowScriptHash(const CSPHashValue&) const;
+ bool allowStyleHash(const CSPHashValue&) const;
+
+ const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; }
+ ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflectedXSSDisposition; }
+ ReferrerPolicy referrerPolicy() const { return m_referrerPolicy; }
+ bool didSetReferrerPolicy() const { return m_didSetReferrerPolicy; }
+ bool isReportOnly() const { return m_reportOnly; }
+ const Vector<KURL>& reportURIs() const { return m_reportURIs; }
+
+private:
+ CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
+
+ bool parseDirective(const UChar* begin, const UChar* end, String& name, String& value);
+ void parseReportURI(const String& name, const String& value);
+ void parsePluginTypes(const String& name, const String& value);
+ void parseReflectedXSS(const String& name, const String& value);
+ void parseReferrer(const String& name, const String& value);
+ void addDirective(const String& name, const String& value);
+ void applySandboxPolicy(const String& name, const String& sandboxPolicy);
+
+ template <class CSPDirectiveType>
+ void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>&);
+
+ SourceListDirective* operativeDirective(SourceListDirective*) const;
+ SourceListDirective* operativeDirective(SourceListDirective*, SourceListDirective* override) const;
+ void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const;
+ void reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
+ void reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptState*) const;
+
+ bool checkEval(SourceListDirective*) const;
+ bool checkInline(SourceListDirective*) const;
+ bool checkNonce(SourceListDirective*, const String&) const;
+ bool checkHash(SourceListDirective*, const CSPHashValue&) const;
+ bool checkSource(SourceListDirective*, const KURL&) const;
+ bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
+ bool checkAncestors(SourceListDirective*, LocalFrame*) const;
+
+ void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisabledErrorMessage = errorMessage; }
+
+ bool checkEvalAndReportViolation(SourceListDirective*, const String& consoleMessage, ScriptState*) const;
+ bool checkInlineAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const;
+
+ bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective) const;
+ bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& type, const String& typeAttribute, const String& consoleMessage) const;
+ bool checkAncestorsAndReportViolation(SourceListDirective*, LocalFrame*) const;
+
+ bool denyIfEnforcingPolicy() const { return m_reportOnly; }
+
+ ContentSecurityPolicy* m_policy;
+
+ String m_header;
+ ContentSecurityPolicyHeaderType m_headerType;
+ ContentSecurityPolicyHeaderSource m_headerSource;
+
+ bool m_reportOnly;
+ bool m_haveSandboxPolicy;
+ ReflectedXSSDisposition m_reflectedXSSDisposition;
+
+ bool m_didSetReferrerPolicy;
+ ReferrerPolicy m_referrerPolicy;
+
+ OwnPtr<MediaListDirective> m_pluginTypes;
+ OwnPtr<SourceListDirective> m_baseURI;
+ OwnPtr<SourceListDirective> m_childSrc;
+ OwnPtr<SourceListDirective> m_connectSrc;
+ OwnPtr<SourceListDirective> m_defaultSrc;
+ OwnPtr<SourceListDirective> m_fontSrc;
+ OwnPtr<SourceListDirective> m_formAction;
+ OwnPtr<SourceListDirective> m_frameAncestors;
+ OwnPtr<SourceListDirective> m_frameSrc;
+ OwnPtr<SourceListDirective> m_imgSrc;
+ OwnPtr<SourceListDirective> m_mediaSrc;
+ OwnPtr<SourceListDirective> m_objectSrc;
+ OwnPtr<SourceListDirective> m_scriptSrc;
+ OwnPtr<SourceListDirective> m_styleSrc;
+
+ Vector<KURL> m_reportURIs;
+
+ String m_evalDisabledErrorMessage;
+};
+
+
+} // namespace
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp
new file mode 100644
index 00000000000..863addc09ce
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp
@@ -0,0 +1,93 @@
+// Copyright 2014 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 "config.h"
+#include "core/frame/csp/CSPSource.h"
+
+#include "core/frame/csp/ContentSecurityPolicy.h"
+#include "platform/weborigin/KURL.h"
+#include "platform/weborigin/KnownPorts.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+CSPSource::CSPSource(ContentSecurityPolicy* policy, const String& scheme, const String& host, int port, const String& path, bool hostHasWildcard, bool portHasWildcard)
+ : m_policy(policy)
+ , m_scheme(scheme)
+ , m_host(host)
+ , m_port(port)
+ , m_path(path)
+ , m_hostHasWildcard(hostHasWildcard)
+ , m_portHasWildcard(portHasWildcard)
+{
+}
+
+bool CSPSource::matches(const KURL& url) const
+{
+ if (!schemeMatches(url))
+ return false;
+ if (isSchemeOnly())
+ return true;
+ return hostMatches(url) && portMatches(url) && pathMatches(url);
+}
+
+bool CSPSource::schemeMatches(const KURL& url) const
+{
+ if (m_scheme.isEmpty()) {
+ String protectedResourceScheme(m_policy->securityOrigin()->protocol());
+ if (equalIgnoringCase("http", protectedResourceScheme))
+ return url.protocolIs("http") || url.protocolIs("https");
+ return equalIgnoringCase(url.protocol(), protectedResourceScheme);
+ }
+ return equalIgnoringCase(url.protocol(), m_scheme);
+}
+
+bool CSPSource::hostMatches(const KURL& url) const
+{
+ const String& host = url.host();
+ if (equalIgnoringCase(host, m_host))
+ return true;
+ return m_hostHasWildcard && host.endsWith("." + m_host, false);
+
+}
+
+bool CSPSource::pathMatches(const KURL& url) const
+{
+ if (m_path.isEmpty())
+ return true;
+
+ String path = decodeURLEscapeSequences(url.path());
+
+ if (m_path.endsWith("/"))
+ return path.startsWith(m_path, false);
+
+ return path == m_path;
+}
+
+bool CSPSource::portMatches(const KURL& url) const
+{
+ if (m_portHasWildcard)
+ return true;
+
+ int port = url.port();
+
+ if (port == m_port)
+ return true;
+
+ if (!port)
+ return isDefaultPortForProtocol(m_port, url.protocol());
+
+ if (!m_port)
+ return isDefaultPortForProtocol(port, url.protocol());
+
+ return false;
+}
+
+bool CSPSource::isSchemeOnly() const
+{
+ return m_host.isEmpty();
+}
+
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.h b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.h
new file mode 100644
index 00000000000..9088b196b3f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSource.h
@@ -0,0 +1,39 @@
+// Copyright 2014 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.
+
+#ifndef CSPSource_h
+#define CSPSource_h
+
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ContentSecurityPolicy;
+class KURL;
+
+class CSPSource {
+public:
+ CSPSource(ContentSecurityPolicy*, const String& scheme, const String& host, int port, const String& path, bool hostHasWildcard, bool portHasWildcard);
+ bool matches(const KURL&) const;
+
+private:
+ bool schemeMatches(const KURL&) const;
+ bool hostMatches(const KURL&) const;
+ bool pathMatches(const KURL&) const;
+ bool portMatches(const KURL&) const;
+ bool isSchemeOnly() const;
+
+ ContentSecurityPolicy* m_policy;
+ String m_scheme;
+ String m_host;
+ int m_port;
+ String m_path;
+
+ bool m_hostHasWildcard;
+ bool m_portHasWildcard;
+};
+
+} // namespace
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
new file mode 100644
index 00000000000..bff7146dab0
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
@@ -0,0 +1,485 @@
+// Copyright 2014 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 "config.h"
+#include "core/frame/csp/CSPSourceList.h"
+
+#include "core/frame/csp/CSPSource.h"
+#include "core/frame/csp/ContentSecurityPolicy.h"
+#include "platform/ParsingUtilities.h"
+#include "platform/weborigin/KURL.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "wtf/HashSet.h"
+#include "wtf/text/Base64.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+static bool isSourceListNone(const UChar* begin, const UChar* end)
+{
+ skipWhile<UChar, isASCIISpace>(begin, end);
+
+ const UChar* position = begin;
+ skipWhile<UChar, isSourceCharacter>(position, end);
+ if (!equalIgnoringCase("'none'", begin, position - begin))
+ return false;
+
+ skipWhile<UChar, isASCIISpace>(position, end);
+ if (position != end)
+ return false;
+
+ return true;
+}
+
+CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& directiveName)
+ : m_policy(policy)
+ , m_directiveName(directiveName)
+ , m_allowStar(false)
+ , m_allowInline(false)
+ , m_allowEval(false)
+ , m_hashAlgorithmsUsed(0)
+{
+}
+
+bool CSPSourceList::matches(const KURL& url) const
+{
+ if (m_allowStar)
+ return true;
+
+ KURL effectiveURL = SecurityOrigin::shouldUseInnerURL(url) ? SecurityOrigin::extractInnerURL(url) : url;
+
+ for (size_t i = 0; i < m_list.size(); ++i) {
+ if (m_list[i].matches(effectiveURL))
+ return true;
+ }
+
+ return false;
+}
+
+bool CSPSourceList::allowInline() const
+{
+ return m_allowInline;
+}
+
+bool CSPSourceList::allowEval() const
+{
+ return m_allowEval;
+}
+
+bool CSPSourceList::allowNonce(const String& nonce) const
+{
+ return !nonce.isNull() && m_nonces.contains(nonce);
+}
+
+bool CSPSourceList::allowHash(const CSPHashValue& hashValue) const
+{
+ return m_hashes.contains(hashValue);
+}
+
+uint8_t CSPSourceList::hashAlgorithmsUsed() const
+{
+ return m_hashAlgorithmsUsed;
+}
+
+bool CSPSourceList::isHashOrNoncePresent() const
+{
+ return !m_nonces.isEmpty() || m_hashAlgorithmsUsed != ContentSecurityPolicyHashAlgorithmNone;
+}
+
+// source-list = *WSP [ source *( 1*WSP source ) *WSP ]
+// / *WSP "'none'" *WSP
+//
+void CSPSourceList::parse(const UChar* begin, const UChar* end)
+{
+ // We represent 'none' as an empty m_list.
+ if (isSourceListNone(begin, end))
+ return;
+
+ const UChar* position = begin;
+ while (position < end) {
+ skipWhile<UChar, isASCIISpace>(position, end);
+ if (position == end)
+ return;
+
+ const UChar* beginSource = position;
+ skipWhile<UChar, isSourceCharacter>(position, end);
+
+ String scheme, host, path;
+ int port = 0;
+ bool hostHasWildcard = false;
+ bool portHasWildcard = false;
+
+ if (parseSource(beginSource, position, scheme, host, port, path, hostHasWildcard, portHasWildcard)) {
+ // Wildcard hosts and keyword sources ('self', 'unsafe-inline',
+ // etc.) aren't stored in m_list, but as attributes on the source
+ // list itself.
+ if (scheme.isEmpty() && host.isEmpty())
+ continue;
+ if (m_policy->isDirectiveName(host))
+ m_policy->reportDirectiveAsSourceExpression(m_directiveName, host);
+ m_list.append(CSPSource(m_policy, scheme, host, port, path, hostHasWildcard, portHasWildcard));
+ } else {
+ m_policy->reportInvalidSourceExpression(m_directiveName, String(beginSource, position - beginSource));
+ }
+
+ ASSERT(position == end || isASCIISpace(*position));
+ }
+}
+
+// source = scheme ":"
+// / ( [ scheme "://" ] host [ port ] [ path ] )
+// / "'self'"
+bool CSPSourceList::parseSource(const UChar* begin, const UChar* end, String& scheme, String& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard)
+{
+ if (begin == end)
+ return false;
+
+ if (equalIgnoringCase("'none'", begin, end - begin))
+ return false;
+
+ if (end - begin == 1 && *begin == '*') {
+ addSourceStar();
+ return true;
+ }
+
+ if (equalIgnoringCase("'self'", begin, end - begin)) {
+ addSourceSelf();
+ return true;
+ }
+
+ if (equalIgnoringCase("'unsafe-inline'", begin, end - begin)) {
+ addSourceUnsafeInline();
+ return true;
+ }
+
+ if (equalIgnoringCase("'unsafe-eval'", begin, end - begin)) {
+ addSourceUnsafeEval();
+ return true;
+ }
+
+ String nonce;
+ if (!parseNonce(begin, end, nonce))
+ return false;
+
+ if (!nonce.isNull()) {
+ addSourceNonce(nonce);
+ return true;
+ }
+
+ DigestValue hash;
+ ContentSecurityPolicyHashAlgorithm algorithm = ContentSecurityPolicyHashAlgorithmNone;
+ if (!parseHash(begin, end, hash, algorithm))
+ return false;
+
+ if (hash.size() > 0) {
+ addSourceHash(algorithm, hash);
+ return true;
+ }
+
+ const UChar* position = begin;
+ const UChar* beginHost = begin;
+ const UChar* beginPath = end;
+ const UChar* beginPort = 0;
+
+ skipWhile<UChar, isNotColonOrSlash>(position, end);
+
+ if (position == end) {
+ // host
+ // ^
+ return parseHost(beginHost, position, host, hostHasWildcard);
+ }
+
+ if (position < end && *position == '/') {
+ // host/path || host/ || /
+ // ^ ^ ^
+ return parseHost(beginHost, position, host, hostHasWildcard) && parsePath(position, end, path);
+ }
+
+ if (position < end && *position == ':') {
+ if (end - position == 1) {
+ // scheme:
+ // ^
+ return parseScheme(begin, position, scheme);
+ }
+
+ if (position[1] == '/') {
+ // scheme://host || scheme://
+ // ^ ^
+ if (!parseScheme(begin, position, scheme)
+ || !skipExactly<UChar>(position, end, ':')
+ || !skipExactly<UChar>(position, end, '/')
+ || !skipExactly<UChar>(position, end, '/'))
+ return false;
+ if (position == end)
+ return true;
+ beginHost = position;
+ skipWhile<UChar, isNotColonOrSlash>(position, end);
+ }
+
+ if (position < end && *position == ':') {
+ // host:port || scheme://host:port
+ // ^ ^
+ beginPort = position;
+ skipUntil<UChar>(position, end, '/');
+ }
+ }
+
+ if (position < end && *position == '/') {
+ // scheme://host/path || scheme://host:port/path
+ // ^ ^
+ if (position == beginHost)
+ return false;
+ beginPath = position;
+ }
+
+ if (!parseHost(beginHost, beginPort ? beginPort : beginPath, host, hostHasWildcard))
+ return false;
+
+ if (beginPort) {
+ if (!parsePort(beginPort, beginPath, port, portHasWildcard))
+ return false;
+ } else {
+ port = 0;
+ }
+
+ if (beginPath != end) {
+ if (!parsePath(beginPath, end, path))
+ return false;
+ }
+
+ return true;
+}
+
+// nonce-source = "'nonce-" nonce-value "'"
+// nonce-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
+//
+bool CSPSourceList::parseNonce(const UChar* begin, const UChar* end, String& nonce)
+{
+ DEFINE_STATIC_LOCAL(const String, noncePrefix, ("'nonce-"));
+
+ if (!equalIgnoringCase(noncePrefix.characters8(), begin, noncePrefix.length()))
+ return true;
+
+ const UChar* position = begin + noncePrefix.length();
+ const UChar* nonceBegin = position;
+
+ skipWhile<UChar, isNonceCharacter>(position, end);
+ ASSERT(nonceBegin <= position);
+
+ if ((position + 1) != end || *position != '\'' || !(position - nonceBegin))
+ return false;
+
+ nonce = String(nonceBegin, position - nonceBegin);
+ return true;
+}
+
+// hash-source = "'" hash-algorithm "-" hash-value "'"
+// hash-algorithm = "sha1" / "sha256" / "sha384" / "sha512"
+// hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
+//
+bool CSPSourceList::parseHash(const UChar* begin, const UChar* end, DigestValue& hash, ContentSecurityPolicyHashAlgorithm& hashAlgorithm)
+{
+ // Any additions or subtractions from this struct should also modify the
+ // respective entries in the kAlgorithmMap array in checkDigest().
+ static const struct {
+ const char* prefix;
+ ContentSecurityPolicyHashAlgorithm algorithm;
+ } kSupportedPrefixes[] = {
+ { "'sha1-", ContentSecurityPolicyHashAlgorithmSha1 },
+ { "'sha256-", ContentSecurityPolicyHashAlgorithmSha256 },
+ { "'sha384-", ContentSecurityPolicyHashAlgorithmSha384 },
+ { "'sha512-", ContentSecurityPolicyHashAlgorithmSha512 }
+ };
+
+ String prefix;
+ hashAlgorithm = ContentSecurityPolicyHashAlgorithmNone;
+
+ // Instead of this sizeof() calculation to get the length of this array,
+ // it would be preferable to use WTF_ARRAY_LENGTH for simplicity and to
+ // guarantee a compile time calculation. Unfortunately, on some
+ // compliers, the call to WTF_ARRAY_LENGTH fails on arrays of anonymous
+ // stucts, so, for now, it is necessary to resort to this sizeof
+ // calculation.
+ for (size_t i = 0; i < (sizeof(kSupportedPrefixes) / sizeof(kSupportedPrefixes[0])); i++) {
+ if (equalIgnoringCase(kSupportedPrefixes[i].prefix, begin, strlen(kSupportedPrefixes[i].prefix))) {
+ prefix = kSupportedPrefixes[i].prefix;
+ hashAlgorithm = kSupportedPrefixes[i].algorithm;
+ break;
+ }
+ }
+
+ if (hashAlgorithm == ContentSecurityPolicyHashAlgorithmNone)
+ return true;
+
+ const UChar* position = begin + prefix.length();
+ const UChar* hashBegin = position;
+
+ skipWhile<UChar, isBase64EncodedCharacter>(position, end);
+ ASSERT(hashBegin <= position);
+
+ // Base64 encodings may end with exactly one or two '=' characters
+ skipExactly<UChar>(position, position + 1, '=');
+ skipExactly<UChar>(position, position + 1, '=');
+
+ if ((position + 1) != end || *position != '\'' || !(position - hashBegin))
+ return false;
+
+ Vector<char> hashVector;
+ base64Decode(hashBegin, position - hashBegin, hashVector);
+ if (hashVector.size() > kMaxDigestSize)
+ return false;
+ hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size());
+ return true;
+}
+
+// ; <scheme> production from RFC 3986
+// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+//
+bool CSPSourceList::parseScheme(const UChar* begin, const UChar* end, String& scheme)
+{
+ ASSERT(begin <= end);
+ ASSERT(scheme.isEmpty());
+
+ if (begin == end)
+ return false;
+
+ const UChar* position = begin;
+
+ if (!skipExactly<UChar, isASCIIAlpha>(position, end))
+ return false;
+
+ skipWhile<UChar, isSchemeContinuationCharacter>(position, end);
+
+ if (position != end)
+ return false;
+
+ scheme = String(begin, end - begin);
+ return true;
+}
+
+// host = [ "*." ] 1*host-char *( "." 1*host-char )
+// / "*"
+// host-char = ALPHA / DIGIT / "-"
+//
+bool CSPSourceList::parseHost(const UChar* begin, const UChar* end, String& host, bool& hostHasWildcard)
+{
+ ASSERT(begin <= end);
+ ASSERT(host.isEmpty());
+ ASSERT(!hostHasWildcard);
+
+ if (begin == end)
+ return false;
+
+ const UChar* position = begin;
+
+ if (skipExactly<UChar>(position, end, '*')) {
+ hostHasWildcard = true;
+
+ if (position == end)
+ return true;
+
+ if (!skipExactly<UChar>(position, end, '.'))
+ return false;
+ }
+
+ const UChar* hostBegin = position;
+
+ while (position < end) {
+ if (!skipExactly<UChar, isHostCharacter>(position, end))
+ return false;
+
+ skipWhile<UChar, isHostCharacter>(position, end);
+
+ if (position < end && !skipExactly<UChar>(position, end, '.'))
+ return false;
+ }
+
+ ASSERT(position == end);
+ host = String(hostBegin, end - hostBegin);
+ return true;
+}
+
+bool CSPSourceList::parsePath(const UChar* begin, const UChar* end, String& path)
+{
+ ASSERT(begin <= end);
+ ASSERT(path.isEmpty());
+
+ const UChar* position = begin;
+ skipWhile<UChar, isPathComponentCharacter>(position, end);
+ // path/to/file.js?query=string || path/to/file.js#anchor
+ // ^ ^
+ if (position < end)
+ m_policy->reportInvalidPathCharacter(m_directiveName, String(begin, end - begin), *position);
+
+ path = decodeURLEscapeSequences(String(begin, position - begin));
+
+ ASSERT(position <= end);
+ ASSERT(position == end || (*position == '#' || *position == '?'));
+ return true;
+}
+
+// port = ":" ( 1*DIGIT / "*" )
+//
+bool CSPSourceList::parsePort(const UChar* begin, const UChar* end, int& port, bool& portHasWildcard)
+{
+ ASSERT(begin <= end);
+ ASSERT(!port);
+ ASSERT(!portHasWildcard);
+
+ if (!skipExactly<UChar>(begin, end, ':'))
+ ASSERT_NOT_REACHED();
+
+ if (begin == end)
+ return false;
+
+ if (end - begin == 1 && *begin == '*') {
+ port = 0;
+ portHasWildcard = true;
+ return true;
+ }
+
+ const UChar* position = begin;
+ skipWhile<UChar, isASCIIDigit>(position, end);
+
+ if (position != end)
+ return false;
+
+ bool ok;
+ port = charactersToIntStrict(begin, end - begin, &ok);
+ return ok;
+}
+
+void CSPSourceList::addSourceSelf()
+{
+ m_list.append(CSPSource(m_policy, m_policy->securityOrigin()->protocol(), m_policy->securityOrigin()->host(), m_policy->securityOrigin()->port(), String(), false, false));
+}
+
+void CSPSourceList::addSourceStar()
+{
+ m_allowStar = true;
+}
+
+void CSPSourceList::addSourceUnsafeInline()
+{
+ m_allowInline = true;
+}
+
+void CSPSourceList::addSourceUnsafeEval()
+{
+ m_allowEval = true;
+}
+
+void CSPSourceList::addSourceNonce(const String& nonce)
+{
+ m_nonces.add(nonce);
+}
+
+void CSPSourceList::addSourceHash(const ContentSecurityPolicyHashAlgorithm& algorithm, const DigestValue& hash)
+{
+ m_hashes.add(CSPHashValue(algorithm, hash));
+ m_hashAlgorithmsUsed |= algorithm;
+}
+
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h
new file mode 100644
index 00000000000..c982fe68ac7
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h
@@ -0,0 +1,65 @@
+// Copyright 2014 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.
+
+#ifndef CSPSourceList_h
+#define CSPSourceList_h
+
+#include "core/frame/csp/CSPSource.h"
+#include "platform/Crypto.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "wtf/HashSet.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ContentSecurityPolicy;
+class KURL;
+
+class CSPSourceList {
+ WTF_MAKE_NONCOPYABLE(CSPSourceList);
+public:
+ CSPSourceList(ContentSecurityPolicy*, const String& directiveName);
+
+ void parse(const UChar* begin, const UChar* end);
+
+ bool matches(const KURL&) const;
+ bool allowInline() const;
+ bool allowEval() const;
+ bool allowNonce(const String&) const;
+ bool allowHash(const CSPHashValue&) const;
+ uint8_t hashAlgorithmsUsed() const;
+
+ bool isHashOrNoncePresent() const;
+
+private:
+ bool parseSource(const UChar* begin, const UChar* end, String& scheme, String& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard);
+ bool parseScheme(const UChar* begin, const UChar* end, String& scheme);
+ bool parseHost(const UChar* begin, const UChar* end, String& host, bool& hostHasWildcard);
+ bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHasWildcard);
+ bool parsePath(const UChar* begin, const UChar* end, String& path);
+ bool parseNonce(const UChar* begin, const UChar* end, String& nonce);
+ bool parseHash(const UChar* begin, const UChar* end, DigestValue& hash, ContentSecurityPolicyHashAlgorithm&);
+
+ void addSourceSelf();
+ void addSourceStar();
+ void addSourceUnsafeInline();
+ void addSourceUnsafeEval();
+ void addSourceNonce(const String& nonce);
+ void addSourceHash(const ContentSecurityPolicyHashAlgorithm&, const DigestValue& hash);
+
+ ContentSecurityPolicy* m_policy;
+ Vector<CSPSource> m_list;
+ String m_directiveName;
+ bool m_allowStar;
+ bool m_allowInline;
+ bool m_allowEval;
+ HashSet<String> m_nonces;
+ HashSet<CSPHashValue> m_hashes;
+ uint8_t m_hashAlgorithmsUsed;
+};
+
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp b/chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
new file mode 100644
index 00000000000..cdd5d063a27
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2011 Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/frame/csp/ContentSecurityPolicy.h"
+
+#include "bindings/v8/ScriptCallStackFactory.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/DOMStringList.h"
+#include "core/dom/Document.h"
+#include "core/events/SecurityPolicyViolationEvent.h"
+#include "core/frame/LocalDOMWindow.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/UseCounter.h"
+#include "core/frame/csp/CSPDirectiveList.h"
+#include "core/frame/csp/CSPSource.h"
+#include "core/frame/csp/CSPSourceList.h"
+#include "core/frame/csp/MediaListDirective.h"
+#include "core/frame/csp/SourceListDirective.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/PingLoader.h"
+#include "platform/Crypto.h"
+#include "platform/JSONValues.h"
+#include "platform/NotImplemented.h"
+#include "platform/ParsingUtilities.h"
+#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "platform/network/ContentSecurityPolicyResponseHeaders.h"
+#include "platform/network/FormData.h"
+#include "platform/network/ResourceResponse.h"
+#include "platform/weborigin/KURL.h"
+#include "platform/weborigin/KnownPorts.h"
+#include "platform/weborigin/SchemeRegistry.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebArrayBuffer.h"
+#include "public/platform/WebCrypto.h"
+#include "public/platform/WebCryptoAlgorithm.h"
+#include "wtf/StringHasher.h"
+#include "wtf/text/StringBuilder.h"
+#include "wtf/text/StringUTF8Adaptor.h"
+
+namespace WebCore {
+
+// CSP 1.0 Directives
+const char ContentSecurityPolicy::ConnectSrc[] = "connect-src";
+const char ContentSecurityPolicy::DefaultSrc[] = "default-src";
+const char ContentSecurityPolicy::FontSrc[] = "font-src";
+const char ContentSecurityPolicy::FrameSrc[] = "frame-src";
+const char ContentSecurityPolicy::ImgSrc[] = "img-src";
+const char ContentSecurityPolicy::MediaSrc[] = "media-src";
+const char ContentSecurityPolicy::ObjectSrc[] = "object-src";
+const char ContentSecurityPolicy::ReportURI[] = "report-uri";
+const char ContentSecurityPolicy::Sandbox[] = "sandbox";
+const char ContentSecurityPolicy::ScriptSrc[] = "script-src";
+const char ContentSecurityPolicy::StyleSrc[] = "style-src";
+
+// CSP 1.1 Directives
+const char ContentSecurityPolicy::BaseURI[] = "base-uri";
+const char ContentSecurityPolicy::ChildSrc[] = "child-src";
+const char ContentSecurityPolicy::FormAction[] = "form-action";
+const char ContentSecurityPolicy::FrameAncestors[] = "frame-ancestors";
+const char ContentSecurityPolicy::PluginTypes[] = "plugin-types";
+const char ContentSecurityPolicy::ReflectedXSS[] = "reflected-xss";
+const char ContentSecurityPolicy::Referrer[] = "referrer";
+
+bool ContentSecurityPolicy::isDirectiveName(const String& name)
+{
+ return (equalIgnoringCase(name, ConnectSrc)
+ || equalIgnoringCase(name, DefaultSrc)
+ || equalIgnoringCase(name, FontSrc)
+ || equalIgnoringCase(name, FrameSrc)
+ || equalIgnoringCase(name, ImgSrc)
+ || equalIgnoringCase(name, MediaSrc)
+ || equalIgnoringCase(name, ObjectSrc)
+ || equalIgnoringCase(name, ReportURI)
+ || equalIgnoringCase(name, Sandbox)
+ || equalIgnoringCase(name, ScriptSrc)
+ || equalIgnoringCase(name, StyleSrc)
+ || equalIgnoringCase(name, BaseURI)
+ || equalIgnoringCase(name, ChildSrc)
+ || equalIgnoringCase(name, FormAction)
+ || equalIgnoringCase(name, FrameAncestors)
+ || equalIgnoringCase(name, PluginTypes)
+ || equalIgnoringCase(name, ReflectedXSS)
+ || equalIgnoringCase(name, Referrer)
+ );
+}
+
+static UseCounter::Feature getUseCounterType(ContentSecurityPolicyHeaderType type)
+{
+ switch (type) {
+ case ContentSecurityPolicyHeaderTypeEnforce:
+ return UseCounter::ContentSecurityPolicy;
+ case ContentSecurityPolicyHeaderTypeReport:
+ return UseCounter::ContentSecurityPolicyReportOnly;
+ }
+ ASSERT_NOT_REACHED();
+ return UseCounter::NumberOfFeatures;
+}
+
+static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b)
+{
+ if (a != b)
+ return ReferrerPolicyNever;
+ return a;
+}
+
+ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContext* executionContext)
+ : m_executionContext(executionContext)
+ , m_overrideInlineStyleAllowed(false)
+ , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone)
+ , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone)
+{
+}
+
+ContentSecurityPolicy::~ContentSecurityPolicy()
+{
+}
+
+void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other)
+{
+ ASSERT(m_policies.isEmpty());
+ for (CSPDirectiveListVector::const_iterator iter = other->m_policies.begin(); iter != other->m_policies.end(); ++iter)
+ addPolicyFromHeaderValue((*iter)->header(), (*iter)->headerType(), (*iter)->headerSource());
+}
+
+void ContentSecurityPolicy::didReceiveHeaders(const ContentSecurityPolicyResponseHeaders& headers)
+{
+ if (!headers.contentSecurityPolicy().isEmpty())
+ didReceiveHeader(headers.contentSecurityPolicy(), ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
+ if (!headers.contentSecurityPolicyReportOnly().isEmpty())
+ didReceiveHeader(headers.contentSecurityPolicyReportOnly(), ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
+}
+
+void ContentSecurityPolicy::didReceiveHeader(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
+{
+ addPolicyFromHeaderValue(header, type, source);
+}
+
+void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
+{
+ Document* document = this->document();
+ if (document) {
+ UseCounter::count(*document, getUseCounterType(type));
+
+ // CSP 1.1 defines report-only in a <meta> element as invalid. Measure for now, disable in experimental mode.
+ if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecurityPolicyHeaderTypeReport) {
+ UseCounter::count(*document, UseCounter::ContentSecurityPolicyReportOnlyInMeta);
+ if (experimentalFeaturesEnabled()) {
+ reportReportOnlyInMeta(header);
+ return;
+ }
+ }
+ }
+
+
+ Vector<UChar> characters;
+ header.appendTo(characters);
+
+ const UChar* begin = characters.data();
+ const UChar* end = begin + characters.size();
+
+ // RFC2616, section 4.2 specifies that headers appearing multiple times can
+ // be combined with a comma. Walk the header string, and parse each comma
+ // separated chunk as a separate header.
+ const UChar* position = begin;
+ while (position < end) {
+ skipUntil<UChar>(position, end, ',');
+
+ // header1,header2 OR header1
+ // ^ ^
+ OwnPtr<CSPDirectiveList> policy = CSPDirectiveList::create(this, begin, position, type, source);
+
+ // We disable 'eval()' even in the case of report-only policies, and rely on the check in the V8Initializer::codeGenerationCheckCallbackInMainThread callback to determine whether the call should execute or not.
+ if (!policy->allowEval(0, SuppressReport))
+ m_executionContext->disableEval(policy->evalDisabledErrorMessage());
+
+ m_policies.append(policy.release());
+
+ // Skip the comma, and begin the next header from the current position.
+ ASSERT(position == end || *position == ',');
+ skipExactly<UChar>(position, end, ',');
+ begin = position;
+ }
+
+ if (document && type != ContentSecurityPolicyHeaderTypeReport && didSetReferrerPolicy())
+ document->setReferrerPolicy(referrerPolicy());
+}
+
+void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value)
+{
+ m_overrideInlineStyleAllowed = value;
+}
+
+const String& ContentSecurityPolicy::deprecatedHeader() const
+{
+ return m_policies.isEmpty() ? emptyString() : m_policies[0]->header();
+}
+
+ContentSecurityPolicyHeaderType ContentSecurityPolicy::deprecatedHeaderType() const
+{
+ return m_policies.isEmpty() ? ContentSecurityPolicyHeaderTypeEnforce : m_policies[0]->headerType();
+}
+
+template<bool (CSPDirectiveList::*allowed)(ContentSecurityPolicy::ReportingStatus) const>
+bool isAllowedByAll(const CSPDirectiveListVector& policies, ContentSecurityPolicy::ReportingStatus reportingStatus)
+{
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowed)(reportingStatus))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowed)(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus) const>
+bool isAllowedByAllWithState(const CSPDirectiveListVector& policies, ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus)
+{
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowed)(scriptState, reportingStatus))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowed)(const String&, const WTF::OrdinalNumber&, ContentSecurityPolicy::ReportingStatus) const>
+bool isAllowedByAllWithContext(const CSPDirectiveListVector& policies, const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus)
+{
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowed)(contextURL, contextLine, reportingStatus))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowed)(const String&) const>
+bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const String& nonce)
+{
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowed)(nonce))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
+bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const CSPHashValue& hashValue)
+{
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowed)(hashValue))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPolicy::ReportingStatus) const>
+bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus)
+{
+ if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
+ return true;
+
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowFromURL)(url, reportingStatus))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowed)(LocalFrame*, ContentSecurityPolicy::ReportingStatus) const>
+bool isAllowedByAllWithFrame(const CSPDirectiveListVector& policies, LocalFrame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus)
+{
+ for (size_t i = 0; i < policies.size(); ++i) {
+ if (!(policies[i].get()->*allowed)(frame, reportingStatus))
+ return false;
+ }
+ return true;
+}
+
+template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
+bool checkDigest(const String& source, uint8_t hashAlgorithmsUsed, const CSPDirectiveListVector& policies)
+{
+ // Any additions or subtractions from this struct should also modify the
+ // respective entries in the kSupportedPrefixes array in
+ // CSPSourceList::parseHash().
+ static const struct {
+ ContentSecurityPolicyHashAlgorithm cspHashAlgorithm;
+ HashAlgorithm algorithm;
+ } kAlgorithmMap[] = {
+ { ContentSecurityPolicyHashAlgorithmSha1, HashAlgorithmSha1 },
+ { ContentSecurityPolicyHashAlgorithmSha256, HashAlgorithmSha256 },
+ { ContentSecurityPolicyHashAlgorithmSha384, HashAlgorithmSha384 },
+ { ContentSecurityPolicyHashAlgorithmSha512, HashAlgorithmSha512 }
+ };
+
+ // Only bother normalizing the source/computing digests if there are any checks to be done.
+ if (hashAlgorithmsUsed == ContentSecurityPolicyHashAlgorithmNone)
+ return false;
+
+ StringUTF8Adaptor normalizedSource(source, StringUTF8Adaptor::Normalize, WTF::EntitiesForUnencodables);
+
+ // See comment in CSPSourceList::parseHash about why we are using this sizeof
+ // calculation instead of WTF_ARRAY_LENGTH.
+ for (size_t i = 0; i < (sizeof(kAlgorithmMap) / sizeof(kAlgorithmMap[0])); i++) {
+ DigestValue digest;
+ if (kAlgorithmMap[i].cspHashAlgorithm & hashAlgorithmsUsed) {
+ bool digestSuccess = computeDigest(kAlgorithmMap[i].algorithm, normalizedSource.data(), normalizedSource.length(), digest);
+ if (digestSuccess && isAllowedByAllWithHash<allowed>(policies, CSPHashValue(kAlgorithmMap[i].cspHashAlgorithm, digest)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ContentSecurityPolicy::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(m_policies, contextURL, contextLine, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineEventHandlers>(m_policies, contextURL, contextLine, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (m_overrideInlineStyleAllowed)
+ return true;
+ return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowEval(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithState<&CSPDirectiveList::allowEval>(m_policies, scriptState, reportingStatus);
+}
+
+String ContentSecurityPolicy::evalDisabledErrorMessage() const
+{
+ for (size_t i = 0; i < m_policies.size(); ++i) {
+ if (!m_policies[i]->allowEval(0, SuppressReport))
+ return m_policies[i]->evalDisabledErrorMessage();
+ }
+ return String();
+}
+
+bool ContentSecurityPolicy::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ for (size_t i = 0; i < m_policies.size(); ++i) {
+ if (!m_policies[i]->allowPluginType(type, typeAttribute, url, reportingStatus))
+ return false;
+ }
+ return true;
+}
+
+bool ContentSecurityPolicy::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowScriptNonce(const String& nonce) const
+{
+ return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_policies, nonce);
+}
+
+bool ContentSecurityPolicy::allowStyleNonce(const String& nonce) const
+{
+ return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policies, nonce);
+}
+
+bool ContentSecurityPolicy::allowScriptHash(const String& source) const
+{
+ return checkDigest<&CSPDirectiveList::allowScriptHash>(source, m_scriptHashAlgorithmsUsed, m_policies);
+}
+
+bool ContentSecurityPolicy::allowStyleHash(const String& source) const
+{
+ return checkDigest<&CSPDirectiveList::allowStyleHash>(source, m_styleHashAlgorithmsUsed, m_policies);
+}
+
+void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms)
+{
+ m_scriptHashAlgorithmsUsed |= algorithms;
+}
+
+void ContentSecurityPolicy::usesStyleHashAlgorithms(uint8_t algorithms)
+{
+ m_styleHashAlgorithmsUsed |= algorithms;
+}
+
+bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowStyleFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowAncestors(LocalFrame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithFrame<&CSPDirectiveList::allowAncestors>(m_policies, frame, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ return isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowWorkerContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ // CSP 1.1 moves workers from 'script-src' to the new 'child-src'. Measure the impact of this backwards-incompatible change.
+ if (m_executionContext->isDocument()) {
+ Document* document = static_cast<Document*>(m_executionContext);
+ UseCounter::count(*document, UseCounter::WorkerSubjectToCSP);
+ if (isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, SuppressReport) && !isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, SuppressReport))
+ UseCounter::count(*document, UseCounter::WorkerAllowedByChildBlockedByScript);
+ }
+
+ return experimentalFeaturesEnabled() ?
+ isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(m_policies, url, reportingStatus) :
+ isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, reportingStatus);
+}
+
+bool ContentSecurityPolicy::isActive() const
+{
+ return !m_policies.isEmpty();
+}
+
+ReflectedXSSDisposition ContentSecurityPolicy::reflectedXSSDisposition() const
+{
+ ReflectedXSSDisposition disposition = ReflectedXSSUnset;
+ for (size_t i = 0; i < m_policies.size(); ++i) {
+ if (m_policies[i]->reflectedXSSDisposition() > disposition)
+ disposition = std::max(disposition, m_policies[i]->reflectedXSSDisposition());
+ }
+ return disposition;
+}
+
+ReferrerPolicy ContentSecurityPolicy::referrerPolicy() const
+{
+ ReferrerPolicy policy = ReferrerPolicyDefault;
+ bool first = true;
+ for (size_t i = 0; i < m_policies.size(); ++i) {
+ if (m_policies[i]->didSetReferrerPolicy()) {
+ if (first)
+ policy = m_policies[i]->referrerPolicy();
+ else
+ policy = mergeReferrerPolicies(policy, m_policies[i]->referrerPolicy());
+ }
+ }
+ return policy;
+}
+
+bool ContentSecurityPolicy::didSetReferrerPolicy() const
+{
+ for (size_t i = 0; i < m_policies.size(); ++i) {
+ if (m_policies[i]->didSetReferrerPolicy())
+ return true;
+ }
+ return false;
+}
+
+SecurityOrigin* ContentSecurityPolicy::securityOrigin() const
+{
+ return m_executionContext->securityContext().securityOrigin();
+}
+
+const KURL ContentSecurityPolicy::url() const
+{
+ return m_executionContext->contextURL();
+}
+
+KURL ContentSecurityPolicy::completeURL(const String& url) const
+{
+ return m_executionContext->contextCompleteURL(url);
+}
+
+void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask) const
+{
+ if (Document* document = this->document())
+ document->enforceSandboxFlags(mask);
+}
+
+static String stripURLForUseInReport(Document* document, const KURL& url)
+{
+ if (!url.isValid())
+ return String();
+ if (!url.isHierarchical() || url.protocolIs("file"))
+ return url.protocol();
+ return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsReferrer() : SecurityOrigin::create(url)->toString();
+}
+
+static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventInit& init, Document* document, const String& directiveText, const String& effectiveDirective, const KURL& blockedURL, const String& header)
+{
+ init.documentURI = document->url().string();
+ init.referrer = document->referrer();
+ init.blockedURI = stripURLForUseInReport(document, blockedURL);
+ init.violatedDirective = directiveText;
+ init.effectiveDirective = effectiveDirective;
+ init.originalPolicy = header;
+ init.sourceFile = String();
+ init.lineNumber = 0;
+ init.columnNumber = 0;
+ init.statusCode = 0;
+
+ if (!SecurityOrigin::isSecure(document->url()) && document->loader())
+ init.statusCode = document->loader()->response().httpStatusCode();
+
+ RefPtrWillBeRawPtr<ScriptCallStack> stack = createScriptCallStack(1, false);
+ if (!stack)
+ return;
+
+ const ScriptCallFrame& callFrame = stack->at(0);
+
+ if (callFrame.lineNumber()) {
+ KURL source = KURL(ParsedURLString, callFrame.sourceURL());
+ init.sourceFile = stripURLForUseInReport(document, source);
+ init.lineNumber = callFrame.lineNumber();
+ init.columnNumber = callFrame.columnNumber();
+ }
+}
+
+void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header)
+{
+ // FIXME: Support sending reports from worker.
+ if (!m_executionContext->isDocument())
+ return;
+
+ Document* document = this->document();
+ LocalFrame* frame = document->frame();
+ if (!frame)
+ return;
+
+ SecurityPolicyViolationEventInit violationData;
+ gatherSecurityPolicyViolationEventData(violationData, document, directiveText, effectiveDirective, blockedURL, header);
+
+ if (experimentalFeaturesEnabled())
+ frame->domWindow()->enqueueDocumentEvent(SecurityPolicyViolationEvent::create(EventTypeNames::securitypolicyviolation, violationData));
+
+ if (reportURIs.isEmpty())
+ return;
+
+ // We need to be careful here when deciding what information to send to the
+ // report-uri. Currently, we send only the current document's URL and the
+ // directive that was violated. The document's URL is safe to send because
+ // it's the document itself that's requesting that it be sent. You could
+ // make an argument that we shouldn't send HTTPS document URLs to HTTP
+ // report-uris (for the same reasons that we supress the Referer in that
+ // case), but the Referer is sent implicitly whereas this request is only
+ // sent explicitly. As for which directive was violated, that's pretty
+ // harmless information.
+
+ RefPtr<JSONObject> cspReport = JSONObject::create();
+ cspReport->setString("document-uri", violationData.documentURI);
+ cspReport->setString("referrer", violationData.referrer);
+ cspReport->setString("violated-directive", violationData.violatedDirective);
+ if (experimentalFeaturesEnabled())
+ cspReport->setString("effective-directive", violationData.effectiveDirective);
+ cspReport->setString("original-policy", violationData.originalPolicy);
+ cspReport->setString("blocked-uri", violationData.blockedURI);
+ if (!violationData.sourceFile.isEmpty() && violationData.lineNumber) {
+ cspReport->setString("source-file", violationData.sourceFile);
+ cspReport->setNumber("line-number", violationData.lineNumber);
+ cspReport->setNumber("column-number", violationData.columnNumber);
+ }
+ cspReport->setNumber("status-code", violationData.statusCode);
+
+ RefPtr<JSONObject> reportObject = JSONObject::create();
+ reportObject->setObject("csp-report", cspReport.release());
+ String stringifiedReport = reportObject->toJSONString();
+
+ if (!shouldSendViolationReport(stringifiedReport))
+ return;
+
+ RefPtr<FormData> report = FormData::create(stringifiedReport.utf8());
+
+ for (size_t i = 0; i < reportURIs.size(); ++i)
+ PingLoader::sendViolationReport(frame, reportURIs[i], report, PingLoader::ContentSecurityPolicyViolationReport);
+
+ didSendViolationReport(stringifiedReport);
+}
+
+void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue) const
+{
+ logToConsole("The 'referrer' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"never\", and \"origin\".");
+}
+
+void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) const
+{
+ logToConsole("The report-only Content Security Policy '" + header + "' was delivered via a <meta> element, which is disallowed. The policy has been ignored.");
+}
+
+void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) const
+{
+ logToConsole("The Content Security Policy '" + header + "' was delivered via a <meta> element outside the document's <head>, which is disallowed. The policy has been ignored.");
+}
+
+void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) const
+{
+ logToConsole("The Content Security Policy directive '" + name + "' is ignored when delivered in a report-only policy.");
+}
+
+void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const
+{
+ DEFINE_STATIC_LOCAL(String, allow, ("allow"));
+ DEFINE_STATIC_LOCAL(String, options, ("options"));
+ DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri"));
+ DEFINE_STATIC_LOCAL(String, allowMessage, ("The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect."));
+ DEFINE_STATIC_LOCAL(String, optionsMessage, ("The 'options' directive has been replaced with 'unsafe-inline' and 'unsafe-eval' source expressions for the 'script-src' and 'style-src' directives. Please use those directives instead, as 'options' has no effect."));
+ DEFINE_STATIC_LOCAL(String, policyURIMessage, ("The 'policy-uri' directive has been removed from the specification. Please specify a complete policy via the Content-Security-Policy header."));
+
+ String message = "Unrecognized Content-Security-Policy directive '" + name + "'.\n";
+ if (equalIgnoringCase(name, allow))
+ message = allowMessage;
+ else if (equalIgnoringCase(name, options))
+ message = optionsMessage;
+ else if (equalIgnoringCase(name, policyURI))
+ message = policyURIMessage;
+
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression) const
+{
+ String message = "The Content Security Policy directive '" + directiveName + "' contains '" + sourceExpression + "' as a source expression. Did you mean '" + directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?";
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportDuplicateDirective(const String& name) const
+{
+ String message = "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n";
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) const
+{
+ String message;
+ if (pluginType.isNull())
+ message = "'plugin-types' Content Security Policy directive is empty; all plugins will be blocked.\n";
+ else
+ message = "Invalid plugin type in 'plugin-types' Content Security Policy directive: '" + pluginType + "'.\n";
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags) const
+{
+ logToConsole("Error while parsing the 'sandbox' Content Security Policy directive: " + invalidFlags);
+}
+
+void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue) const
+{
+ logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\", and \"block\".");
+}
+
+void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const
+{
+ String message = "The value for Content Security Policy directive '" + directiveName + "' contains an invalid character: '" + value + "'. Non-whitespace characters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.";
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveName, const String& value, const char invalidChar) const
+{
+ ASSERT(invalidChar == '#' || invalidChar == '?');
+
+ String ignoring = "The fragment identifier, including the '#', will be ignored.";
+ if (invalidChar == '?')
+ ignoring = "The query component, including the '?', will be ignored.";
+ String message = "The source list for Content Security Policy directive '" + directiveName + "' contains a source with an invalid path: '" + value + "'. " + ignoring;
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiveName, const String& source) const
+{
+ String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ignored.";
+ if (equalIgnoringCase(source, "'none'"))
+ message = message + " Note that 'none' has no effect unless it is the only expression in the source list.";
+ logToConsole(message);
+}
+
+void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const
+{
+ logToConsole("The Content Security Policy '" + policy + "' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header.");
+}
+
+void ContentSecurityPolicy::logToConsole(const String& message) const
+{
+ m_executionContext->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
+}
+
+void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String& directiveText) const
+{
+ m_executionContext->reportBlockedScriptExecutionToInspector(directiveText);
+}
+
+bool ContentSecurityPolicy::experimentalFeaturesEnabled() const
+{
+ return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnabled();
+}
+
+bool ContentSecurityPolicy::shouldBypassMainWorld(ExecutionContext* context)
+{
+ if (context && context->isDocument()) {
+ Document* document = toDocument(context);
+ if (document->frame())
+ return document->frame()->script().shouldBypassMainWorldContentSecurityPolicy();
+ }
+ return false;
+}
+
+bool ContentSecurityPolicy::shouldSendViolationReport(const String& report) const
+{
+ // Collisions have no security impact, so we can save space by storing only the string's hash rather than the whole report.
+ return !m_violationReportsSent.contains(report.impl()->hash());
+}
+
+void ContentSecurityPolicy::didSendViolationReport(const String& report)
+{
+ m_violationReportsSent.add(report.impl()->hash());
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h b/chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
new file mode 100644
index 00000000000..5d07921bfef
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2011 Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ContentSecurityPolicy_h
+#define ContentSecurityPolicy_h
+
+#include "bindings/v8/ScriptState.h"
+#include "core/dom/Document.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "platform/network/HTTPParsers.h"
+#include "platform/weborigin/ReferrerPolicy.h"
+#include "wtf/HashSet.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefCounted.h"
+#include "wtf/Vector.h"
+#include "wtf/text/StringHash.h"
+#include "wtf/text/TextPosition.h"
+#include "wtf/text/WTFString.h"
+
+namespace WTF {
+class OrdinalNumber;
+}
+
+namespace WebCore {
+
+class ContentSecurityPolicyResponseHeaders;
+class CSPDirectiveList;
+class DOMStringList;
+class JSONObject;
+class KURL;
+class SecurityOrigin;
+
+typedef int SandboxFlags;
+typedef Vector<OwnPtr<CSPDirectiveList> > CSPDirectiveListVector;
+
+class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ // CSP 1.0 Directives
+ static const char ConnectSrc[];
+ static const char DefaultSrc[];
+ static const char FontSrc[];
+ static const char FrameSrc[];
+ static const char ImgSrc[];
+ static const char MediaSrc[];
+ static const char ObjectSrc[];
+ static const char ReportURI[];
+ static const char Sandbox[];
+ static const char ScriptSrc[];
+ static const char StyleSrc[];
+
+ // CSP 1.1 Directives
+ static const char BaseURI[];
+ static const char ChildSrc[];
+ static const char FormAction[];
+ static const char FrameAncestors[];
+ static const char PluginTypes[];
+ static const char ReflectedXSS[];
+ static const char Referrer[];
+
+ static PassRefPtr<ContentSecurityPolicy> create(ExecutionContext* executionContext)
+ {
+ return adoptRef(new ContentSecurityPolicy(executionContext));
+ }
+ ~ContentSecurityPolicy();
+
+ void copyStateFrom(const ContentSecurityPolicy*);
+
+ enum ReportingStatus {
+ SendReport,
+ SuppressReport
+ };
+
+ void didReceiveHeaders(const ContentSecurityPolicyResponseHeaders&);
+ void didReceiveHeader(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
+
+ // These functions are wrong because they assume that there is only one header.
+ // FIXME: Replace them with functions that return vectors.
+ const String& deprecatedHeader() const;
+ ContentSecurityPolicyHeaderType deprecatedHeaderType() const;
+
+ bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
+ bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
+ bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
+ bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
+ bool allowEval(ScriptState* = 0, ReportingStatus = SendReport) const;
+ bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ReportingStatus = SendReport) const;
+
+ bool allowScriptFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowObjectFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowChildFrameFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowImageFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowStyleFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowFontFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowMediaFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowConnectToSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowFormAction(const KURL&, ReportingStatus = SendReport) const;
+ bool allowBaseURI(const KURL&, ReportingStatus = SendReport) const;
+ bool allowAncestors(LocalFrame*, ReportingStatus = SendReport) const;
+ bool allowChildContextFromSource(const KURL&, ReportingStatus = SendReport) const;
+ bool allowWorkerContextFromSource(const KURL&, ReportingStatus = SendReport) const;
+
+ // The nonce and hash allow functions are guaranteed to not have any side
+ // effects, including reporting.
+ bool allowScriptNonce(const String& nonce) const;
+ bool allowStyleNonce(const String& nonce) const;
+ bool allowScriptHash(const String& source) const;
+ bool allowStyleHash(const String& source) const;
+
+ void usesScriptHashAlgorithms(uint8_t ContentSecurityPolicyHashAlgorithm);
+ void usesStyleHashAlgorithms(uint8_t ContentSecurityPolicyHashAlgorithm);
+
+ ReflectedXSSDisposition reflectedXSSDisposition() const;
+
+ ReferrerPolicy referrerPolicy() const;
+ bool didSetReferrerPolicy() const;
+
+ void setOverrideAllowInlineStyle(bool);
+
+ bool isActive() const;
+
+ void reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression) const;
+ void reportDuplicateDirective(const String&) const;
+ void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const;
+ void reportInvalidPathCharacter(const String& directiveName, const String& value, const char) const;
+ void reportInvalidPluginTypes(const String&) const;
+ void reportInvalidSandboxFlags(const String&) const;
+ void reportInvalidSourceExpression(const String& directiveName, const String& source) const;
+ void reportInvalidReflectedXSS(const String&) const;
+ void reportMissingReportURI(const String&) const;
+ void reportUnsupportedDirective(const String&) const;
+ void reportInvalidInReportOnly(const String&) const;
+ void reportInvalidReferrer(const String&) const;
+ void reportReportOnlyInMeta(const String&) const;
+ void reportMetaOutsideHead(const String&) const;
+ void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header);
+
+ void reportBlockedScriptExecutionToInspector(const String& directiveText) const;
+
+ const KURL url() const;
+ KURL completeURL(const String&) const;
+ SecurityOrigin* securityOrigin() const;
+ void enforceSandboxFlags(SandboxFlags) const;
+ String evalDisabledErrorMessage() const;
+
+ bool experimentalFeaturesEnabled() const;
+
+ static bool shouldBypassMainWorld(ExecutionContext*);
+
+ static bool isDirectiveName(const String&);
+
+ ExecutionContext* executionContext() const { return m_executionContext; }
+ Document* document() const { return m_executionContext->isDocument() ? toDocument(m_executionContext) : 0; }
+
+private:
+ explicit ContentSecurityPolicy(ExecutionContext*);
+
+ void logToConsole(const String& message) const;
+ void addPolicyFromHeaderValue(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
+
+ bool shouldSendViolationReport(const String&) const;
+ void didSendViolationReport(const String&);
+
+ ExecutionContext* m_executionContext;
+ bool m_overrideInlineStyleAllowed;
+ CSPDirectiveListVector m_policies;
+
+ HashSet<unsigned, AlreadyHashed> m_violationReportsSent;
+
+ // We put the hash functions used on the policy object so that we only need
+ // to calculate a hash once and then distribute it to all of the directives
+ // for validation.
+ uint8_t m_scriptHashAlgorithmsUsed;
+ uint8_t m_styleHashAlgorithmsUsed;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.cpp b/chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.cpp
new file mode 100644
index 00000000000..434c779dfd8
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.cpp
@@ -0,0 +1,86 @@
+// Copyright 2014 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 "config.h"
+#include "core/frame/csp/MediaListDirective.h"
+
+#include "core/frame/csp/ContentSecurityPolicy.h"
+#include "platform/ParsingUtilities.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "wtf/HashSet.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+MediaListDirective::MediaListDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
+ : CSPDirective(name, value, policy)
+{
+ Vector<UChar> characters;
+ value.appendTo(characters);
+ parse(characters.data(), characters.data() + characters.size());
+}
+
+bool MediaListDirective::allows(const String& type)
+{
+ return m_pluginTypes.contains(type);
+}
+
+void MediaListDirective::parse(const UChar* begin, const UChar* end)
+{
+ const UChar* position = begin;
+
+ // 'plugin-types ____;' OR 'plugin-types;'
+ if (position == end) {
+ policy()->reportInvalidPluginTypes(String());
+ return;
+ }
+
+ while (position < end) {
+ // _____ OR _____mime1/mime1
+ // ^ ^
+ skipWhile<UChar, isASCIISpace>(position, end);
+ if (position == end)
+ return;
+
+ // mime1/mime1 mime2/mime2
+ // ^
+ begin = position;
+ if (!skipExactly<UChar, isMediaTypeCharacter>(position, end)) {
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+ skipWhile<UChar, isMediaTypeCharacter>(position, end);
+
+ // mime1/mime1 mime2/mime2
+ // ^
+ if (!skipExactly<UChar>(position, end, '/')) {
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+
+ // mime1/mime1 mime2/mime2
+ // ^
+ if (!skipExactly<UChar, isMediaTypeCharacter>(position, end)) {
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+ skipWhile<UChar, isMediaTypeCharacter>(position, end);
+
+ // mime1/mime1 mime2/mime2 OR mime1/mime1 OR mime1/mime1/error
+ // ^ ^ ^
+ if (position < end && isNotASCIISpace(*position)) {
+ skipWhile<UChar, isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+ m_pluginTypes.add(String(begin, position - begin));
+
+ ASSERT(position == end || isASCIISpace(*position));
+ }
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.h b/chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.h
new file mode 100644
index 00000000000..9f230ce987e
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/MediaListDirective.h
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+#ifndef MediaListDirective_h
+#define MediaListDirective_h
+
+#include "core/frame/csp/CSPDirective.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "wtf/HashSet.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ContentSecurityPolicy;
+
+class MediaListDirective FINAL : public CSPDirective {
+ WTF_MAKE_NONCOPYABLE(MediaListDirective);
+public:
+ MediaListDirective(const String& name, const String& value, ContentSecurityPolicy*);
+ bool allows(const String& type);
+
+private:
+ void parse(const UChar* begin, const UChar* end);
+
+ HashSet<String> m_pluginTypes;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp b/chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
new file mode 100644
index 00000000000..ccf8c37d792
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
@@ -0,0 +1,62 @@
+// Copyright 2014 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 "config.h"
+#include "core/frame/csp/SourceListDirective.h"
+
+#include "core/frame/csp/CSPSourceList.h"
+#include "core/frame/csp/ContentSecurityPolicy.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "platform/weborigin/KURL.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+SourceListDirective::SourceListDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
+ : CSPDirective(name, value, policy)
+ , m_sourceList(policy, name)
+{
+ Vector<UChar> characters;
+ value.appendTo(characters);
+
+ m_sourceList.parse(characters.data(), characters.data() + characters.size());
+}
+
+bool SourceListDirective::allows(const KURL& url) const
+{
+ return m_sourceList.matches(url.isEmpty() ? policy()->url() : url);
+}
+
+bool SourceListDirective::allowInline() const
+{
+ return m_sourceList.allowInline();
+}
+
+bool SourceListDirective::allowEval() const
+{
+ return m_sourceList.allowEval();
+}
+
+bool SourceListDirective::allowNonce(const String& nonce) const
+{
+ return m_sourceList.allowNonce(nonce.stripWhiteSpace());
+}
+
+bool SourceListDirective::allowHash(const CSPHashValue& hashValue) const
+{
+ return m_sourceList.allowHash(hashValue);
+}
+
+bool SourceListDirective::isHashOrNoncePresent() const
+{
+ return m_sourceList.isHashOrNoncePresent();
+}
+
+uint8_t SourceListDirective::hashAlgorithmsUsed() const
+{
+ return m_sourceList.hashAlgorithmsUsed();
+}
+
+} // namespace WebCore
+
diff --git a/chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h b/chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h
new file mode 100644
index 00000000000..38005d13833
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+#ifndef SourceListDirective_h
+#define SourceListDirective_h
+
+#include "core/frame/csp/CSPDirective.h"
+#include "core/frame/csp/CSPSourceList.h"
+#include "platform/network/ContentSecurityPolicyParsers.h"
+#include "wtf/HashSet.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ContentSecurityPolicy;
+class KURL;
+
+class SourceListDirective FINAL : public CSPDirective {
+ WTF_MAKE_NONCOPYABLE(SourceListDirective);
+public:
+ SourceListDirective(const String& name, const String& value, ContentSecurityPolicy*);
+
+ bool allows(const KURL&) const;
+ bool allowInline() const;
+ bool allowEval() const;
+ bool allowNonce(const String& nonce) const;
+ bool allowHash(const CSPHashValue&) const;
+ bool isHashOrNoncePresent() const;
+ uint8_t hashAlgorithmsUsed() const;
+
+private:
+ CSPSourceList m_sourceList;
+};
+
+} // namespace WebCore
+
+#endif