String CSPDirectiveList::parseSuboriginName(const String& policy) { Vector<UChar> characters; policy.appendTo(characters); const UChar* position = characters.data(); const UChar* end = position + characters.size(); // Parse the name of the suborigin (no spaces, single string) skipWhile<UChar, isASCIISpace>(position, end); if (position == end) { m_policy->reportInvalidSuboriginFlags("No suborigin name specified."); return String(); } const UChar* begin = position; skipWhile<UChar, isASCIIAlphanumeric>(position, end); if (position != end && !isASCIISpace(*position)) { m_policy->reportInvalidSuboriginFlags("Invalid character \'" + String(position, 1) + "\' in suborigin."); return String(); } size_t length = position - begin; skipWhile<UChar, isASCIISpace>(position, end); if (position != end) { m_policy->reportInvalidSuboriginFlags("Whitespace is not allowed in suborigin names."); return String(); } return String(begin, length); }
MediaListDirective::MediaListDirective(const String& name, const String& value, ContentSecurityPolicy* policy) : CSPDirective(name, value, policy) { Vector<UChar> characters; value.appendTo(characters); parse(characters.data(), characters.data() + characters.size()); }
void CSPDirectiveList::parseReportURI(const String& name, const String& value) { if (!m_reportEndpoints.isEmpty()) { m_policy->reportDuplicateDirective(name); return; } Vector<UChar> characters; value.appendTo(characters); const UChar* position = characters.data(); const UChar* end = position + characters.size(); while (position < end) { skipWhile<UChar, isASCIISpace>(position, end); const UChar* urlBegin = position; skipWhile<UChar, isNotASCIISpace>(position, end); if (urlBegin < position) { String url = String(urlBegin, position - urlBegin); m_reportEndpoints.append(url); } } }
void checkTextOfParagraph(TextCheckerClient& client, const String& text, TextCheckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) { Vector<UChar> characters; text.appendTo(characters); unsigned length = text.length(); Vector<TextCheckingResult> spellingResult; if (checkingTypes & TextCheckingTypeSpelling) findMisspellings(client, characters.data(), 0, length, spellingResult); Vector<TextCheckingResult> grammarResult; if (checkingTypes & TextCheckingTypeGrammar) { // Only checks grammartical error before the first misspellings int grammarCheckLength = length; for (const auto& spelling : spellingResult) { if (spelling.location < grammarCheckLength) grammarCheckLength = spelling.location; } findBadGrammars(client, characters.data(), 0, grammarCheckLength, grammarResult); } if (grammarResult.size()) results.swap(grammarResult); if (spellingResult.size()) { if (results.isEmpty()) results.swap(spellingResult); else results.appendVector(spellingResult); } }
SourceListDirective::SourceListDirective(const String& name, const String& value, ContentSecurityPolicy* policy) : CSPDirective(name, value, policy) , m_sourceList(policy, name) { Vector<UChar> characters; value.appendTo(characters); m_sourceList.parse(characters.data(), characters.data() + characters.size()); }
void CSPDirectiveList::parseReferrer(const String& name, const String& value) { if (m_didSetReferrerPolicy) { m_policy->reportDuplicateDirective(name); m_referrerPolicy = ReferrerPolicyNever; return; } m_didSetReferrerPolicy = true; if (value.isEmpty()) { m_policy->reportInvalidReferrer(value); m_referrerPolicy = ReferrerPolicyNever; return; } Vector<UChar> characters; value.appendTo(characters); const UChar* position = characters.data(); const UChar* end = position + characters.size(); skipWhile<UChar, isASCIISpace>(position, end); const UChar* begin = position; skipWhile<UChar, isNotASCIISpace>(position, end); // value1 // ^ if (equalIgnoringCase("unsafe-url", begin, position - begin)) { m_referrerPolicy = ReferrerPolicyAlways; } else if (equalIgnoringCase("no-referrer", begin, position - begin)) { m_referrerPolicy = ReferrerPolicyNever; } else if (equalIgnoringCase("no-referrer-when-downgrade", begin, position - begin)) { m_referrerPolicy = ReferrerPolicyDefault; } else if (equalIgnoringCase("origin", begin, position - begin)) { m_referrerPolicy = ReferrerPolicyOrigin; } else if (equalIgnoringCase("origin-when-crossorigin", begin, position - begin)) { m_referrerPolicy = ReferrerPolicyOriginWhenCrossOrigin; } else { m_referrerPolicy = ReferrerPolicyNever; m_policy->reportInvalidReferrer(value); return; } skipWhile<UChar, isASCIISpace>(position, end); if (position == end) return; // value1 value2 // ^ m_referrerPolicy = ReferrerPolicyNever; m_policy->reportInvalidReferrer(value); }
void expectMimeType(const String& text, const char* expectedType) { Vector<UChar> characters; text.appendTo(characters); const UChar* position = characters.data(); const UChar* end = characters.end(); String type; EXPECT_TRUE(SubresourceIntegrity::parseMimeType(position, end, type)); EXPECT_EQ(expectedType, type); }
void expectDigest(const String& text, const char* expectedDigest) { Vector<UChar> characters; text.appendTo(characters); const UChar* position = characters.data(); const UChar* end = characters.end(); String digest; EXPECT_TRUE(SubresourceIntegrity::parseDigest(position, end, digest)); EXPECT_EQ(expectedDigest, digest); }
void expectDigestFailure(const String& text) { Vector<UChar> characters; text.appendTo(characters); const UChar* position = characters.data(); const UChar* end = characters.end(); String digest; EXPECT_FALSE(SubresourceIntegrity::parseDigest(position, end, digest)); EXPECT_TRUE(digest.isEmpty()); }
void expectMimeTypeFailure(const String& text) { Vector<UChar> characters; text.appendTo(characters); const UChar* position = characters.data(); const UChar* end = characters.end(); String type; EXPECT_FALSE(SubresourceIntegrity::parseMimeType(position, end, type)); EXPECT_TRUE(type.isEmpty()); }
void expectAlgorithmFailure(const String& text) { Vector<UChar> characters; text.appendTo(characters); const UChar* position = characters.data(); const UChar* begin = characters.data(); const UChar* end = characters.end(); HashAlgorithm algorithm; EXPECT_FALSE(SubresourceIntegrity::parseAlgorithm(position, end, algorithm)); EXPECT_EQ(begin, position); }
void expectAlgorithm(const String& text, HashAlgorithm expectedAlgorithm) { Vector<UChar> characters; text.appendTo(characters); const UChar* position = characters.data(); const UChar* end = characters.end(); HashAlgorithm algorithm; EXPECT_TRUE(SubresourceIntegrity::parseAlgorithm(position, end, algorithm)); EXPECT_EQ(expectedAlgorithm, algorithm); EXPECT_EQ(';', *position); }
// Tests that report-uri directives are discarded from policies // delivered in <meta> elements. TEST_F(ContentSecurityPolicyTest, ReportURIInMeta) { String policy = "img-src 'none'; report-uri http://foo.test"; Vector<UChar> characters; policy.appendTo(characters); const UChar* begin = characters.data(); const UChar* end = begin + characters.size(); CSPDirectiveList* directiveList(CSPDirectiveList::create(csp, begin, end, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceMeta)); EXPECT_TRUE(directiveList->reportEndpoints().isEmpty()); directiveList = CSPDirectiveList::create(csp, begin, end, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); EXPECT_FALSE(directiveList->reportEndpoints().isEmpty()); }
inline SearchBuffer::SearchBuffer(const String& target, FindOptions options) : m_options(options) , m_prefixLength(0) , m_numberOfCharactersJustAppended(0) , m_atBreak(true) , m_needsMoreContext(options & AtWordStarts) , m_targetRequiresKanaWorkaround(containsKanaLetters(target)) { ASSERT(!target.isEmpty()); target.appendTo(m_target); // FIXME: We'd like to tailor the searcher to fold quote marks for us instead // of doing it in a separate replacement pass here, but ICU doesn't offer a way // to add tailoring on top of the locale-specific tailoring as of this writing. foldQuoteMarksAndSoftHyphens(m_target.data(), m_target.size()); size_t targetLength = m_target.size(); m_buffer.reserveInitialCapacity(std::max(targetLength * 8, minimumSearchBufferSize)); m_overlap = m_buffer.capacity() / 4; if ((m_options & AtWordStarts) && targetLength) { UChar32 targetFirstCharacter; U16_GET(m_target.data(), 0, 0, targetLength, targetFirstCharacter); // Characters in the separator category never really occur at the beginning of a word, // so if the target begins with such a character, we just ignore the AtWordStart option. if (isSeparator(targetFirstCharacter)) { m_options &= ~AtWordStarts; m_needsMoreContext = false; } } // Grab the single global searcher. // If we ever have a reason to do more than once search buffer at once, we'll have // to move to multiple searchers. lockSearcher(); UStringSearch* searcher = blink::searcher(); UCollator* collator = usearch_getCollator(searcher); UCollationStrength strength = m_options & CaseInsensitive ? UCOL_PRIMARY : UCOL_TERTIARY; if (ucol_getStrength(collator) != strength) { ucol_setStrength(collator, strength); usearch_reset(searcher); } UErrorCode status = U_ZERO_ERROR; usearch_setPattern(searcher, m_target.data(), targetLength, &status); ASSERT(status == U_ZERO_ERROR); // The kana workaround requires a normalized copy of the target string. if (m_targetRequiresKanaWorkaround) normalizeCharactersIntoNFCForm(m_target.data(), m_target.size(), m_normalizedTarget); }
void CSPDirectiveList::parseReflectedXSS(const String& name, const String& value) { if (m_reflectedXSSDisposition != ReflectedXSSUnset) { m_policy->reportDuplicateDirective(name); m_reflectedXSSDisposition = ReflectedXSSInvalid; return; } if (value.isEmpty()) { m_reflectedXSSDisposition = ReflectedXSSInvalid; m_policy->reportInvalidReflectedXSS(value); return; } Vector<UChar> characters; value.appendTo(characters); const UChar* position = characters.data(); const UChar* end = position + characters.size(); skipWhile<UChar, isASCIISpace>(position, end); const UChar* begin = position; skipWhile<UChar, isNotASCIISpace>(position, end); // value1 // ^ if (equalIgnoringCase("allow", begin, position - begin)) { m_reflectedXSSDisposition = AllowReflectedXSS; } else if (equalIgnoringCase("filter", begin, position - begin)) { m_reflectedXSSDisposition = FilterReflectedXSS; } else if (equalIgnoringCase("block", begin, position - begin)) { m_reflectedXSSDisposition = BlockReflectedXSS; } else { m_reflectedXSSDisposition = ReflectedXSSInvalid; m_policy->reportInvalidReflectedXSS(value); return; } skipWhile<UChar, isASCIISpace>(position, end); if (position == end && m_reflectedXSSDisposition != ReflectedXSSUnset) return; // value1 value2 // ^ m_reflectedXSSDisposition = ReflectedXSSInvalid; m_policy->reportInvalidReflectedXSS(value); }
inline SearchBuffer::SearchBuffer(const String& target, FindOptions options) : m_options(options), m_prefixLength(0), m_numberOfCharactersJustAppended(0), m_atBreak(true), m_needsMoreContext(options & AtWordStarts), m_targetRequiresKanaWorkaround(containsKanaLetters(target)) { DCHECK(!target.isEmpty()) << target; target.appendTo(m_target); // FIXME: We'd like to tailor the searcher to fold quote marks for us instead // of doing it in a separate replacement pass here, but ICU doesn't offer a // way to add tailoring on top of the locale-specific tailoring as of this // writing. foldQuoteMarksAndSoftHyphens(m_target.data(), m_target.size()); size_t targetLength = m_target.size(); m_buffer.reserveInitialCapacity( std::max(targetLength * 8, kMinimumSearchBufferSize)); m_overlap = m_buffer.capacity() / 4; if ((m_options & AtWordStarts) && targetLength) { const UChar32 targetFirstCharacter = getCodePointAt(m_target.data(), 0, targetLength); // Characters in the separator category never really occur at the beginning // of a word, so if the target begins with such a character, we just ignore // the AtWordStart option. if (isSeparator(targetFirstCharacter)) { m_options &= ~AtWordStarts; m_needsMoreContext = false; } } m_textSearcher = WTF::makeUnique<TextSearcherICU>(); m_textSearcher->setPattern(StringView(m_target.data(), m_target.size()), !(m_options & CaseInsensitive)); // The kana workaround requires a normalized copy of the target string. if (m_targetRequiresKanaWorkaround) normalizeCharactersIntoNFCForm(m_target.data(), m_target.size(), m_normalizedTarget); }
void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source) { // If this is a report-only header inside a <meta> element, bail out. if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecurityPolicyHeaderTypeReport && experimentalFeaturesEnabled()) { reportReportOnlyInMeta(header); return; } Vector<UChar> characters; header.appendTo(characters); const UChar* begin = characters.data(); const UChar* end = begin + characters.size(); // RFC2616, section 4.2 specifies that headers appearing multiple times can // be combined with a comma. Walk the header string, and parse each comma // separated chunk as a separate header. const UChar* position = begin; while (position < end) { skipUntil<UChar>(position, end, ','); // header1,header2 OR header1 // ^ ^ OwnPtr<CSPDirectiveList> policy = CSPDirectiveList::create(this, begin, position, type, source); // When a referrer policy has already been set, the most recent // one takes precedence. if (type != ContentSecurityPolicyHeaderTypeReport && policy->didSetReferrerPolicy()) m_referrerPolicy = policy->referrerPolicy(); if (!policy->allowEval(0, SuppressReport) && m_disableEvalErrorMessage.isNull()) m_disableEvalErrorMessage = policy->evalDisabledErrorMessage(); m_policies.append(policy.release()); // Skip the comma, and begin the next header from the current position. ASSERT(position == end || *position == ','); skipExactly<UChar>(position, end, ','); begin = position; } }
static String getFormatForSkeleton(const char* locale, const String& skeleton) { String format = "yyyy-MM"; UErrorCode status = U_ZERO_ERROR; UDateTimePatternGenerator* patternGenerator = udatpg_open(locale, &status); if (!patternGenerator) return format; status = U_ZERO_ERROR; Vector<UChar> skeletonCharacters; skeleton.appendTo(skeletonCharacters); int32_t length = udatpg_getBestPattern(patternGenerator, skeletonCharacters.data(), skeletonCharacters.size(), 0, 0, &status); if (status == U_BUFFER_OVERFLOW_ERROR && length) { StringBuffer<UChar> buffer(length); status = U_ZERO_ERROR; udatpg_getBestPattern(patternGenerator, skeletonCharacters.data(), skeletonCharacters.size(), buffer.characters(), length, &status); if (U_SUCCESS(status)) format = String::adopt(buffer); } udatpg_close(patternGenerator); return format; }
static void parseSourceList(CSPSourceList& sourceList, String& sources) { Vector<UChar> characters; sources.appendTo(characters); sourceList.parse(characters.data(), characters.data() + characters.size()); }