Merge "WebProcess crash is occured during changing default directory path for file...
[framework/web/webkit-efl.git] / Source / WebCore / page / ContentSecurityPolicy.cpp
1 /*
2  * Copyright (C) 2011 Google, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ContentSecurityPolicy.h"
28
29 #include "Console.h"
30 #include "DOMStringList.h"
31 #include "Document.h"
32 #include "FormData.h"
33 #include "FormDataList.h"
34 #include "Frame.h"
35 #include "InspectorInstrumentation.h"
36 #include "InspectorValues.h"
37 #include "KURL.h"
38 #include "PingLoader.h"
39 #include "SchemeRegistry.h"
40 #include "ScriptCallStack.h"
41 #include "SecurityOrigin.h"
42 #include "TextEncoding.h"
43 #include <wtf/text/TextPosition.h>
44 #include <wtf/text/WTFString.h>
45
46 namespace WebCore {
47
48 // Normally WebKit uses "static" for internal linkage, but using "static" for
49 // these functions causes a compile error because these functions are used as
50 // template parameters.
51 namespace {
52
53 bool isDirectiveNameCharacter(UChar c)
54 {
55     return isASCIIAlphanumeric(c) || c == '-';
56 }
57
58 bool isDirectiveValueCharacter(UChar c)
59 {
60     return isASCIISpace(c) || (c >= 0x21 && c <= 0x7e); // Whitespace + VCHAR
61 }
62
63 bool isSourceCharacter(UChar c)
64 {
65     return !isASCIISpace(c);
66 }
67
68 bool isHostCharacter(UChar c)
69 {
70     return isASCIIAlphanumeric(c) || c == '-';
71 }
72
73 bool isSchemeContinuationCharacter(UChar c)
74 {
75     return isASCIIAlphanumeric(c) || c == '+' || c == '-' || c == '.';
76 }
77
78 bool isNotASCIISpace(UChar c)
79 {
80     return !isASCIISpace(c);
81 }
82
83 bool isNotColonOrSlash(UChar c)
84 {
85     return c != ':' && c != '/';
86 }
87
88 } // namespace
89
90 static bool skipExactly(const UChar*& position, const UChar* end, UChar delimiter)
91 {
92     if (position < end && *position == delimiter) {
93         ++position;
94         return true;
95     }
96     return false;
97 }
98
99 template<bool characterPredicate(UChar)>
100 static bool skipExactly(const UChar*& position, const UChar* end)
101 {
102     if (position < end && characterPredicate(*position)) {
103         ++position;
104         return true;
105     }
106     return false;
107 }
108
109 static void skipUntil(const UChar*& position, const UChar* end, UChar delimiter)
110 {
111     while (position < end && *position != delimiter)
112         ++position;
113 }
114
115 template<bool characterPredicate(UChar)>
116 static void skipWhile(const UChar*& position, const UChar* end)
117 {
118     while (position < end && characterPredicate(*position))
119         ++position;
120 }
121
122 class CSPSource {
123 public:
124     CSPSource(const String& scheme, const String& host, int port, bool hostHasWildcard, bool portHasWildcard)
125         : m_scheme(scheme)
126         , m_host(host)
127         , m_port(port)
128         , m_hostHasWildcard(hostHasWildcard)
129         , m_portHasWildcard(portHasWildcard)
130     {
131     }
132
133     bool matches(const KURL& url) const
134     {
135         if (!schemeMatches(url))
136             return false;
137         if (isSchemeOnly())
138             return true;
139         return hostMatches(url) && portMatches(url);
140     }
141
142 private:
143     bool schemeMatches(const KURL& url) const
144     {
145         return equalIgnoringCase(url.protocol(), m_scheme);
146     }
147
148     bool hostMatches(const KURL& url) const
149     {
150         const String& host = url.host();
151         if (equalIgnoringCase(host, m_host))
152             return true;
153         return m_hostHasWildcard && host.endsWith("." + m_host, false);
154
155     }
156
157     bool portMatches(const KURL& url) const
158     {
159         if (m_portHasWildcard)
160             return true;
161
162         int port = url.port();
163
164         if (port == m_port)
165             return true;
166
167         if (!port)
168             return isDefaultPortForProtocol(m_port, m_scheme);
169
170         if (!m_port)
171             return isDefaultPortForProtocol(port, m_scheme);
172
173         return false;
174     }
175
176     bool isSchemeOnly() const { return m_host.isEmpty(); }
177
178     String m_scheme;
179     String m_host;
180     int m_port;
181
182     bool m_hostHasWildcard;
183     bool m_portHasWildcard;
184 };
185
186 class CSPSourceList {
187 public:
188     CSPSourceList(ContentSecurityPolicy*, const String& directiveName);
189
190     void parse(const String&);
191     bool matches(const KURL&);
192     bool allowInline() const { return m_allowInline; }
193     bool allowEval() const { return m_allowEval; }
194
195 private:
196     void parse(const UChar* begin, const UChar* end);
197
198     bool parseSource(const UChar* begin, const UChar* end, String& scheme, String& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard);
199     bool parseScheme(const UChar* begin, const UChar* end, String& scheme);
200     bool parseHost(const UChar* begin, const UChar* end, String& host, bool& hostHasWildcard);
201     bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHasWildcard);
202     bool parsePath(const UChar* begin, const UChar* end, String& path);
203
204     void addSourceSelf();
205     void addSourceStar();
206     void addSourceUnsafeInline();
207     void addSourceUnsafeEval();
208
209     ContentSecurityPolicy* m_policy;
210     Vector<CSPSource> m_list;
211     String m_directiveName;
212     bool m_allowStar;
213     bool m_allowInline;
214     bool m_allowEval;
215 };
216
217 CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& directiveName)
218     : m_policy(policy)
219     , m_directiveName(directiveName)
220     , m_allowStar(false)
221     , m_allowInline(false)
222     , m_allowEval(false)
223 {
224 }
225
226 void CSPSourceList::parse(const String& value)
227 {
228     parse(value.characters(), value.characters() + value.length());
229 }
230
231 bool CSPSourceList::matches(const KURL& url)
232 {
233     if (m_allowStar)
234         return true;
235
236     for (size_t i = 0; i < m_list.size(); ++i) {
237         if (m_list[i].matches(url))
238             return true;
239     }
240
241     return false;
242 }
243
244 // source-list       = *WSP [ source *( 1*WSP source ) *WSP ]
245 //                   / *WSP "'none'" *WSP
246 //
247 void CSPSourceList::parse(const UChar* begin, const UChar* end)
248 {
249     const UChar* position = begin;
250
251     bool isFirstSourceInList = true;
252     while (position < end) {
253         skipWhile<isASCIISpace>(position, end);
254         const UChar* beginSource = position;
255         skipWhile<isSourceCharacter>(position, end);
256
257         if (isFirstSourceInList && equalIgnoringCase("'none'", beginSource, position - beginSource))
258             return; // We represent 'none' as an empty m_list.
259         isFirstSourceInList = false;
260
261         String scheme, host, path;
262         int port = 0;
263         bool hostHasWildcard = false;
264         bool portHasWildcard = false;
265
266         if (parseSource(beginSource, position, scheme, host, port, path, hostHasWildcard, portHasWildcard)) {
267             if (scheme.isEmpty())
268                 scheme = m_policy->securityOrigin()->protocol();
269             if (!path.isEmpty())
270                 m_policy->reportIgnoredPathComponent(m_directiveName, String(beginSource, position - beginSource), path);
271             m_list.append(CSPSource(scheme, host, port, hostHasWildcard, portHasWildcard));
272         }
273
274         ASSERT(position == end || isASCIISpace(*position));
275      }
276 }
277
278 // source            = scheme ":"
279 //                   / ( [ scheme "://" ] host [ port ] [ path ] )
280 //                   / "'self'"
281 //
282 bool CSPSourceList::parseSource(const UChar* begin, const UChar* end,
283                                 String& scheme, String& host, int& port, String& path,
284                                 bool& hostHasWildcard, bool& portHasWildcard)
285 {
286     if (begin == end)
287         return false;
288
289     if (end - begin == 1 && *begin == '*') {
290         addSourceStar();
291         return false;
292     }
293
294     if (equalIgnoringCase("'self'", begin, end - begin)) {
295         addSourceSelf();
296         return false;
297     }
298
299     if (equalIgnoringCase("'unsafe-inline'", begin, end - begin)) {
300         addSourceUnsafeInline();
301         return false;
302     }
303
304     if (equalIgnoringCase("'unsafe-eval'", begin, end - begin)) {
305         addSourceUnsafeEval();
306         return false;
307     }
308
309     const UChar* position = begin;
310     const UChar* beginHost = begin;
311     const UChar* beginPath = end;
312     const UChar* beginPort = 0;
313
314     skipWhile<isNotColonOrSlash>(position, end);
315
316     if (position == end) {
317         // host
318         //     ^
319         return parseHost(beginHost, position, host, hostHasWildcard);
320     }
321
322     if (position < end && *position == '/') {
323         // host/path || host/ || /
324         //     ^            ^    ^
325         if (!parseHost(beginHost, position, host, hostHasWildcard)
326             || !parsePath(position, end, path)
327             || position != end)
328             return false;
329         return true;
330     }
331
332     if (position < end && *position == ':') {
333         if (end - position == 1) {
334             // scheme:
335             //       ^
336             return parseScheme(begin, position, scheme);
337         }
338
339         if (position[1] == '/') {
340             // scheme://host || scheme://
341             //       ^                ^
342             if (!parseScheme(begin, position, scheme)
343                 || !skipExactly(position, end, ':')
344                 || !skipExactly(position, end, '/')
345                 || !skipExactly(position, end, '/'))
346                 return false;
347             if (position == end)
348                 return true;
349             beginHost = position;
350             skipWhile<isNotColonOrSlash>(position, end);
351         }
352
353         if (position < end && *position == ':') {
354             // host:port || scheme://host:port
355             //     ^                     ^
356             beginPort = position;
357             skipUntil(position, end, '/');
358         }
359     }
360
361     if (position < end && *position == '/') {
362         // scheme://host/path || scheme://host:port/path
363         //              ^                          ^
364         if (position == beginHost)
365             return false;
366
367         beginPath = position;
368     }
369
370     if (!parseHost(beginHost, beginPort ? beginPort : beginPath, host, hostHasWildcard))
371         return false;
372
373     if (beginPort) {
374         if (!parsePort(beginPort, beginPath, port, portHasWildcard))
375             return false;
376     } else {
377         port = 0;
378     }
379
380     if (beginPath != end) {
381         if (!parsePath(beginPath, end, path))
382             return false;
383     }
384
385     return true;
386 }
387
388 //                     ; <scheme> production from RFC 3986
389 // scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
390 //
391 bool CSPSourceList::parseScheme(const UChar* begin, const UChar* end, String& scheme)
392 {
393     ASSERT(begin <= end);
394     ASSERT(scheme.isEmpty());
395
396     if (begin == end)
397         return false;
398
399     const UChar* position = begin;
400
401     if (!skipExactly<isASCIIAlpha>(position, end))
402         return false;
403
404     skipWhile<isSchemeContinuationCharacter>(position, end);
405
406     if (position != end)
407         return false;
408
409     scheme = String(begin, end - begin);
410     return true;
411 }
412
413 // host              = [ "*." ] 1*host-char *( "." 1*host-char )
414 //                   / "*"
415 // host-char         = ALPHA / DIGIT / "-"
416 //
417 bool CSPSourceList::parseHost(const UChar* begin, const UChar* end, String& host, bool& hostHasWildcard)
418 {
419     ASSERT(begin <= end);
420     ASSERT(host.isEmpty());
421     ASSERT(!hostHasWildcard);
422
423     if (begin == end)
424         return false;
425
426     const UChar* position = begin;
427
428     if (skipExactly(position, end, '*')) {
429         hostHasWildcard = true;
430
431         if (position == end)
432             return true;
433
434         if (!skipExactly(position, end, '.'))
435             return false;
436     }
437
438     const UChar* hostBegin = position;
439
440     while (position < end) {
441         if (!skipExactly<isHostCharacter>(position, end))
442             return false;
443
444         skipWhile<isHostCharacter>(position, end);
445
446         if (position < end && !skipExactly(position, end, '.'))
447             return false;
448     }
449
450     ASSERT(position == end);
451     host = String(hostBegin, end - hostBegin);
452     return true;
453 }
454
455 // FIXME: Deal with an actual path. This just sucks up everything to the end of the string.
456 bool CSPSourceList::parsePath(const UChar* begin, const UChar* end, String& path)
457 {
458     ASSERT(begin <= end);
459     ASSERT(path.isEmpty());
460
461     if (begin == end)
462         return false;
463
464     path = String(begin, end - begin);
465     return true;
466 }
467
468 // port              = ":" ( 1*DIGIT / "*" )
469 //
470 bool CSPSourceList::parsePort(const UChar* begin, const UChar* end, int& port, bool& portHasWildcard)
471 {
472     ASSERT(begin <= end);
473     ASSERT(!port);
474     ASSERT(!portHasWildcard);
475
476     if (!skipExactly(begin, end, ':'))
477         ASSERT_NOT_REACHED();
478
479     if (begin == end)
480         return false;
481
482     if (end - begin == 1 && *begin == '*') {
483         port = 0;
484         portHasWildcard = true;
485         return true;
486     }
487
488     const UChar* position = begin;
489     skipWhile<isASCIIDigit>(position, end);
490
491     if (position != end)
492         return false;
493
494     bool ok;
495     port = charactersToIntStrict(begin, end - begin, &ok);
496     return ok;
497 }
498
499 void CSPSourceList::addSourceSelf()
500 {
501     m_list.append(CSPSource(m_policy->securityOrigin()->protocol(), m_policy->securityOrigin()->host(), m_policy->securityOrigin()->port(), false, false));
502 }
503
504 void CSPSourceList::addSourceStar()
505 {
506     m_allowStar = true;
507 }
508
509 void CSPSourceList::addSourceUnsafeInline()
510 {
511     m_allowInline = true;
512 }
513
514 void CSPSourceList::addSourceUnsafeEval()
515 {
516     m_allowEval = true;
517 }
518
519 class CSPDirective {
520 public:
521     CSPDirective(const String& name, const String& value, ContentSecurityPolicy* policy)
522         : m_sourceList(policy, name)
523         , m_text(name + ' ' + value)
524         , m_selfURL(policy->url())
525     {
526         m_sourceList.parse(value);
527     }
528
529     bool allows(const KURL& url)
530     {
531         return m_sourceList.matches(url.isEmpty() ? m_selfURL : url);
532     }
533
534     bool allowInline() const { return m_sourceList.allowInline(); }
535     bool allowEval() const { return m_sourceList.allowEval(); }
536
537     const String& text() { return m_text; }
538
539 private:
540     CSPSourceList m_sourceList;
541     String m_text;
542     KURL m_selfURL;
543 };
544
545 class CSPDirectiveList {
546 public:
547     static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const String&, ContentSecurityPolicy::HeaderType);
548
549     const String& header() const { return m_header; }
550     ContentSecurityPolicy::HeaderType headerType() const { return m_reportOnly ? ContentSecurityPolicy::ReportOnly : ContentSecurityPolicy::EnforcePolicy; }
551
552     bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
553     bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
554     bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
555     bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
556     bool allowEval(PassRefPtr<ScriptCallStack>, ContentSecurityPolicy::ReportingStatus) const;
557     bool allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL&) const;
558
559     bool allowScriptFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
560     bool allowObjectFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
561     bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
562     bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
563     bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
564     bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
565     bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
566     bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
567
568     void gatherReportURIs(DOMStringList&) const;
569
570 private:
571     explicit CSPDirectiveList(ContentSecurityPolicy*);
572
573     void parse(const String&);
574
575     bool parseDirective(const UChar* begin, const UChar* end, String& name, String& value);
576     void parseReportURI(const String& name, const String& value);
577     void parseScriptNonce(const String& name, const String& value);
578     void addDirective(const String& name, const String& value);
579     void applySandboxPolicy(const String& name, const String& sandboxPolicy);
580
581     void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirective>&);
582
583     CSPDirective* operativeDirective(CSPDirective*) const;
584     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;
585
586     bool checkEval(CSPDirective*) const;
587     bool checkInline(CSPDirective*) const;
588     bool checkNonce(const String&) const;
589     bool checkSource(CSPDirective*, const KURL&) const;
590
591     bool checkEvalAndReportViolation(CSPDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
592     bool checkInlineAndReportViolation(CSPDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
593     bool checkNonceAndReportViolation(const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
594     bool checkSourceAndReportViolation(CSPDirective*, const KURL&, const String& type) const;
595
596     bool denyIfEnforcingPolicy() const { return m_reportOnly; }
597
598     ContentSecurityPolicy* m_policy;
599     String m_header;
600
601     bool m_reportOnly;
602     bool m_haveSandboxPolicy;
603
604     OwnPtr<CSPDirective> m_defaultSrc;
605     OwnPtr<CSPDirective> m_scriptSrc;
606     OwnPtr<CSPDirective> m_objectSrc;
607     OwnPtr<CSPDirective> m_frameSrc;
608     OwnPtr<CSPDirective> m_imgSrc;
609     OwnPtr<CSPDirective> m_styleSrc;
610     OwnPtr<CSPDirective> m_fontSrc;
611     OwnPtr<CSPDirective> m_mediaSrc;
612     OwnPtr<CSPDirective> m_connectSrc;
613
614     Vector<KURL> m_reportURIs;
615     String m_scriptNonce;
616 };
617
618 CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy)
619     : m_policy(policy)
620     , m_reportOnly(false)
621     , m_haveSandboxPolicy(false)
622 {
623 }
624
625 PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* policy, const String& header, ContentSecurityPolicy::HeaderType type)
626 {
627     OwnPtr<CSPDirectiveList> directives = adoptPtr(new CSPDirectiveList(policy));
628     directives->parse(header);
629     directives->m_header = header;
630
631     switch (type) {
632     case ContentSecurityPolicy::ReportOnly:
633         directives->m_reportOnly = true;
634         return directives.release();
635     case ContentSecurityPolicy::EnforcePolicy:
636         ASSERT(!directives->m_reportOnly);
637         break;
638     }
639
640     return directives.release();
641 }
642
643 void CSPDirectiveList::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
644 {
645     String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
646     m_policy->reportViolation(directiveText, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine, callStack);
647 }
648
649 bool CSPDirectiveList::checkEval(CSPDirective* directive) const
650 {
651     return !directive || directive->allowEval();
652 }
653
654 bool CSPDirectiveList::checkInline(CSPDirective* directive) const
655 {
656     return !directive || directive->allowInline();
657 }
658
659 bool CSPDirectiveList::checkNonce(const String& nonce) const
660 {
661     return (m_scriptNonce.isNull()
662             || (!m_scriptNonce.isEmpty()
663                 && nonce.stripWhiteSpace() == m_scriptNonce));
664 }
665
666 bool CSPDirectiveList::checkSource(CSPDirective* directive, const KURL& url) const
667 {
668     return !directive || directive->allows(url);
669 }
670
671 CSPDirective* CSPDirectiveList::operativeDirective(CSPDirective* directive) const
672 {
673     return directive ? directive : m_defaultSrc.get();
674 }
675
676 bool CSPDirectiveList::checkEvalAndReportViolation(CSPDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
677 {
678     if (checkEval(directive))
679         return true;
680     reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine, callStack);
681     return denyIfEnforcingPolicy();
682 }
683
684 bool CSPDirectiveList::checkNonceAndReportViolation(const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
685 {
686     if (checkNonce(nonce))
687         return true;
688     reportViolation(m_scriptNonce, consoleMessage + "\"script-nonce " + m_scriptNonce + "\".\n", KURL(), contextURL, contextLine);
689     return denyIfEnforcingPolicy();
690 }
691
692 bool CSPDirectiveList::checkInlineAndReportViolation(CSPDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
693 {
694     if (checkInline(directive))
695         return true;
696     reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine);
697     return denyIfEnforcingPolicy();
698 }
699
700 bool CSPDirectiveList::checkSourceAndReportViolation(CSPDirective* directive, const KURL& url, const String& type) const
701 {
702     if (checkSource(directive, url))
703         return true;
704     String verb = type == "connect" ? "connect to" : "load the";
705     reportViolation(directive->text(), "Refused to " + verb + " " + type + " '" + url.string() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\".\n", url);
706     return denyIfEnforcingPolicy();
707 }
708
709 bool CSPDirectiveList::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
710 {
711     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "));
712     if (reportingStatus == ContentSecurityPolicy::SendReport) {
713         return (checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine)
714                 && checkNonceAndReportViolation(String(), consoleMessage, contextURL, contextLine));
715     } else {
716         return (checkInline(operativeDirective(m_scriptSrc.get()))
717                 && checkNonce(String()));
718     }
719 }
720
721 bool CSPDirectiveList::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
722 {
723     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline event handler because it violates the following Content Security Policy directive: "));
724     if (reportingStatus == ContentSecurityPolicy::SendReport) {
725         return (checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine)
726                 && checkNonceAndReportViolation(String(), consoleMessage, contextURL, contextLine));
727     } else {
728         return (checkInline(operativeDirective(m_scriptSrc.get()))
729                 && checkNonce(String()));
730     }
731 }
732
733 bool CSPDirectiveList::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
734 {
735     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline script because it violates the following Content Security Policy directive: "));
736     return reportingStatus == ContentSecurityPolicy::SendReport ?
737         checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine) :
738         checkInline(operativeDirective(m_scriptSrc.get()));
739 }
740
741 bool CSPDirectiveList::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
742 {
743     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to apply inline style because it violates the following Content Security Policy directive: "));
744     return reportingStatus == ContentSecurityPolicy::SendReport ?
745         checkInlineAndReportViolation(operativeDirective(m_styleSrc.get()), consoleMessage, contextURL, contextLine) :
746         checkInline(operativeDirective(m_styleSrc.get()));
747 }
748
749 bool CSPDirectiveList::allowEval(PassRefPtr<ScriptCallStack> callStack, ContentSecurityPolicy::ReportingStatus reportingStatus) const
750 {
751     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to evaluate script because it violates the following Content Security Policy directive: "));
752     return reportingStatus == ContentSecurityPolicy::SendReport ?
753         checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, String(), WTF::OrdinalNumber::beforeFirst(), callStack) :
754         checkEval(operativeDirective(m_scriptSrc.get()));
755 }
756
757 bool CSPDirectiveList::allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL& url) const
758 {
759     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute script because it violates the following Content Security Policy directive: "));
760     if (url.isEmpty())
761         return checkNonceAndReportViolation(nonce, consoleMessage, contextURL, contextLine);
762     return checkNonceAndReportViolation(nonce, "Refused to load '" + url.string() + "' because it violates the following Content Security Policy directive: ", contextURL, contextLine);
763 }
764
765 bool CSPDirectiveList::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
766 {
767     DEFINE_STATIC_LOCAL(String, type, ("script"));
768     return reportingStatus == ContentSecurityPolicy::SendReport ?
769         checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, type) :
770         checkSource(operativeDirective(m_scriptSrc.get()), url);
771 }
772
773 bool CSPDirectiveList::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
774 {
775     DEFINE_STATIC_LOCAL(String, type, ("object"));
776     if (url.isBlankURL())
777         return true;
778     return reportingStatus == ContentSecurityPolicy::SendReport ?
779         checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, type) :
780         checkSource(operativeDirective(m_objectSrc.get()), url);
781 }
782
783 bool CSPDirectiveList::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
784 {
785     DEFINE_STATIC_LOCAL(String, type, ("frame"));
786     if (url.isBlankURL())
787         return true;
788     return reportingStatus == ContentSecurityPolicy::SendReport ?
789         checkSourceAndReportViolation(operativeDirective(m_frameSrc.get()), url, type) :
790         checkSource(operativeDirective(m_frameSrc.get()), url);
791 }
792
793 bool CSPDirectiveList::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
794 {
795     DEFINE_STATIC_LOCAL(String, type, ("image"));
796     return reportingStatus == ContentSecurityPolicy::SendReport ?
797         checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, type) :
798         checkSource(operativeDirective(m_imgSrc.get()), url);
799 }
800
801 bool CSPDirectiveList::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
802 {
803     DEFINE_STATIC_LOCAL(String, type, ("style"));
804     return reportingStatus == ContentSecurityPolicy::SendReport ?
805         checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, type) :
806         checkSource(operativeDirective(m_styleSrc.get()), url);
807 }
808
809 bool CSPDirectiveList::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
810 {
811     DEFINE_STATIC_LOCAL(String, type, ("font"));
812     return reportingStatus == ContentSecurityPolicy::SendReport ?
813         checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, type) :
814         checkSource(operativeDirective(m_fontSrc.get()), url);
815 }
816
817 bool CSPDirectiveList::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
818 {
819     DEFINE_STATIC_LOCAL(String, type, ("media"));
820     return reportingStatus == ContentSecurityPolicy::SendReport ?
821         checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, type) :
822         checkSource(operativeDirective(m_mediaSrc.get()), url);
823 }
824
825 bool CSPDirectiveList::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
826 {
827     DEFINE_STATIC_LOCAL(String, type, ("connect"));
828     return reportingStatus == ContentSecurityPolicy::SendReport ?
829         checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, type) :
830         checkSource(operativeDirective(m_connectSrc.get()), url);
831 }
832
833 void CSPDirectiveList::gatherReportURIs(DOMStringList& list) const
834 {
835     for (size_t i = 0; i < m_reportURIs.size(); ++i)
836         list.append(m_reportURIs[i].string());
837 }
838
839 // policy            = directive-list
840 // directive-list    = [ directive *( ";" [ directive ] ) ]
841 //
842 void CSPDirectiveList::parse(const String& policy)
843 {
844     if (policy.isEmpty())
845         return;
846
847     const UChar* position = policy.characters();
848     const UChar* end = position + policy.length();
849
850     while (position < end) {
851         const UChar* directiveBegin = position;
852         skipUntil(position, end, ';');
853
854         String name, value;
855         if (parseDirective(directiveBegin, position, name, value)) {
856             ASSERT(!name.isEmpty());
857             addDirective(name, value);
858         }
859
860         ASSERT(position == end || *position == ';');
861         skipExactly(position, end, ';');
862     }
863 }
864
865 // directive         = *WSP [ directive-name [ WSP directive-value ] ]
866 // directive-name    = 1*( ALPHA / DIGIT / "-" )
867 // directive-value   = *( WSP / <VCHAR except ";"> )
868 //
869 bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, String& name, String& value)
870 {
871     ASSERT(name.isEmpty());
872     ASSERT(value.isEmpty());
873
874     const UChar* position = begin;
875     skipWhile<isASCIISpace>(position, end);
876
877     // Empty directive (e.g. ";;;"). Exit early.
878     if (position == end)
879         return false;
880
881     const UChar* nameBegin = position;
882     skipWhile<isDirectiveNameCharacter>(position, end);
883
884     // The directive-name must be non-empty.
885     if (nameBegin == position) {
886         skipWhile<isNotASCIISpace>(position, end);
887         m_policy->reportUnrecognizedDirective(String(nameBegin, position - nameBegin));
888         return false;
889     }
890
891     name = String(nameBegin, position - nameBegin);
892
893     if (position == end)
894         return true;
895
896     if (!skipExactly<isASCIISpace>(position, end)) {
897         skipWhile<isNotASCIISpace>(position, end);
898         m_policy->reportUnrecognizedDirective(String(nameBegin, position - nameBegin));
899         return false;
900     }
901
902     skipWhile<isASCIISpace>(position, end);
903
904     const UChar* valueBegin = position;
905     skipWhile<isDirectiveValueCharacter>(position, end);
906
907     if (position != end)
908         return false;
909
910     // The directive-value may be empty.
911     if (valueBegin == position)
912         return true;
913
914     value = String(valueBegin, position - valueBegin);
915     return true;
916 }
917
918 void CSPDirectiveList::parseReportURI(const String& name, const String& value)
919 {
920     if (!m_reportURIs.isEmpty()) {
921         m_policy->reportDuplicateDirective(name);
922         return;
923     }
924     const UChar* position = value.characters();
925     const UChar* end = position + value.length();
926
927     while (position < end) {
928         skipWhile<isASCIISpace>(position, end);
929
930         const UChar* urlBegin = position;
931         skipWhile<isNotASCIISpace>(position, end);
932
933         if (urlBegin < position) {
934             String url = String(urlBegin, position - urlBegin);
935             m_reportURIs.append(m_policy->completeURL(url));
936         }
937     }
938 }
939
940 void CSPDirectiveList::parseScriptNonce(const String& name, const String& value)
941 {
942     if (!m_scriptNonce.isNull()) {
943         m_policy->reportDuplicateDirective(name);
944         return;
945     }
946
947     String nonce;
948     const UChar* position = value.characters();
949     const UChar* end = position + value.length();
950
951     skipWhile<isASCIISpace>(position, end);
952     const UChar* nonceBegin = position;
953     if (position == end) {
954         m_policy->reportInvalidNonce(String());
955         m_scriptNonce = "";
956         return;
957     }
958     skipWhile<isNotASCIISpace>(position, end);
959     if (nonceBegin < position)
960         nonce = String(nonceBegin, position - nonceBegin);
961
962     // Trim off trailing whitespace: If we're not at the end of the string, log
963     // an error.
964     skipWhile<isASCIISpace>(position, end);
965     if (position < end) {
966         m_policy->reportInvalidNonce(value);
967         m_scriptNonce = "";
968     } else
969         m_scriptNonce = nonce;
970 }
971
972 void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirective>& directive)
973 {
974     if (directive) {
975         m_policy->reportDuplicateDirective(name);
976         return;
977     }
978     directive = adoptPtr(new CSPDirective(name, value, m_policy));
979 }
980
981 void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sandboxPolicy)
982 {
983     if (m_haveSandboxPolicy) {
984         m_policy->reportDuplicateDirective(name);
985         return;
986     }
987     m_haveSandboxPolicy = true;
988     m_policy->enforceSandboxFlags(SecurityContext::parseSandboxPolicy(sandboxPolicy));
989 }
990
991 void CSPDirectiveList::addDirective(const String& name, const String& value)
992 {
993     DEFINE_STATIC_LOCAL(String, defaultSrc, ("default-src"));
994     DEFINE_STATIC_LOCAL(String, scriptSrc, ("script-src"));
995 #if ENABLE(CSP_NEXT)
996     DEFINE_STATIC_LOCAL(String, scriptNonce, ("script-nonce"));
997 #endif
998     DEFINE_STATIC_LOCAL(String, objectSrc, ("object-src"));
999     DEFINE_STATIC_LOCAL(String, frameSrc, ("frame-src"));
1000     DEFINE_STATIC_LOCAL(String, imgSrc, ("img-src"));
1001     DEFINE_STATIC_LOCAL(String, styleSrc, ("style-src"));
1002     DEFINE_STATIC_LOCAL(String, fontSrc, ("font-src"));
1003     DEFINE_STATIC_LOCAL(String, mediaSrc, ("media-src"));
1004     DEFINE_STATIC_LOCAL(String, connectSrc, ("connect-src"));
1005     DEFINE_STATIC_LOCAL(String, sandbox, ("sandbox"));
1006     DEFINE_STATIC_LOCAL(String, reportURI, ("report-uri"));
1007
1008     ASSERT(!name.isEmpty());
1009
1010     if (equalIgnoringCase(name, defaultSrc))
1011         setCSPDirective(name, value, m_defaultSrc);
1012     else if (equalIgnoringCase(name, scriptSrc))
1013         setCSPDirective(name, value, m_scriptSrc);
1014     else if (equalIgnoringCase(name, objectSrc))
1015         setCSPDirective(name, value, m_objectSrc);
1016     else if (equalIgnoringCase(name, frameSrc))
1017         setCSPDirective(name, value, m_frameSrc);
1018     else if (equalIgnoringCase(name, imgSrc))
1019         setCSPDirective(name, value, m_imgSrc);
1020     else if (equalIgnoringCase(name, styleSrc))
1021         setCSPDirective(name, value, m_styleSrc);
1022     else if (equalIgnoringCase(name, fontSrc))
1023         setCSPDirective(name, value, m_fontSrc);
1024     else if (equalIgnoringCase(name, mediaSrc))
1025         setCSPDirective(name, value, m_mediaSrc);
1026     else if (equalIgnoringCase(name, connectSrc))
1027         setCSPDirective(name, value, m_connectSrc);
1028     else if (equalIgnoringCase(name, sandbox))
1029         applySandboxPolicy(name, value);
1030     else if (equalIgnoringCase(name, reportURI))
1031         parseReportURI(name, value);
1032 #if ENABLE(CSP_NEXT)
1033     else if (equalIgnoringCase(name, scriptNonce))
1034         parseScriptNonce(name, value);
1035 #endif
1036     else
1037         m_policy->reportUnrecognizedDirective(name);
1038 }
1039
1040 ContentSecurityPolicy::ContentSecurityPolicy(ScriptExecutionContext* scriptExecutionContext)
1041     : m_scriptExecutionContext(scriptExecutionContext)
1042     , m_overrideInlineStyleAllowed(false)
1043 {
1044 }
1045
1046 ContentSecurityPolicy::~ContentSecurityPolicy()
1047 {
1048 }
1049
1050 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other) 
1051 {
1052     ASSERT(m_policies.isEmpty());
1053     for (CSPDirectiveListVector::const_iterator iter = other->m_policies.begin(); iter != other->m_policies.end(); ++iter)
1054         didReceiveHeader((*iter)->header(), (*iter)->headerType());
1055 }
1056
1057 void ContentSecurityPolicy::didReceiveHeader(const String& header, HeaderType type)
1058 {
1059     // RFC2616, section 4.2 specifies that headers appearing multiple times can
1060     // be combined with a comma. Walk the header string, and parse each comma
1061     // separated chunk as a separate header.
1062     const UChar* begin = header.characters();
1063     const UChar* position = begin;
1064     const UChar* end = begin + header.length();
1065     while (position < end) {
1066         skipUntil(position, end, ',');
1067
1068         // header1,header2 OR header1
1069         //        ^                  ^
1070         m_policies.append(CSPDirectiveList::create(this, String(begin, position - begin), type));
1071
1072         // Skip the comma, and begin the next header from the current position.
1073         ASSERT(position == end || *position == ',');
1074         skipExactly(position, end, ',');
1075         begin = position;
1076     }
1077
1078     if (!allowEval(0, SuppressReport))
1079         m_scriptExecutionContext->disableEval();
1080 }
1081
1082 void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value)
1083 {
1084     m_overrideInlineStyleAllowed = value;
1085 }
1086
1087 const String& ContentSecurityPolicy::deprecatedHeader() const
1088 {
1089     return m_policies.isEmpty() ? emptyString() : m_policies[0]->header();
1090 }
1091
1092 ContentSecurityPolicy::HeaderType ContentSecurityPolicy::deprecatedHeaderType() const
1093 {
1094     return m_policies.isEmpty() ? EnforcePolicy : m_policies[0]->headerType();
1095 }
1096
1097 template<bool (CSPDirectiveList::*allowed)(PassRefPtr<ScriptCallStack>, ContentSecurityPolicy::ReportingStatus) const>
1098 bool isAllowedByAllWithCallStack(const CSPDirectiveListVector& policies, PassRefPtr<ScriptCallStack> callStack, ContentSecurityPolicy::ReportingStatus reportingStatus)
1099 {
1100     for (size_t i = 0; i < policies.size(); ++i) {
1101         if (!(policies[i].get()->*allowed)(callStack, reportingStatus))
1102             return false;
1103     }
1104     return true;
1105 }
1106
1107 template<bool (CSPDirectiveList::*allowed)(const String&, const WTF::OrdinalNumber&, ContentSecurityPolicy::ReportingStatus) const>
1108 bool isAllowedByAllWithContext(const CSPDirectiveListVector& policies, const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus)
1109 {
1110     for (size_t i = 0; i < policies.size(); ++i) {
1111         if (!(policies[i].get()->*allowed)(contextURL, contextLine, reportingStatus))
1112             return false;
1113     }
1114     return true;
1115 }
1116
1117 template<bool (CSPDirectiveList::*allowed)(const String&, const String&, const WTF::OrdinalNumber&, const KURL&) const>
1118 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL& url)
1119 {
1120     for (size_t i = 0; i < policies.size(); ++i) {
1121         if (!(policies[i].get()->*allowed)(nonce, contextURL, contextLine, url))
1122             return false;
1123     }
1124     return true;
1125 }
1126
1127 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPolicy::ReportingStatus) const>
1128 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus)
1129 {
1130     if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
1131         return true;
1132
1133     for (size_t i = 0; i < policies.size(); ++i) {
1134         if (!(policies[i].get()->*allowFromURL)(url, reportingStatus))
1135             return false;
1136     }
1137     return true;
1138 }
1139
1140 bool ContentSecurityPolicy::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1141 {
1142     return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(m_policies, contextURL, contextLine, reportingStatus);
1143 }
1144
1145 bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1146 {
1147     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineEventHandlers>(m_policies, contextURL, contextLine, reportingStatus);
1148 }
1149
1150 bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1151 {
1152     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
1153 }
1154
1155 bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1156 {
1157     if (m_overrideInlineStyleAllowed)
1158         return true;
1159     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
1160 }
1161
1162 bool ContentSecurityPolicy::allowEval(PassRefPtr<ScriptCallStack> callStack, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1163 {
1164     return isAllowedByAllWithCallStack<&CSPDirectiveList::allowEval>(m_policies, callStack, reportingStatus);
1165 }
1166
1167 bool ContentSecurityPolicy::allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL& url) const
1168 {
1169     return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_policies, nonce, contextURL, contextLine, url);
1170 }
1171
1172 bool ContentSecurityPolicy::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1173 {
1174     return isAllowedByAllWithURL<&CSPDirectiveList::allowScriptFromSource>(m_policies, url, reportingStatus);
1175 }
1176
1177 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1178 {
1179     return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_policies, url, reportingStatus);
1180 }
1181
1182 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1183 {
1184     return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m_policies, url, reportingStatus);
1185 }
1186
1187 bool ContentSecurityPolicy::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1188 {
1189     return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(m_policies, url, reportingStatus);
1190 }
1191
1192 bool ContentSecurityPolicy::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1193 {
1194     return isAllowedByAllWithURL<&CSPDirectiveList::allowStyleFromSource>(m_policies, url, reportingStatus);
1195 }
1196
1197 bool ContentSecurityPolicy::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1198 {
1199     return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(m_policies, url, reportingStatus);
1200 }
1201
1202 bool ContentSecurityPolicy::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1203 {
1204     return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(m_policies, url, reportingStatus);
1205 }
1206
1207 bool ContentSecurityPolicy::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
1208 {
1209     return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(m_policies, url, reportingStatus);
1210 }
1211
1212 bool ContentSecurityPolicy::isActive() const
1213 {
1214     return !m_policies.isEmpty();
1215 }
1216
1217 void ContentSecurityPolicy::gatherReportURIs(DOMStringList& list) const
1218 {
1219     for (size_t i = 0; i < m_policies.size(); ++i)
1220         m_policies[i].get()->gatherReportURIs(list);
1221 }
1222
1223 SecurityOrigin* ContentSecurityPolicy::securityOrigin() const
1224 {
1225     return m_scriptExecutionContext->securityOrigin();
1226 }
1227
1228 const KURL& ContentSecurityPolicy::url() const
1229 {
1230     return m_scriptExecutionContext->url();
1231 }
1232
1233 KURL ContentSecurityPolicy::completeURL(const String& url) const
1234 {
1235     return m_scriptExecutionContext->completeURL(url);
1236 }
1237
1238 void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask) const
1239 {
1240     m_scriptExecutionContext->enforceSandboxFlags(mask);
1241 }
1242
1243 void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
1244 {
1245     logToConsole(consoleMessage, contextURL, contextLine, callStack);
1246
1247     if (reportURIs.isEmpty())
1248         return;
1249
1250     // FIXME: Support sending reports from worker.
1251     if (!m_scriptExecutionContext->isDocument())
1252         return;
1253
1254     Document* document = static_cast<Document*>(m_scriptExecutionContext);
1255     Frame* frame = document->frame();
1256     if (!frame)
1257         return;
1258
1259     // We need to be careful here when deciding what information to send to the
1260     // report-uri. Currently, we send only the current document's URL and the
1261     // directive that was violated. The document's URL is safe to send because
1262     // it's the document itself that's requesting that it be sent. You could
1263     // make an argument that we shouldn't send HTTPS document URLs to HTTP
1264     // report-uris (for the same reasons that we supress the Referer in that
1265     // case), but the Referer is sent implicitly whereas this request is only
1266     // sent explicitly. As for which directive was violated, that's pretty
1267     // harmless information.
1268
1269     RefPtr<InspectorObject> cspReport = InspectorObject::create();
1270     cspReport->setString("document-uri", document->url().strippedForUseAsReferrer());
1271     String referrer = document->referrer();
1272     if (!referrer.isEmpty())
1273         cspReport->setString("referrer", referrer);
1274     if (!directiveText.isEmpty())
1275         cspReport->setString("violated-directive", directiveText);
1276     cspReport->setString("original-policy", header);
1277     if (blockedURL.isValid())
1278         cspReport->setString("blocked-uri", document->securityOrigin()->canRequest(blockedURL) ? blockedURL.strippedForUseAsReferrer() : SecurityOrigin::create(blockedURL)->toString());
1279
1280     RefPtr<InspectorObject> reportObject = InspectorObject::create();
1281     reportObject->setObject("csp-report", cspReport.release());
1282
1283     RefPtr<FormData> report = FormData::create(reportObject->toJSONString().utf8());
1284
1285     for (size_t i = 0; i < reportURIs.size(); ++i)
1286         PingLoader::reportContentSecurityPolicyViolation(frame, reportURIs[i], report);
1287 }
1288
1289 void ContentSecurityPolicy::reportUnrecognizedDirective(const String& name) const
1290 {
1291     String message = makeString("Unrecognized Content-Security-Policy directive '", name, "'.\n");
1292     logToConsole(message);
1293 }
1294
1295 void ContentSecurityPolicy::reportDuplicateDirective(const String& name) const
1296 {
1297     String message = makeString("Ignoring duplicate Content-Security-Policy directive '", name, "'.\n");
1298     logToConsole(message);
1299 }
1300
1301 void ContentSecurityPolicy::reportInvalidNonce(const String& nonce) const
1302 {
1303     String message = makeString("Ignoring invalid Content Security Policy script nonce: '", nonce, "'.\n");
1304     logToConsole(message);
1305 }
1306
1307 void ContentSecurityPolicy::reportIgnoredPathComponent(const String& directiveName, const String& completeSource, const String& path) const
1308 {
1309     String message = makeString("The source list for Content Security Policy directive '", directiveName, "' contains the source '", completeSource, "'. Content Security Policy 1.0 supports only schemes, hosts, and ports. Paths might be supported in the future, but for now, '", path, "' is being ignored. Be careful.");
1310     logToConsole(message);
1311 }
1312
1313 void ContentSecurityPolicy::logToConsole(const String& message, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
1314 {
1315 #if ENABLE(TIZEN_CSP)
1316     TIZEN_LOGI("message(%s)", message.utf8().data());
1317 #endif
1318     m_scriptExecutionContext->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt(), callStack);
1319 }
1320
1321 }