diff options
Diffstat (limited to 'Source/WebCore/page/ContentSecurityPolicy.cpp')
-rw-r--r-- | Source/WebCore/page/ContentSecurityPolicy.cpp | 116 |
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)); } } |