bool XSSAuditor::filterEmbedToken(HTMLToken& token) { ASSERT(token.type() == HTMLTokenTypes::StartTag); ASSERT(hasName(token, embedTag)); bool didBlockScript = false; if (isContainedInRequest(decodedSnippetForName(token))) { didBlockScript |= eraseAttributeIfInjected(token, codeAttr, String(), SrcLikeAttribute); didBlockScript |= eraseAttributeIfInjected(token, srcAttr, blankURL().string(), SrcLikeAttribute); didBlockScript |= eraseAttributeIfInjected(token, typeAttr); } return didBlockScript; }
bool XSSAuditor::filterScriptToken(HTMLToken& token) { ASSERT(token.type() == HTMLTokenTypes::StartTag); ASSERT(hasName(token, scriptTag)); m_cachedDecodedSnippet = decodedSnippetForName(token); m_shouldAllowCDATA = m_parser->tokenizer()->shouldAllowCDATA(); if (isContainedInRequest(decodedSnippetForName(token))) return eraseAttributeIfInjected(token, srcAttr, blankURL().string(), SrcLikeAttribute); return false; }
bool XSSAuditor::filterAppletToken(HTMLToken& token) { ASSERT(m_state == Initial); ASSERT(token.type() == HTMLToken::StartTag); ASSERT(hasName(token, appletTag)); bool didBlockScript = false; didBlockScript |= eraseAttributeIfInjected(token, codeAttr); didBlockScript |= eraseAttributeIfInjected(token, objectAttr); return didBlockScript; }
bool XSSAuditor::filterEmbedToken(HTMLToken& token) { ASSERT(m_state == Initial); ASSERT(token.type() == HTMLToken::StartTag); ASSERT(hasName(token, embedTag)); bool didBlockScript = false; didBlockScript |= eraseAttributeIfInjected(token, srcAttr, blankURL().string()); didBlockScript |= eraseAttributeIfInjected(token, typeAttr); return didBlockScript; }
bool XSSAuditor::filterScriptToken(HTMLToken& token) { ASSERT(m_state == Initial); ASSERT(token.type() == HTMLToken::StartTag); ASSERT(hasName(token, scriptTag)); if (eraseAttributeIfInjected(token, srcAttr, blankURL().string())) return true; m_state = AfterScriptStartTag; m_cachedSnippet = m_parser->sourceForToken(token); return false; }
bool XSSAuditor::filterObjectToken(HTMLToken& token) { ASSERT(m_state == Initial); ASSERT(token.type() == HTMLTokenTypes::StartTag); ASSERT(hasName(token, objectTag)); bool didBlockScript = false; didBlockScript |= eraseAttributeIfInjected(token, dataAttr, blankURL().string(), SrcLikeAttribute); didBlockScript |= eraseAttributeIfInjected(token, typeAttr); didBlockScript |= eraseAttributeIfInjected(token, classidAttr); return didBlockScript; }
void XSSAuditor::filterToken(HTMLToken& token) { if (m_state == Uninitialized) init(); ASSERT(m_state == Initialized); if (!m_isEnabled || m_xssProtection == XSSProtectionDisabled) return; bool didBlockScript = false; if (token.type() == HTMLTokenTypes::StartTag) didBlockScript = filterStartToken(token); else if (m_scriptTagNestingLevel) { if (token.type() == HTMLTokenTypes::Character) didBlockScript = filterCharacterToken(token); else if (token.type() == HTMLTokenTypes::EndTag) filterEndToken(token); } if (didBlockScript) { // FIXME: Consider using a more helpful console message. DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_parser->document()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage); bool didBlockEntirePage = (m_xssProtection == XSSProtectionBlockEnabled); if (didBlockEntirePage) m_parser->document()->frame()->loader()->stopAllLoaders(); if (!m_notifiedClient) { m_parser->document()->frame()->loader()->client()->didDetectXSS(m_parser->document()->url(), didBlockEntirePage); m_notifiedClient = true; } if (didBlockEntirePage) m_parser->document()->frame()->navigationScheduler()->scheduleLocationChange(m_parser->document()->securityOrigin(), blankURL(), String()); } }
void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken) { AtomicHTMLToken token(rawToken); // We clear the rawToken in case constructTreeFromAtomicToken // synchronously re-enters the parser. We don't clear the token immedately // for Character tokens because the AtomicHTMLToken avoids copying the // characters by keeping a pointer to the underlying buffer in the // HTMLToken. Fortunately, Character tokens can't cause us to re-enter // the parser. // // FIXME: Stop clearing the rawToken once we start running the parser off // the main thread or once we stop allowing synchronous JavaScript // execution from parseAttribute. if (rawToken.type() != HTMLToken::Character) rawToken.clear(); m_treeBuilder->constructTree(&token); if (!rawToken.isUninitialized()) { ASSERT(rawToken.type() == HTMLToken::Character); rawToken.clear(); } }
//------------------------------------------------------------------------------------------------ void XMLReader::HandleStart (HTMLToken t) { string val = StringUtil::ToLowerCopy(t.GetValue()); if (val == "board") inBoard = true; else if (val == "history") inHistory = true; else if (val == "move") { moveNum = 1; move.SetCaptured(NOTYPE); inMove = true; } if (val == "piece" && inMove) { switch(moveNum) { case 0 : break; case 1 : { move.SetType(GetTypeByName(t.GetAttribute("type"))); move.SetColor(GetColorByName(t.GetAttribute("color"))); Position pstart; pstart.SetRow(atoi((t.GetAttribute("row")).c_str())); pstart.SetCol(atoi((t.GetAttribute("column")).c_str())); move.SetStart(pstart); moveNum++; break; } case 2 : { Position pend; pend.SetRow(atoi((t.GetAttribute("row")).c_str())); pend.SetCol(atoi((t.GetAttribute("column")).c_str())); move.SetEnd(pend); moveNum++; break; } case 3 : move.SetCaptured(GetTypeByName(t.GetAttribute("type"))); moveNum++; break; } } }
void GameLoader::LoadBoard(HTMLTokenizer & tokenizer, Board * boardPtr) const { HTMLToken currentToken = tokenizer.GetNextToken(); while (currentToken.GetValue() != "board") { CheckForEndToken(currentToken); currentToken = tokenizer.GetNextToken(); } currentToken = tokenizer.GetNextToken(); while (currentToken.GetValue() != "board") { CheckForEndToken(currentToken); if (currentToken.GetValue() == "piece") { int pieceType = ConvertTypeStrToInt(currentToken.GetAttribute("type")); int pieceColor = ConvertColorStrToInt(currentToken.GetAttribute("color")); int col = atoi(currentToken.GetAttribute("column").c_str()); int row = atoi(currentToken.GetAttribute("row").c_str()); boardPtr->SetPiece(BoardPosition(row, col), pieceType, pieceColor); } currentToken = tokenizer.GetNextToken(); } }
bool XSSFilter::filterTokenAfterScriptStartTag(HTMLToken& token) { ASSERT(m_state == AfterScriptStartTag); m_state = Initial; if (token.type() != HTMLToken::Character) { ASSERT(token.type() == HTMLToken::EndTag || token.type() == HTMLToken::EndOfFile); return false; } int start = 0; // FIXME: We probably want to grab only the first few characters of the // contents of the script element. int end = token.endIndex() - token.startIndex(); if (isContainedInRequest(m_cachedSnippet + snippetForRange(token, start, end))) { token.eraseCharacters(); token.appendToCharacter(' '); // Technically, character tokens can't be empty. return true; } return false; }
bool XSSAuditor::filterTokenAfterScriptStartTag(HTMLToken& token) { ASSERT(m_state == AfterScriptStartTag); m_state = Initial; if (token.type() != HTMLTokenTypes::Character) { ASSERT(token.type() == HTMLTokenTypes::EndTag || token.type() == HTMLTokenTypes::EndOfFile); return false; } TextResourceDecoder* decoder = m_parser->document()->decoder(); if (isContainedInRequest(fullyDecodeString(m_cachedSnippet, decoder))) { int start = 0; int end = token.endIndex() - token.startIndex(); String snippet = snippetForJavaScript(snippetForRange(token, start, end)); if (isContainedInRequest(fullyDecodeString(snippet, decoder))) { token.eraseCharacters(); token.appendToCharacter(' '); // Technically, character tokens can't be empty. return true; } } return false; }
void TokenPreloadScanner::updatePredictedBaseURL(const HTMLToken& token) { ASSERT(m_predictedBaseElementURL.isEmpty()); if (auto* hrefAttribute = findAttribute(token.attributes(), hrefAttr.localName().string())) m_predictedBaseElementURL = URL(m_documentURL, stripLeadingAndTrailingHTMLSpaces(StringImpl::create8BitIfPossible(hrefAttribute->value))).isolatedCopy(); }
void TokenPreloadScanner::scan(const HTMLToken& token, Vector<std::unique_ptr<PreloadRequest>>& requests, Document& document) { switch (token.type()) { case HTMLToken::Character: if (!m_inStyle) return; m_cssScanner.scan(token.characters(), requests); return; case HTMLToken::EndTag: { TagId tagId = tagIdFor(token.name()); #if ENABLE(TEMPLATE_ELEMENT) if (tagId == TagId::Template) { if (m_templateCount) --m_templateCount; return; } #endif if (tagId == TagId::Style) { if (m_inStyle) m_cssScanner.reset(); m_inStyle = false; } else if (tagId == TagId::Picture && !m_pictureSourceState.isEmpty()) m_pictureSourceState.removeLast(); return; } case HTMLToken::StartTag: { #if ENABLE(TEMPLATE_ELEMENT) if (m_templateCount) return; #endif TagId tagId = tagIdFor(token.name()); #if ENABLE(TEMPLATE_ELEMENT) if (tagId == TagId::Template) { ++m_templateCount; return; } #endif if (tagId == TagId::Style) { m_inStyle = true; return; } if (tagId == TagId::Base) { // The first <base> element is the one that wins. if (!m_predictedBaseElementURL.isEmpty()) return; updatePredictedBaseURL(token); return; } if (tagId == TagId::Picture) { m_pictureSourceState.append(false); return; } StartTagScanner scanner(tagId, m_deviceScaleFactor); scanner.processAttributes(token.attributes(), document, m_pictureSourceState); if (auto request = scanner.createPreloadRequest(m_predictedBaseElementURL)) requests.append(WTFMove(request)); return; } default: return; } }
bool HTMLParser::isHeadStart(HTMLToken & token){ string lower = token.GetValue(); StringUtil::ToLower(lower); return (token.GetType() == TAG_START && lower.compare("head") == 0); }
void GameLoader::LoadMoveHistory(HTMLTokenizer & tokenizer, MoveHistory * gameHistory) const { HTMLToken currentToken = tokenizer.GetNextToken(); while (currentToken.GetValue() != "history") { CheckForEndToken(currentToken); currentToken = tokenizer.GetNextToken(); } currentToken = tokenizer.GetNextToken(); while (currentToken.GetValue() != "history") { CheckForEndToken(currentToken); if (currentToken.GetValue() == "move" && currentToken.GetType() == HTMLTokenType::TAG_START) { while (currentToken.GetValue() != "piece") { CheckForEndToken(currentToken); currentToken = tokenizer.GetNextToken(); } HTMLToken origin = currentToken; currentToken = tokenizer.GetNextToken(); while (currentToken.GetValue() != "piece") { CheckForEndToken(currentToken); currentToken = tokenizer.GetNextToken(); } HTMLToken destination = currentToken; currentToken = tokenizer.GetNextToken(); int originPieceType = ConvertTypeStrToInt(origin.GetAttribute("type")); int originPieceColor = ConvertColorStrToInt(origin.GetAttribute("color")); int originCol = atoi(origin.GetAttribute("column").c_str()); int originRow = atoi(origin.GetAttribute("row").c_str()); int destinationCol = atoi(destination.GetAttribute("column").c_str()); int destinationRow = atoi(destination.GetAttribute("row").c_str()); int capturedPieceType = -1; int capturedCol = -1; int capturedRow = -1; while (currentToken.GetValue() != "piece" && currentToken.GetValue() != "move") { CheckForEndToken(currentToken); currentToken = tokenizer.GetNextToken(); } if (currentToken.GetValue() == "piece") { capturedPieceType = ConvertTypeStrToInt(currentToken.GetAttribute("type")); capturedCol = atoi(currentToken.GetAttribute("column").c_str()); capturedRow = atoi(currentToken.GetAttribute("row").c_str()); } gameHistory->AddMove(Move(originPieceType, originPieceColor, BoardPosition(originRow, originCol), BoardPosition(destinationRow, destinationCol), capturedPieceType, BoardPosition(capturedRow, capturedCol))); } else { currentToken = tokenizer.GetNextToken(); } } }
String XSSAuditor::decodedSnippetForName(const HTMLToken& token) { // Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<"). return fullyDecodeString(m_parser->sourceForToken(token), m_parser->document()->decoder()).substring(0, token.name().size() + 1); }
bool HTMLParser::isScriptEnd(HTMLToken & token){ string lower = token.GetValue(); StringUtil::ToLower(lower); return (token.GetType() == TAG_END && lower == "script"); }
bool HTMLParser::isTitleEnd(HTMLToken & token){ string lower = token.GetValue(); StringUtil::ToLower(lower); return (token.GetType() == TAG_END && lower.compare("title") == 0); }
static bool hasName(const HTMLToken& token, const QualifiedName& name) { return threadSafeMatch(token.name(), name); }
bool HTMLParser::isText(HTMLToken & token){ string lower = token.GetValue(); StringUtil::ToLower(lower); return (token.GetType() == TEXT && !isWhiteSpace(lower)); }
CompactHTMLToken::CompactHTMLToken(const HTMLToken& token) : m_type(token.type()) { switch (m_type) { case HTMLTokenTypes::Uninitialized: ASSERT_NOT_REACHED(); break; case HTMLTokenTypes::DOCTYPE: m_data = String(token.name().data(), token.name().size()); m_publicIdentifier = String(token.publicIdentifier().data(), token.publicIdentifier().size()); m_systemIdentifier = String(token.systemIdentifier().data(), token.systemIdentifier().size()); break; case HTMLTokenTypes::EndOfFile: break; case HTMLTokenTypes::StartTag: m_attributes.reserveInitialCapacity(token.attributes().size()); for (Vector<AttributeBase>::const_iterator it = token.attributes().begin(); it != token.attributes().end(); ++it) m_attributes.append(CompactAttribute(String(it->m_name.data(), it->m_name.size()), String(it->m_value.data(), it->m_value.size()))); // Fall through! case HTMLTokenTypes::EndTag: m_selfClosing = token.selfClosing(); // Fall through! case HTMLTokenTypes::Comment: case HTMLTokenTypes::Character: if (token.isAll8BitData()) m_data = String::make8BitFrom16BitSource(token.data().data(), token.data().size()); else m_data = String(token.data().data(), token.data().size()); break; default: ASSERT_NOT_REACHED(); break; } }
bool HTMLParser::isHeaderEnd(HTMLToken & token){ string lower = token.GetValue(); StringUtil::ToLower(lower); boost::regex re("[hH][1-9]"); return (boost::regex_match(lower, re) && token.GetType() == TAG_END); }
TEST(AtomicHTMLTokenTest, EmptyAttributeValueFromCompactHTMLToken) { HTMLToken token; token.beginStartTag('a'); token.addNewAttribute(); token.beginAttributeName(3); token.appendToAttributeName('b'); token.endAttributeName(4); token.addNewAttribute(); token.beginAttributeName(5); token.appendToAttributeName('c'); token.endAttributeName(6); token.beginAttributeValue(8); token.endAttributeValue(8); AtomicHTMLToken atoken(CompactHTMLToken(&token, TextPosition())); const blink::Attribute* attributeB = atoken.getAttributeItem( QualifiedName(AtomicString(), "b", AtomicString())); ASSERT_TRUE(attributeB); EXPECT_FALSE(attributeB->value().isNull()); EXPECT_TRUE(attributeB->value().isEmpty()); const blink::Attribute* attributeC = atoken.getAttributeItem( QualifiedName(AtomicString(), "c", AtomicString())); ASSERT_TRUE(attributeC); EXPECT_FALSE(attributeC->value().isNull()); EXPECT_TRUE(attributeC->value().isEmpty()); const blink::Attribute* attributeD = atoken.getAttributeItem( QualifiedName(AtomicString(), "d", AtomicString())); EXPECT_FALSE(attributeD); }
static bool hasName(const HTMLToken& token, const QualifiedName& name) { return equalIgnoringNullity(token.name(), static_cast<const String&>(name.localName())); }
bool HTMLParser::isLinkStart(HTMLToken & token){ string lower = token.GetValue(); StringUtil::ToLower(lower); return (token.GetType() == TAG_START && lower == "a"); }