Modified: trunk/Source/WebCore/page/ContentSecurityPolicy.cpp (125816 => 125817)
--- trunk/Source/WebCore/page/ContentSecurityPolicy.cpp 2012-08-16 22:42:03 UTC (rev 125816)
+++ trunk/Source/WebCore/page/ContentSecurityPolicy.cpp 2012-08-16 22:44:07 UTC (rev 125817)
@@ -536,27 +536,162 @@
class CSPDirective {
public:
CSPDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
- : m_sourceList(policy, name)
+ : m_name(name)
, m_text(name + ' ' + value)
- , m_selfURL(policy->url())
+ , 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;
+};
+
+class NonceDirective : public CSPDirective {
+public:
+ NonceDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
+ : CSPDirective(name, value, policy)
+ {
+ parse(value);
+ }
+
+ bool allows(const String& nonce) const
+ {
+ return (!m_scriptNonce.isEmpty() && nonce.stripWhiteSpace() == m_scriptNonce);
+ }
+
+private:
+ void parse(const String& value)
+ {
+ String nonce;
+ const UChar* position = value.characters();
+ const UChar* end = position + value.length();
+
+ skipWhile<isASCIISpace>(position, end);
+ const UChar* nonceBegin = position;
+ if (position == end) {
+ policy()->reportInvalidNonce(String());
+ m_scriptNonce = "";
+ return;
+ }
+ skipWhile<isNonceCharacter>(position, end);
+ if (nonceBegin < position)
+ nonce = String(nonceBegin, position - nonceBegin);
+
+ // Trim off trailing whitespace: If we're not at the end of the string, log
+ // an error.
+ skipWhile<isASCIISpace>(position, end);
+ if (position < end) {
+ policy()->reportInvalidNonce(value);
+ m_scriptNonce = "";
+ } else
+ m_scriptNonce = nonce;
+ }
+
+ String m_scriptNonce;
+};
+
+class MediaListDirective : public CSPDirective {
+public:
+ MediaListDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
+ : CSPDirective(name, value, policy)
+ {
+ parse(value);
+ }
+
+ bool allows(const String& type)
+ {
+ return m_pluginTypes.contains(type);
+ }
+
+private:
+ void parse(const String& value)
+ {
+ const UChar* begin = value.characters();
+ const UChar* position = begin;
+ const UChar* end = begin + value.length();
+
+ // 'plugin-types ____;' OR 'plugin-types;'
+ if (value.isEmpty()) {
+ policy()->reportInvalidPluginTypes(value);
+ return;
+ }
+
+ while (position < end) {
+ // _____ OR _____mime1/mime1
+ // ^ ^
+ skipWhile<isASCIISpace>(position, end);
+ if (position == end)
+ return;
+
+ // mime1/mime1 mime2/mime2
+ // ^
+ begin = position;
+ if (!skipExactly<isMediaTypeCharacter>(position, end)) {
+ skipWhile<isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+ skipWhile<isMediaTypeCharacter>(position, end);
+
+ // mime1/mime1 mime2/mime2
+ // ^
+ if (!skipExactly(position, end, '/')) {
+ skipWhile<isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+
+ // mime1/mime1 mime2/mime2
+ // ^
+ if (!skipExactly<isMediaTypeCharacter>(position, end)) {
+ skipWhile<isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+ skipWhile<isMediaTypeCharacter>(position, end);
+
+ // mime1/mime1 mime2/mime2 OR mime1/mime1 OR mime1/mime1/error
+ // ^ ^ ^
+ if (position < end && isNotASCIISpace(*position)) {
+ skipWhile<isNotASCIISpace>(position, end);
+ policy()->reportInvalidPluginTypes(String(begin, position - begin));
+ continue;
+ }
+ m_pluginTypes.add(String(begin, position - begin));
+
+ ASSERT(position == end || isASCIISpace(*position));
+ }
+ }
+
+ HashSet<String> m_pluginTypes;
+};
+
+class SourceListDirective : public CSPDirective {
+public:
+ SourceListDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
+ : CSPDirective(name, value, policy)
+ , m_sourceList(policy, name)
+ {
m_sourceList.parse(value);
}
bool allows(const KURL& url)
{
- return m_sourceList.matches(url.isEmpty() ? m_selfURL : url);
+ return m_sourceList.matches(url.isEmpty() ? policy()->url() : url);
}
bool allowInline() const { return m_sourceList.allowInline(); }
bool allowEval() const { return m_sourceList.allowEval(); }
- const String& text() { return m_text; }
-
private:
CSPSourceList m_sourceList;
- String m_text;
- KURL m_selfURL;
};
class CSPDirectiveList {
@@ -598,22 +733,23 @@
void addDirective(const String& name, const String& value);
void applySandboxPolicy(const String& name, const String& sandboxPolicy);
- void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirective>&);
+ template <class CSPDirectiveType>
+ void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>&);
- CSPDirective* operativeDirective(CSPDirective*) const;
+ SourceListDirective* operativeDirective(SourceListDirective*) const;
void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL = KURL(), const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
- bool checkEval(CSPDirective*) const;
- bool checkInline(CSPDirective*) const;
- bool checkNonce(const String&) const;
- bool checkSource(CSPDirective*, const KURL&) const;
- bool checkPluginType(const String& type, const String& typeAttribute) const;
+ bool checkEval(SourceListDirective*) const;
+ bool checkInline(SourceListDirective*) const;
+ bool checkNonce(NonceDirective*, const String&) const;
+ bool checkSource(SourceListDirective*, const KURL&) const;
+ bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
- bool checkEvalAndReportViolation(CSPDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
- bool checkInlineAndReportViolation(CSPDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
- bool checkNonceAndReportViolation(const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
- bool checkSourceAndReportViolation(CSPDirective*, const KURL&, const String& type) const;
- bool checkPluginTypeAndReportViolation(const String& type, const String& typeAttribute, const String& consoleMessage) const;
+ bool checkEvalAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
+ bool checkInlineAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
+ bool checkNonceAndReportViolation(NonceDirective*, const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
+ bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& type) const;
+ bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& type, const String& typeAttribute, const String& consoleMessage) const;
bool denyIfEnforcingPolicy() const { return m_reportOnly; }
@@ -623,21 +759,20 @@
bool m_reportOnly;
bool m_haveSandboxPolicy;
- OwnPtr<CSPDirective> m_defaultSrc;
- OwnPtr<CSPDirective> m_scriptSrc;
- OwnPtr<CSPDirective> m_objectSrc;
- OwnPtr<CSPDirective> m_frameSrc;
- OwnPtr<CSPDirective> m_imgSrc;
- OwnPtr<CSPDirective> m_styleSrc;
- OwnPtr<CSPDirective> m_fontSrc;
- OwnPtr<CSPDirective> m_mediaSrc;
- OwnPtr<CSPDirective> m_connectSrc;
- OwnPtr<CSPDirective> m_formAction;
+ OwnPtr<MediaListDirective> m_pluginTypes;
+ OwnPtr<NonceDirective> m_scriptNonce;
+ OwnPtr<SourceListDirective> m_connectSrc;
+ OwnPtr<SourceListDirective> m_defaultSrc;
+ OwnPtr<SourceListDirective> m_fontSrc;
+ OwnPtr<SourceListDirective> m_formAction;
+ 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;
- HashSet<String> m_pluginTypes;
- String m_pluginTypesDirective;
- String m_scriptNonce;
};
CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy)
@@ -671,43 +806,41 @@
m_policy->reportViolation(directiveText, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine, callStack);
}
-bool CSPDirectiveList::checkEval(CSPDirective* directive) const
+bool CSPDirectiveList::checkEval(SourceListDirective* directive) const
{
return !directive || directive->allowEval();
}
-bool CSPDirectiveList::checkInline(CSPDirective* directive) const
+bool CSPDirectiveList::checkInline(SourceListDirective* directive) const
{
return !directive || directive->allowInline();
}
-bool CSPDirectiveList::checkNonce(const String& nonce) const
+bool CSPDirectiveList::checkNonce(NonceDirective* directive, const String& nonce) const
{
- return (m_scriptNonce.isNull()
- || (!m_scriptNonce.isEmpty()
- && nonce.stripWhiteSpace() == m_scriptNonce));
+ return !directive || directive->allows(nonce);
}
-bool CSPDirectiveList::checkSource(CSPDirective* directive, const KURL& url) const
+bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& url) const
{
return !directive || directive->allows(url);
}
-bool CSPDirectiveList::checkPluginType(const String& type, const String& typeAttribute) const
+bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
{
- if (m_pluginTypesDirective.isNull())
+ if (!directive)
return true;
if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
return false;
- return m_pluginTypes.contains(type);
+ return directive->allows(type);
}
-CSPDirective* CSPDirectiveList::operativeDirective(CSPDirective* directive) const
+SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive) const
{
return directive ? directive : m_defaultSrc.get();
}
-bool CSPDirectiveList::checkEvalAndReportViolation(CSPDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
+bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
{
if (checkEval(directive))
return true;
@@ -715,24 +848,24 @@
return denyIfEnforcingPolicy();
}
-bool CSPDirectiveList::checkNonceAndReportViolation(const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
+bool CSPDirectiveList::checkNonceAndReportViolation(NonceDirective* directive, const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
{
- if (checkNonce(nonce))
+ if (checkNonce(directive, nonce))
return true;
- reportViolation(m_scriptNonce, consoleMessage + "\"script-nonce " + m_scriptNonce + "\".\n", KURL(), contextURL, contextLine);
+ reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine);
return denyIfEnforcingPolicy();
}
-bool CSPDirectiveList::checkPluginTypeAndReportViolation(const String& type, const String& typeAttribute, const String& consoleMessage) const
+bool CSPDirectiveList::checkMediaTypeAndReportViolation(MediaListDirective* directive, const String& type, const String& typeAttribute, const String& consoleMessage) const
{
- if (checkPluginType(type, typeAttribute))
+ if (checkMediaType(directive, type, typeAttribute))
return true;
- reportViolation(m_pluginTypesDirective, consoleMessage + "'plugin-types " + m_pluginTypesDirective + "'.\n", KURL());
+ reportViolation(directive->text(), consoleMessage + "\'" + directive->text() + "\'.\n", KURL());
return denyIfEnforcingPolicy();
}
-bool CSPDirectiveList::checkInlineAndReportViolation(CSPDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
+bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
{
if (checkInline(directive))
return true;
@@ -740,7 +873,7 @@
return denyIfEnforcingPolicy();
}
-bool CSPDirectiveList::checkSourceAndReportViolation(CSPDirective* directive, const KURL& url, const String& type) const
+bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& type) const
{
if (checkSource(directive, url))
return true;
@@ -760,10 +893,10 @@
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)
- && checkNonceAndReportViolation(String(), consoleMessage, contextURL, contextLine));
+ && checkNonceAndReportViolation(m_scriptNonce.get(), String(), consoleMessage, contextURL, contextLine));
} else {
return (checkInline(operativeDirective(m_scriptSrc.get()))
- && checkNonce(String()));
+ && checkNonce(m_scriptNonce.get(), String()));
}
}
@@ -772,10 +905,10 @@
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)
- && checkNonceAndReportViolation(String(), consoleMessage, contextURL, contextLine));
+ && checkNonceAndReportViolation(m_scriptNonce.get(), String(), consoleMessage, contextURL, contextLine));
} else {
return (checkInline(operativeDirective(m_scriptSrc.get()))
- && checkNonce(String()));
+ && checkNonce(m_scriptNonce.get(), String()));
}
}
@@ -807,15 +940,15 @@
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute script because it violates the following Content Security Policy directive: "));
if (url.isEmpty())
- return checkNonceAndReportViolation(nonce, consoleMessage, contextURL, contextLine);
- return checkNonceAndReportViolation(nonce, "Refused to load '" + url.string() + "' because it violates the following Content Security Policy directive: ", contextURL, contextLine);
+ return checkNonceAndReportViolation(m_scriptNonce.get(), nonce, consoleMessage, contextURL, contextLine);
+ return checkNonceAndReportViolation(m_scriptNonce.get(), nonce, "Refused to load '" + url.string() + "' because it violates the following Content Security Policy directive: ", contextURL, contextLine);
}
bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
- checkPluginTypeAndReportViolation(type, typeAttribute, "Refused to load '" + url.string() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") :
- checkPluginType(type, typeAttribute);
+ checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.string() + "' (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
@@ -1001,111 +1134,15 @@
}
}
-void CSPDirectiveList::parseScriptNonce(const String& name, const String& value)
-{
- if (!m_scriptNonce.isNull()) {
- m_policy->reportDuplicateDirective(name);
- return;
- }
- String nonce;
- const UChar* position = value.characters();
- const UChar* end = position + value.length();
-
- skipWhile<isASCIISpace>(position, end);
- const UChar* nonceBegin = position;
- if (position == end) {
- m_policy->reportInvalidNonce(String());
- m_scriptNonce = "";
- return;
- }
- skipWhile<isNonceCharacter>(position, end);
- if (nonceBegin < position)
- nonce = String(nonceBegin, position - nonceBegin);
-
- // Trim off trailing whitespace: If we're not at the end of the string, log
- // an error.
- skipWhile<isASCIISpace>(position, end);
- if (position < end) {
- m_policy->reportInvalidNonce(value);
- m_scriptNonce = "";
- } else
- m_scriptNonce = nonce;
-}
-
-void CSPDirectiveList::parsePluginTypes(const String& name, const String& value)
+template<class CSPDirectiveType>
+void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>& directive)
{
- if (!m_pluginTypesDirective.isNull()) {
- m_policy->reportDuplicateDirective(name);
- return;
- }
-
- const UChar* begin = value.characters();
- const UChar* position = begin;
- const UChar* end = begin + value.length();
- m_pluginTypesDirective = value;
-
- // 'plugin-types ____;' OR 'plugin-types;'
- if (value.isEmpty()) {
- m_policy->reportInvalidPluginTypes(value);
- m_pluginTypesDirective = "";
- return;
- }
-
- while (position < end) {
- // _____ OR _____mime1/mime1
- // ^ ^
- skipWhile<isASCIISpace>(position, end);
- if (position == end)
- return;
-
- // mime1/mime1 mime2/mime2
- // ^
- begin = position;
- if (!skipExactly<isMediaTypeCharacter>(position, end)) {
- skipWhile<isNotASCIISpace>(position, end);
- m_policy->reportInvalidPluginTypes(String(begin, position - begin));
- continue;
- }
- skipWhile<isMediaTypeCharacter>(position, end);
-
- // mime1/mime1 mime2/mime2
- // ^
- if (!skipExactly(position, end, '/')) {
- skipWhile<isNotASCIISpace>(position, end);
- m_policy->reportInvalidPluginTypes(String(begin, position - begin));
- continue;
- }
-
- // mime1/mime1 mime2/mime2
- // ^
- if (!skipExactly<isMediaTypeCharacter>(position, end)) {
- skipWhile<isNotASCIISpace>(position, end);
- m_policy->reportInvalidPluginTypes(String(begin, position - begin));
- continue;
- }
- skipWhile<isMediaTypeCharacter>(position, end);
-
- // mime1/mime1 mime2/mime2 OR mime1/mime1 OR mime1/mime1/error
- // ^ ^ ^
- if (position < end && isNotASCIISpace(*position)) {
- skipWhile<isNotASCIISpace>(position, end);
- m_policy->reportInvalidPluginTypes(String(begin, position - begin));
- continue;
- }
- m_pluginTypes.add(String(begin, position - begin));
-
- ASSERT(position == end || isASCIISpace(*position));
- }
-}
-
-void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirective>& directive)
-{
if (directive) {
m_policy->reportDuplicateDirective(name);
return;
}
- directive = adoptPtr(new CSPDirective(name, value, m_policy));
+ directive = adoptPtr(new CSPDirectiveType(name, value, m_policy));
}
void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sandboxPolicy)
@@ -1140,34 +1177,34 @@
ASSERT(!name.isEmpty());
if (equalIgnoringCase(name, defaultSrc))
- setCSPDirective(name, value, m_defaultSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_defaultSrc);
else if (equalIgnoringCase(name, scriptSrc))
- setCSPDirective(name, value, m_scriptSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_scriptSrc);
else if (equalIgnoringCase(name, objectSrc))
- setCSPDirective(name, value, m_objectSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_objectSrc);
else if (equalIgnoringCase(name, frameSrc))
- setCSPDirective(name, value, m_frameSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_frameSrc);
else if (equalIgnoringCase(name, imgSrc))
- setCSPDirective(name, value, m_imgSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_imgSrc);
else if (equalIgnoringCase(name, styleSrc))
- setCSPDirective(name, value, m_styleSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_styleSrc);
else if (equalIgnoringCase(name, fontSrc))
- setCSPDirective(name, value, m_fontSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_fontSrc);
else if (equalIgnoringCase(name, mediaSrc))
- setCSPDirective(name, value, m_mediaSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_mediaSrc);
else if (equalIgnoringCase(name, connectSrc))
- setCSPDirective(name, value, m_connectSrc);
+ setCSPDirective<SourceListDirective>(name, value, m_connectSrc);
else if (equalIgnoringCase(name, sandbox))
applySandboxPolicy(name, value);
else if (equalIgnoringCase(name, reportURI))
parseReportURI(name, value);
#if ENABLE(CSP_NEXT)
else if (equalIgnoringCase(name, formAction))
- setCSPDirective(name, value, m_formAction);
+ setCSPDirective<SourceListDirective>(name, value, m_formAction);
else if (equalIgnoringCase(name, pluginTypes))
- parsePluginTypes(name, value);
+ setCSPDirective<MediaListDirective>(name, value, m_pluginTypes);
else if (equalIgnoringCase(name, scriptNonce))
- parseScriptNonce(name, value);
+ setCSPDirective<NonceDirective>(name, value, m_scriptNonce);
#endif
else
m_policy->reportUnrecognizedDirective(name);