summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/page/ContentSecurityPolicy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/ContentSecurityPolicy.cpp')
-rw-r--r--Source/WebCore/page/ContentSecurityPolicy.cpp116
1 files changed, 111 insertions, 5 deletions
diff --git a/Source/WebCore/page/ContentSecurityPolicy.cpp b/Source/WebCore/page/ContentSecurityPolicy.cpp
index 045e5aa..97cd447 100644
--- a/Source/WebCore/page/ContentSecurityPolicy.cpp
+++ b/Source/WebCore/page/ContentSecurityPolicy.cpp
@@ -29,20 +29,126 @@
namespace WebCore {
+class CSPDirective {
+public:
+ explicit CSPDirective(const String& value)
+ : m_value(value)
+ {
+ }
+
+ bool allows(const KURL&)
+ {
+ return false;
+ }
+
+private:
+ String m_value;
+};
+
ContentSecurityPolicy::ContentSecurityPolicy()
- : m_isEnabled(false)
+ : m_havePolicy(false)
+{
+}
+
+ContentSecurityPolicy::~ContentSecurityPolicy()
{
}
void ContentSecurityPolicy::didReceiveHeader(const String& header)
{
- m_isEnabled = true;
- m_header = header;
+ if (m_havePolicy)
+ return; // The first policy wins.
+
+ parse(header);
+ m_havePolicy = true;
+}
+
+bool ContentSecurityPolicy::allowJavaScriptURLs() const
+{
+ return !m_scriptSrc;
+}
+
+bool ContentSecurityPolicy::canLoadExternalScriptFromSrc(const String& url) const
+{
+ return !m_scriptSrc || m_scriptSrc->allows(KURL(ParsedURLString, url));
+}
+
+void ContentSecurityPolicy::parse(const String& policy)
+{
+ ASSERT(!m_havePolicy);
+
+ if (policy.isEmpty())
+ return;
+
+ const UChar* pos = policy.characters();
+ const UChar* end = pos + policy.length();
+
+ while (pos < end) {
+ Vector<UChar, 32> name;
+ Vector<UChar, 64> value;
+
+ parseDirective(pos, end, name, value);
+ if (name.isEmpty())
+ continue;
+
+ // We use a copy here instead of String::adopt because we expect
+ // the name and the value to be relatively short, so the copy will
+ // be cheaper than the extra malloc.
+ emitDirective(String(name), String(value));
+ }
+}
+
+void ContentSecurityPolicy::parseDirective(const UChar*& pos, const UChar* end, Vector<UChar, 32>& name, Vector<UChar, 64>& value)
+{
+ ASSERT(pos < end);
+ ASSERT(name.isEmpty());
+ ASSERT(value.isEmpty());
+
+ enum {
+ BeforeDirectiveName,
+ DirectiveName,
+ AfterDirectiveName,
+ DirectiveValue,
+ } state = BeforeDirectiveName;
+
+ while (pos < end) {
+ UChar currentCharacter = *pos++;
+ switch (state) {
+ case BeforeDirectiveName:
+ if (isASCIISpace(currentCharacter))
+ continue;
+ state = DirectiveName;
+ // Fall through.
+ case DirectiveName:
+ if (!isASCIISpace(currentCharacter)) {
+ name.append(currentCharacter);
+ continue;
+ }
+ state = AfterDirectiveName;
+ // Fall through.
+ case AfterDirectiveName:
+ if (isASCIISpace(currentCharacter))
+ continue;
+ state = DirectiveValue;
+ // Fall through.
+ case DirectiveValue:
+ if (currentCharacter != ';') {
+ value.append(currentCharacter);
+ continue;
+ }
+ return;
+ }
+ }
}
-bool ContentSecurityPolicy::canLoadExternalScriptFromSrc(const String&) const
+void ContentSecurityPolicy::emitDirective(const String& name, const String& value)
{
- return !m_isEnabled;
+ DEFINE_STATIC_LOCAL(String, scriptSrc, ("script-src"));
+
+ ASSERT(!name.isEmpty());
+
+ if (!m_scriptSrc && equalIgnoringCase(name, scriptSrc))
+ m_scriptSrc = adoptPtr(new CSPDirective(value));
}
}