1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/frame/csp/CSPDirectiveList.h"
8 #include "core/dom/Document.h"
9 #include "core/frame/LocalFrame.h"
10 #include "core/inspector/ConsoleMessage.h"
11 #include "platform/ParsingUtilities.h"
12 #include "platform/weborigin/KURL.h"
13 #include "wtf/text/WTFString.h"
17 CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
20 , m_headerSource(source)
22 , m_haveSandboxPolicy(false)
23 , m_reflectedXSSDisposition(ReflectedXSSUnset)
24 , m_didSetReferrerPolicy(false)
25 , m_referrerPolicy(ReferrerPolicyDefault)
27 m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport;
30 PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* policy, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
32 OwnPtr<CSPDirectiveList> directives = adoptPtr(new CSPDirectiveList(policy, type, source));
33 directives->parse(begin, end);
35 if (!directives->checkEval(directives->operativeDirective(directives->m_scriptSrc.get()))) {
36 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";
37 directives->setEvalDisabledErrorMessage(message);
40 if (directives->isReportOnly() && directives->reportEndpoints().isEmpty())
41 policy->reportMissingReportURI(String(begin, end - begin));
43 return directives.release();
46 void CSPDirectiveList::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const
48 String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
49 m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message));
50 m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header);
53 void CSPDirectiveList::reportViolationWithFrame(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, LocalFrame* frame) const
55 String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
56 m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message), frame);
57 m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header, frame);
60 void CSPDirectiveList::reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
62 String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
63 m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt()));
64 m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header);
67 void CSPDirectiveList::reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& message, const KURL& blockedURL, ScriptState* scriptState) const
69 String reportMessage = m_reportOnly ? "[Report Only] " + message : message;
70 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, reportMessage);
71 consoleMessage->setScriptState(scriptState);
72 m_policy->logToConsole(consoleMessage.release());
73 m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header);
76 bool CSPDirectiveList::checkEval(SourceListDirective* directive) const
78 return !directive || directive->allowEval();
81 bool CSPDirectiveList::checkInline(SourceListDirective* directive) const
83 return !directive || (directive->allowInline() && !directive->isHashOrNoncePresent());
86 bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String& nonce) const
88 return !directive || directive->allowNonce(nonce);
91 bool CSPDirectiveList::checkHash(SourceListDirective* directive, const CSPHashValue& hashValue) const
93 return !directive || directive->allowHash(hashValue);
96 bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& url) const
98 return !directive || directive->allows(url);
101 bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, LocalFrame* frame) const
103 if (!frame || !directive)
106 for (Frame* current = frame->tree().parent(); current; current = current->tree().parent()) {
107 // FIXME: To make this work for out-of-process iframes, we need to propagate URL information of ancestor frames across processes.
108 if (!current->isLocalFrame() || !directive->allows(toLocalFrame(current)->document()->url()))
114 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
118 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
120 return directive->allows(type);
123 SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive) const
125 return directive ? directive : m_defaultSrc.get();
128 SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive, SourceListDirective* override) const
130 return directive ? directive : override;
133 bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, ScriptState* scriptState) const
135 if (checkEval(directive))
138 String suffix = String();
139 if (directive == m_defaultSrc)
140 suffix = " Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.";
142 reportViolationWithState(directive->text(), ContentSecurityPolicy::ScriptSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), scriptState);
144 m_policy->reportBlockedScriptExecutionToInspector(directive->text());
150 bool CSPDirectiveList::checkMediaTypeAndReportViolation(MediaListDirective* directive, const String& type, const String& typeAttribute, const String& consoleMessage) const
152 if (checkMediaType(directive, type, typeAttribute))
155 String message = consoleMessage + "\'" + directive->text() + "\'.";
156 if (typeAttribute.isEmpty())
157 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]\" ...>').";
159 reportViolation(directive->text(), ContentSecurityPolicy::PluginTypes, message + "\n", KURL());
160 return denyIfEnforcingPolicy();
163 bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const
165 if (checkInline(directive))
168 String suffix = String();
169 if (directive->allowInline() && directive->isHashOrNoncePresent()) {
170 // If inline is allowed, but a hash or nonce is present, we ignore 'unsafe-inline'. Throw a reasonable error.
171 suffix = " Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.";
173 suffix = " Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.";
174 if (directive == m_defaultSrc)
175 suffix = suffix + " Note also that '" + String(isScript ? "script" : "style") + "-src' was not explicitly set, so 'default-src' is used as a fallback.";
178 reportViolationWithLocation(directive->text(), isScript ? ContentSecurityPolicy::ScriptSrc : ContentSecurityPolicy::StyleSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine);
182 m_policy->reportBlockedScriptExecutionToInspector(directive->text());
188 bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& effectiveDirective) const
190 if (checkSource(directive, url))
194 if (ContentSecurityPolicy::BaseURI == effectiveDirective)
195 prefix = "Refused to set the document's base URI to '";
196 else if (ContentSecurityPolicy::ChildSrc == effectiveDirective)
197 prefix = "Refused to create a child context containing '";
198 else if (ContentSecurityPolicy::ConnectSrc == effectiveDirective)
199 prefix = "Refused to connect to '";
200 else if (ContentSecurityPolicy::FontSrc == effectiveDirective)
201 prefix = "Refused to load the font '";
202 else if (ContentSecurityPolicy::FormAction == effectiveDirective)
203 prefix = "Refused to send form data to '";
204 else if (ContentSecurityPolicy::FrameSrc == effectiveDirective)
205 prefix = "Refused to frame '";
206 else if (ContentSecurityPolicy::ImgSrc == effectiveDirective)
207 prefix = "Refused to load the image '";
208 else if (ContentSecurityPolicy::MediaSrc == effectiveDirective)
209 prefix = "Refused to load media from '";
210 else if (ContentSecurityPolicy::ObjectSrc == effectiveDirective)
211 prefix = "Refused to load plugin data from '";
212 else if (ContentSecurityPolicy::ScriptSrc == effectiveDirective)
213 prefix = "Refused to load the script '";
214 else if (ContentSecurityPolicy::StyleSrc == effectiveDirective)
215 prefix = "Refused to load the stylesheet '";
217 String suffix = String();
218 if (directive == m_defaultSrc)
219 suffix = " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback.";
221 reportViolation(directive->text(), effectiveDirective, prefix + url.elidedString() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url);
222 return denyIfEnforcingPolicy();
225 bool CSPDirectiveList::checkAncestorsAndReportViolation(SourceListDirective* directive, LocalFrame* frame, const KURL& url) const
227 if (checkAncestors(directive, frame))
230 reportViolationWithFrame(directive->text(), "frame-ancestors", "Refused to display '" + url.elidedString() + "' in a frame because an ancestor violates the following Content Security Policy directive: \"" + directive->text() + "\".", url, frame);
231 return denyIfEnforcingPolicy();
234 bool CSPDirectiveList::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
236 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "));
237 if (reportingStatus == ContentSecurityPolicy::SendReport)
238 return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
240 return checkInline(operativeDirective(m_scriptSrc.get()));
243 bool CSPDirectiveList::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
245 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline event handler because it violates the following Content Security Policy directive: "));
246 if (reportingStatus == ContentSecurityPolicy::SendReport)
247 return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
248 return checkInline(operativeDirective(m_scriptSrc.get()));
251 bool CSPDirectiveList::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
253 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline script because it violates the following Content Security Policy directive: "));
254 return reportingStatus == ContentSecurityPolicy::SendReport ?
255 checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true) :
256 checkInline(operativeDirective(m_scriptSrc.get()));
259 bool CSPDirectiveList::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
261 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to apply inline style because it violates the following Content Security Policy directive: "));
262 return reportingStatus == ContentSecurityPolicy::SendReport ?
263 checkInlineAndReportViolation(operativeDirective(m_styleSrc.get()), consoleMessage, contextURL, contextLine, false) :
264 checkInline(operativeDirective(m_styleSrc.get()));
267 bool CSPDirectiveList::allowEval(ScriptState* scriptState, ContentSecurityPolicy::ReportingStatus reportingStatus) const
269 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: "));
271 return reportingStatus == ContentSecurityPolicy::SendReport ?
272 checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, scriptState) :
273 checkEval(operativeDirective(m_scriptSrc.get()));
276 bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
278 return reportingStatus == ContentSecurityPolicy::SendReport ?
279 checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.elidedString() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") :
280 checkMediaType(m_pluginTypes.get(), type, typeAttribute);
283 bool CSPDirectiveList::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
285 return reportingStatus == ContentSecurityPolicy::SendReport ?
286 checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, ContentSecurityPolicy::ScriptSrc) :
287 checkSource(operativeDirective(m_scriptSrc.get()), url);
290 bool CSPDirectiveList::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
292 if (url.protocolIsAbout())
294 return reportingStatus == ContentSecurityPolicy::SendReport ?
295 checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, ContentSecurityPolicy::ObjectSrc) :
296 checkSource(operativeDirective(m_objectSrc.get()), url);
299 bool CSPDirectiveList::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
301 if (url.protocolIsAbout())
304 // 'frame-src' is the only directive which overrides something other than the default sources.
305 // It overrides 'child-src', which overrides the default sources. So, we do this nested set
306 // of calls to 'operativeDirective()' to grab 'frame-src' if it exists, 'child-src' if it
307 // doesn't, and 'defaut-src' if neither are available.
309 // All of this only applies, of course, if we're in CSP 1.1. In CSP 1.0, 'frame-src'
310 // overrides 'default-src' directly.
311 SourceListDirective* whichDirective = m_policy->experimentalFeaturesEnabled() ?
312 operativeDirective(m_frameSrc.get(), operativeDirective(m_childSrc.get())) :
313 operativeDirective(m_frameSrc.get());
315 return reportingStatus == ContentSecurityPolicy::SendReport ?
316 checkSourceAndReportViolation(whichDirective, url, ContentSecurityPolicy::FrameSrc) :
317 checkSource(whichDirective, url);
320 bool CSPDirectiveList::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
322 return reportingStatus == ContentSecurityPolicy::SendReport ?
323 checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, ContentSecurityPolicy::ImgSrc) :
324 checkSource(operativeDirective(m_imgSrc.get()), url);
327 bool CSPDirectiveList::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
329 return reportingStatus == ContentSecurityPolicy::SendReport ?
330 checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, ContentSecurityPolicy::StyleSrc) :
331 checkSource(operativeDirective(m_styleSrc.get()), url);
334 bool CSPDirectiveList::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
336 return reportingStatus == ContentSecurityPolicy::SendReport ?
337 checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, ContentSecurityPolicy::FontSrc) :
338 checkSource(operativeDirective(m_fontSrc.get()), url);
341 bool CSPDirectiveList::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
343 return reportingStatus == ContentSecurityPolicy::SendReport ?
344 checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, ContentSecurityPolicy::MediaSrc) :
345 checkSource(operativeDirective(m_mediaSrc.get()), url);
348 bool CSPDirectiveList::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
350 return reportingStatus == ContentSecurityPolicy::SendReport ?
351 checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, ContentSecurityPolicy::ConnectSrc) :
352 checkSource(operativeDirective(m_connectSrc.get()), url);
355 bool CSPDirectiveList::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
357 return reportingStatus == ContentSecurityPolicy::SendReport ?
358 checkSourceAndReportViolation(m_formAction.get(), url, ContentSecurityPolicy::FormAction) :
359 checkSource(m_formAction.get(), url);
362 bool CSPDirectiveList::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
364 return reportingStatus == ContentSecurityPolicy::SendReport ?
365 checkSourceAndReportViolation(m_baseURI.get(), url, ContentSecurityPolicy::BaseURI) :
366 checkSource(m_baseURI.get(), url);
369 bool CSPDirectiveList::allowAncestors(LocalFrame* frame, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
371 return reportingStatus == ContentSecurityPolicy::SendReport ?
372 checkAncestorsAndReportViolation(m_frameAncestors.get(), frame, url) :
373 checkAncestors(m_frameAncestors.get(), frame);
376 bool CSPDirectiveList::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
378 return reportingStatus == ContentSecurityPolicy::SendReport ?
379 checkSourceAndReportViolation(operativeDirective(m_childSrc.get()), url, ContentSecurityPolicy::ChildSrc) :
380 checkSource(operativeDirective(m_childSrc.get()), url);
383 bool CSPDirectiveList::allowScriptNonce(const String& nonce) const
385 return checkNonce(operativeDirective(m_scriptSrc.get()), nonce);
388 bool CSPDirectiveList::allowStyleNonce(const String& nonce) const
390 return checkNonce(operativeDirective(m_styleSrc.get()), nonce);
393 bool CSPDirectiveList::allowScriptHash(const CSPHashValue& hashValue) const
395 return checkHash(operativeDirective(m_scriptSrc.get()), hashValue);
398 bool CSPDirectiveList::allowStyleHash(const CSPHashValue& hashValue) const
400 return checkHash(operativeDirective(m_styleSrc.get()), hashValue);
403 // policy = directive-list
404 // directive-list = [ directive *( ";" [ directive ] ) ]
406 void CSPDirectiveList::parse(const UChar* begin, const UChar* end)
408 m_header = String(begin, end - begin);
413 const UChar* position = begin;
414 while (position < end) {
415 const UChar* directiveBegin = position;
416 skipUntil<UChar>(position, end, ';');
419 if (parseDirective(directiveBegin, position, name, value)) {
420 ASSERT(!name.isEmpty());
421 addDirective(name, value);
424 ASSERT(position == end || *position == ';');
425 skipExactly<UChar>(position, end, ';');
429 // directive = *WSP [ directive-name [ WSP directive-value ] ]
430 // directive-name = 1*( ALPHA / DIGIT / "-" )
431 // directive-value = *( WSP / <VCHAR except ";"> )
433 bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, String& name, String& value)
435 ASSERT(name.isEmpty());
436 ASSERT(value.isEmpty());
438 const UChar* position = begin;
439 skipWhile<UChar, isASCIISpace>(position, end);
441 // Empty directive (e.g. ";;;"). Exit early.
445 const UChar* nameBegin = position;
446 skipWhile<UChar, isCSPDirectiveNameCharacter>(position, end);
448 // The directive-name must be non-empty.
449 if (nameBegin == position) {
450 skipWhile<UChar, isNotASCIISpace>(position, end);
451 m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
455 name = String(nameBegin, position - nameBegin);
460 if (!skipExactly<UChar, isASCIISpace>(position, end)) {
461 skipWhile<UChar, isNotASCIISpace>(position, end);
462 m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
466 skipWhile<UChar, isASCIISpace>(position, end);
468 const UChar* valueBegin = position;
469 skipWhile<UChar, isCSPDirectiveValueCharacter>(position, end);
471 if (position != end) {
472 m_policy->reportInvalidDirectiveValueCharacter(name, String(valueBegin, end - valueBegin));
476 // The directive-value may be empty.
477 if (valueBegin == position)
480 value = String(valueBegin, position - valueBegin);
484 void CSPDirectiveList::parseReportURI(const String& name, const String& value)
486 if (!m_reportEndpoints.isEmpty()) {
487 m_policy->reportDuplicateDirective(name);
491 Vector<UChar> characters;
492 value.appendTo(characters);
494 const UChar* position = characters.data();
495 const UChar* end = position + characters.size();
497 while (position < end) {
498 skipWhile<UChar, isASCIISpace>(position, end);
500 const UChar* urlBegin = position;
501 skipWhile<UChar, isNotASCIISpace>(position, end);
503 if (urlBegin < position) {
504 String url = String(urlBegin, position - urlBegin);
505 m_reportEndpoints.append(url);
511 template<class CSPDirectiveType>
512 void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>& directive)
515 m_policy->reportDuplicateDirective(name);
518 directive = adoptPtr(new CSPDirectiveType(name, value, m_policy));
521 void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sandboxPolicy)
524 m_policy->reportInvalidInReportOnly(name);
527 if (m_haveSandboxPolicy) {
528 m_policy->reportDuplicateDirective(name);
531 m_haveSandboxPolicy = true;
532 String invalidTokens;
533 m_policy->enforceSandboxFlags(parseSandboxPolicy(sandboxPolicy, invalidTokens));
534 if (!invalidTokens.isNull())
535 m_policy->reportInvalidSandboxFlags(invalidTokens);
538 void CSPDirectiveList::parseReflectedXSS(const String& name, const String& value)
540 if (m_reflectedXSSDisposition != ReflectedXSSUnset) {
541 m_policy->reportDuplicateDirective(name);
542 m_reflectedXSSDisposition = ReflectedXSSInvalid;
546 if (value.isEmpty()) {
547 m_reflectedXSSDisposition = ReflectedXSSInvalid;
548 m_policy->reportInvalidReflectedXSS(value);
552 Vector<UChar> characters;
553 value.appendTo(characters);
555 const UChar* position = characters.data();
556 const UChar* end = position + characters.size();
558 skipWhile<UChar, isASCIISpace>(position, end);
559 const UChar* begin = position;
560 skipWhile<UChar, isNotASCIISpace>(position, end);
564 if (equalIgnoringCase("allow", begin, position - begin)) {
565 m_reflectedXSSDisposition = AllowReflectedXSS;
566 } else if (equalIgnoringCase("filter", begin, position - begin)) {
567 m_reflectedXSSDisposition = FilterReflectedXSS;
568 } else if (equalIgnoringCase("block", begin, position - begin)) {
569 m_reflectedXSSDisposition = BlockReflectedXSS;
571 m_reflectedXSSDisposition = ReflectedXSSInvalid;
572 m_policy->reportInvalidReflectedXSS(value);
576 skipWhile<UChar, isASCIISpace>(position, end);
577 if (position == end && m_reflectedXSSDisposition != ReflectedXSSUnset)
582 m_reflectedXSSDisposition = ReflectedXSSInvalid;
583 m_policy->reportInvalidReflectedXSS(value);
586 void CSPDirectiveList::parseReferrer(const String& name, const String& value)
588 if (m_didSetReferrerPolicy) {
589 m_policy->reportDuplicateDirective(name);
590 m_referrerPolicy = ReferrerPolicyNever;
594 m_didSetReferrerPolicy = true;
596 if (value.isEmpty()) {
597 m_policy->reportInvalidReferrer(value);
598 m_referrerPolicy = ReferrerPolicyNever;
602 Vector<UChar> characters;
603 value.appendTo(characters);
605 const UChar* position = characters.data();
606 const UChar* end = position + characters.size();
608 skipWhile<UChar, isASCIISpace>(position, end);
609 const UChar* begin = position;
610 skipWhile<UChar, isNotASCIISpace>(position, end);
614 if (equalIgnoringCase("always", begin, position - begin)) {
615 m_referrerPolicy = ReferrerPolicyAlways;
616 } else if (equalIgnoringCase("default", begin, position - begin)) {
617 m_referrerPolicy = ReferrerPolicyDefault;
618 } else if (equalIgnoringCase("never", begin, position - begin)) {
619 m_referrerPolicy = ReferrerPolicyNever;
620 } else if (equalIgnoringCase("origin", begin, position - begin)) {
621 m_referrerPolicy = ReferrerPolicyOrigin;
623 m_referrerPolicy = ReferrerPolicyNever;
624 m_policy->reportInvalidReferrer(value);
628 skipWhile<UChar, isASCIISpace>(position, end);
634 m_referrerPolicy = ReferrerPolicyNever;
635 m_policy->reportInvalidReferrer(value);
639 void CSPDirectiveList::addDirective(const String& name, const String& value)
641 ASSERT(!name.isEmpty());
643 if (equalIgnoringCase(name, ContentSecurityPolicy::DefaultSrc)) {
644 setCSPDirective<SourceListDirective>(name, value, m_defaultSrc);
645 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ScriptSrc)) {
646 setCSPDirective<SourceListDirective>(name, value, m_scriptSrc);
647 m_policy->usesScriptHashAlgorithms(m_scriptSrc->hashAlgorithmsUsed());
648 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ObjectSrc)) {
649 setCSPDirective<SourceListDirective>(name, value, m_objectSrc);
650 } else if (equalIgnoringCase(name, ContentSecurityPolicy::FrameAncestors)) {
651 setCSPDirective<SourceListDirective>(name, value, m_frameAncestors);
652 } else if (equalIgnoringCase(name, ContentSecurityPolicy::FrameSrc)) {
653 setCSPDirective<SourceListDirective>(name, value, m_frameSrc);
654 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ImgSrc)) {
655 setCSPDirective<SourceListDirective>(name, value, m_imgSrc);
656 } else if (equalIgnoringCase(name, ContentSecurityPolicy::StyleSrc)) {
657 setCSPDirective<SourceListDirective>(name, value, m_styleSrc);
658 m_policy->usesStyleHashAlgorithms(m_styleSrc->hashAlgorithmsUsed());
659 } else if (equalIgnoringCase(name, ContentSecurityPolicy::FontSrc)) {
660 setCSPDirective<SourceListDirective>(name, value, m_fontSrc);
661 } else if (equalIgnoringCase(name, ContentSecurityPolicy::MediaSrc)) {
662 setCSPDirective<SourceListDirective>(name, value, m_mediaSrc);
663 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ConnectSrc)) {
664 setCSPDirective<SourceListDirective>(name, value, m_connectSrc);
665 } else if (equalIgnoringCase(name, ContentSecurityPolicy::Sandbox)) {
666 applySandboxPolicy(name, value);
667 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ReportURI)) {
668 parseReportURI(name, value);
669 } else if (m_policy->experimentalFeaturesEnabled()) {
670 if (equalIgnoringCase(name, ContentSecurityPolicy::BaseURI))
671 setCSPDirective<SourceListDirective>(name, value, m_baseURI);
672 else if (equalIgnoringCase(name, ContentSecurityPolicy::ChildSrc))
673 setCSPDirective<SourceListDirective>(name, value, m_childSrc);
674 else if (equalIgnoringCase(name, ContentSecurityPolicy::FormAction))
675 setCSPDirective<SourceListDirective>(name, value, m_formAction);
676 else if (equalIgnoringCase(name, ContentSecurityPolicy::PluginTypes))
677 setCSPDirective<MediaListDirective>(name, value, m_pluginTypes);
678 else if (equalIgnoringCase(name, ContentSecurityPolicy::ReflectedXSS))
679 parseReflectedXSS(name, value);
680 else if (equalIgnoringCase(name, ContentSecurityPolicy::Referrer))
681 parseReferrer(name, value);
683 m_policy->reportUnsupportedDirective(name);
685 m_policy->reportUnsupportedDirective(name);