Changeset 213669 in webkit
- Timestamp:
- Mar 9, 2017 2:17:13 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r213666 r213669 1 2017-03-09 Alex Christensen <achristensen@webkit.org> 2 3 [Content Extensions] Introduce if-top-url and unless-top-url 4 https://bugs.webkit.org/show_bug.cgi?id=169433 5 6 Reviewed by Brady Eidson. 7 8 In r184116 I added if-domain and unless-domain to control whether a rule applies 9 based on the domain of the main document URL. I'm expanding this by adding if-top-url 10 and unless-top-url that run regular expressions on the entire main document URL so that 11 example.com/user1content can be distinguished from example.com/user2content. 12 To not add to the number of passes we make on the URLs for each load and to maintain JSON 13 backwards compatibility, I've made it so that if-top-url and unless-top-url can be used 14 instead of if-domain and unless-domain (which continue to work) but the two condition types 15 cannot be used together since running regular expressions on the entire main document URL 16 is strictly more powerful than checking the domain and subdomains. 17 As a minor detail, content extension regexes are by default ASCII-case-insensitive, so I've 18 done the same with top URL regexes, adding top-url-filter-is-case-sensitive to mirror the existing 19 url-filter-is-case-sensitive if the JSON author decides to make regexes case sensitive. 20 21 Covered by new API tests. 22 23 * contentextensions/CompiledContentExtension.h: 24 * contentextensions/ContentExtension.cpp: 25 (WebCore::ContentExtensions::ContentExtension::populateConditionCacheIfNeeded): 26 (WebCore::ContentExtensions::ContentExtension::topURLActions): 27 (WebCore::ContentExtensions::ContentExtension::cachedConditionedActions): Deleted. 28 * contentextensions/ContentExtension.h: 29 * contentextensions/ContentExtensionCompiler.cpp: 30 (WebCore::ContentExtensions::addUniversalActionsToDFA): 31 (WebCore::ContentExtensions::compileToBytecode): 32 We had three copies of compiling to bytecode that were almost the same and would've been made into three copies of the same code. 33 I moved them to one helper function that is called three times. 34 (WebCore::ContentExtensions::compileRuleList): 35 * contentextensions/ContentExtensionCompiler.h: 36 * contentextensions/ContentExtensionError.cpp: 37 (WebCore::ContentExtensions::contentExtensionErrorCategory): 38 Add the new error type for JSON that tries to use if-top-url and unless-top-url with if-domain and unless-domain. 39 * contentextensions/ContentExtensionError.h: 40 * contentextensions/ContentExtensionParser.cpp: 41 (WebCore::ContentExtensions::loadTrigger): 42 Parse the new values if-top-url, unless-top-url, and top-url-filter-is-case-sensitive. 43 * contentextensions/ContentExtensionRule.h: 44 (WebCore::ContentExtensions::Trigger::~Trigger): 45 * contentextensions/ContentExtensionsBackend.cpp: 46 (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad): 47 * contentextensions/DFABytecodeInterpreter.cpp: 48 (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretAppendAction): 49 (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretTestFlagsAndAppendAction): 50 (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretWithConditions): 51 * contentextensions/DFABytecodeInterpreter.h: 52 1 53 2017-03-09 Nikita Vasilyev <nvasilyev@apple.com> 2 54 -
trunk/Source/WebCore/contentextensions/CompiledContentExtension.h
r213533 r213669 43 43 virtual const DFABytecode* filtersWithConditionsBytecode() const = 0; 44 44 virtual unsigned filtersWithConditionsBytecodeLength() const = 0; 45 virtual const DFABytecode* conditionedFiltersBytecode() const = 0;46 virtual unsigned conditionedFiltersBytecodeLength() const = 0;45 virtual const DFABytecode* topURLFiltersBytecode() const = 0; 46 virtual unsigned topURLFiltersBytecodeLength() const = 0; 47 47 virtual const SerializedActionByte* actions() const = 0; 48 48 virtual unsigned actionsLength() const = 0; 49 virtual bool conditionsApplyOnlyToDomain() const = 0; 49 50 }; 50 51 -
trunk/Source/WebCore/contentextensions/ContentExtension.cpp
r213533 r213669 119 119 void ContentExtension::populateConditionCacheIfNeeded(const URL& topURL) 120 120 { 121 String domain = topURL.host(); 122 if (m_cachedDomain != domain) { 123 DFABytecodeInterpreter interpreter(m_compiledExtension->conditionedFiltersBytecode(), m_compiledExtension->conditionedFiltersBytecodeLength()); 121 if (m_cachedTopURL != topURL) { 122 DFABytecodeInterpreter interpreter(m_compiledExtension->topURLFiltersBytecode(), m_compiledExtension->topURLFiltersBytecodeLength()); 124 123 const uint16_t allLoadTypesAndResourceTypes = LoadTypeMask | ResourceTypeMask; 125 auto domainActions = interpreter.interpret(domain.utf8(), allLoadTypesAndResourceTypes); 124 String string = m_compiledExtension->conditionsApplyOnlyToDomain() ? topURL.host() : topURL.string(); 125 auto topURLActions = interpreter.interpret(string.utf8(), allLoadTypesAndResourceTypes); 126 126 127 m_cachedConditionedActions.clear(); 128 for (uint64_t action : domainActions) 129 m_cachedConditionedActions.add(action); 127 m_cachedTopURLActions.clear(); 128 for (uint64_t action : topURLActions) 129 m_cachedTopURLActions.add(action); 130 for (uint64_t action : interpreter.actionsMatchingEverything()) 131 m_cachedTopURLActions.add(action); 130 132 131 133 m_cachedUniversalConditionedActions.clear(); 132 134 for (uint64_t action : m_universalActionsWithConditions) { 133 ASSERT_WITH_MESSAGE((action & ~IfConditionFlag) == static_cast<uint32_t>(action), "Universal actions with domains should not have flags.");134 if (!!(action & IfConditionFlag) == m_cached ConditionedActions.contains(action))135 ASSERT_WITH_MESSAGE((action & ~IfConditionFlag) == static_cast<uint32_t>(action), "Universal actions with conditions should not have flags."); 136 if (!!(action & IfConditionFlag) == m_cachedTopURLActions.contains(action)) 135 137 m_cachedUniversalConditionedActions.append(static_cast<uint32_t>(action)); 136 138 } 137 139 m_cachedUniversalConditionedActions.shrinkToFit(); 138 m_cached Domain = domain;140 m_cachedTopURL = topURL; 139 141 } 140 142 } 141 143 142 const DFABytecodeInterpreter::Actions& ContentExtension:: cachedConditionedActions(const URL& topURL)144 const DFABytecodeInterpreter::Actions& ContentExtension::topURLActions(const URL& topURL) 143 145 { 144 146 populateConditionCacheIfNeeded(topURL); 145 return m_cached ConditionedActions;147 return m_cachedTopURLActions; 146 148 } 147 149 -
trunk/Source/WebCore/contentextensions/ContentExtension.h
r213533 r213669 47 47 const CompiledContentExtension& compiledExtension() const { return m_compiledExtension.get(); } 48 48 StyleSheetContents* globalDisplayNoneStyleSheet(); 49 const DFABytecodeInterpreter::Actions& cachedConditionedActions(const URL& topURL);49 const DFABytecodeInterpreter::Actions& topURLActions(const URL& topURL); 50 50 const Vector<uint32_t>& universalActionsWithoutConditions() { return m_universalActionsWithoutConditions; } 51 51 const Vector<uint32_t>& universalActionsWithConditions(const URL& topURL); … … 61 61 void compileGlobalDisplayNoneStyleSheet(); 62 62 63 String m_cachedDomain;63 URL m_cachedTopURL; 64 64 void populateConditionCacheIfNeeded(const URL& topURL); 65 DFABytecodeInterpreter::Actions m_cached ConditionedActions;65 DFABytecodeInterpreter::Actions m_cachedTopURLActions; 66 66 Vector<uint32_t> m_cachedUniversalConditionedActions; 67 67 -
trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp
r213533 r213669 188 188 typedef HashSet<uint64_t, DefaultHash<uint64_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> UniversalActionSet; 189 189 190 static void addUniversalActionsToDFA(DFA& dfa, const UniversalActionSet& universalActions)190 static void addUniversalActionsToDFA(DFA& dfa, UniversalActionSet&& universalActions) 191 191 { 192 192 if (universalActions.isEmpty()) … … 206 206 } 207 207 208 template<typename Functor> 209 static void compileToBytecode(CombinedURLFilters&& filters, UniversalActionSet&& universalActions, Functor writeBytecodeToClient) 210 { 211 // Smaller maxNFASizes risk high compiling and interpreting times from having too many DFAs, 212 // larger maxNFASizes use too much memory when compiling. 213 const unsigned maxNFASize = 75000; 214 215 bool firstNFASeen = false; 216 217 auto lowerDFAToBytecode = [&](DFA&& dfa) 218 { 219 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING 220 dataLogF("DFA\n"); 221 dfa.debugPrintDot(); 222 #endif 223 ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), "All actions on the DFA root should come from regular expressions that match everything."); 224 225 if (!firstNFASeen) { 226 // Put all the universal actions on the first DFA. 227 addUniversalActionsToDFA(dfa, WTFMove(universalActions)); 228 } 229 230 Vector<DFABytecode> bytecode; 231 DFABytecodeCompiler compiler(dfa, bytecode); 232 compiler.compile(); 233 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t)); 234 writeBytecodeToClient(WTFMove(bytecode)); 235 firstNFASeen = true; 236 }; 237 238 const unsigned smallDFASize = 100; 239 DFACombiner smallDFACombiner; 240 filters.processNFAs(maxNFASize, [&](NFA&& nfa) { 241 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING 242 dataLogF("NFA\n"); 243 nfa.debugPrintDot(); 244 #endif 245 LOG_LARGE_STRUCTURES(nfa, nfa.memoryUsed()); 246 DFA dfa = NFAToDFA::convert(nfa); 247 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed()); 248 249 if (dfa.graphSize() < smallDFASize) 250 smallDFACombiner.addDFA(WTFMove(dfa)); 251 else { 252 dfa.minimize(); 253 lowerDFAToBytecode(WTFMove(dfa)); 254 } 255 }); 256 257 smallDFACombiner.combineDFAs(smallDFASize, [&](DFA&& dfa) { 258 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed()); 259 lowerDFAToBytecode(WTFMove(dfa)); 260 }); 261 262 ASSERT(filters.isEmpty()); 263 264 if (!firstNFASeen) { 265 // Our bytecode interpreter expects to have at least one DFA, so if we haven't seen any 266 // create a dummy one and add any universal actions. 267 268 DFA dummyDFA = DFA::empty(); 269 addUniversalActionsToDFA(dummyDFA, WTFMove(universalActions)); 270 271 Vector<DFABytecode> bytecode; 272 DFABytecodeCompiler compiler(dummyDFA, bytecode); 273 compiler.compile(); 274 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t)); 275 writeBytecodeToClient(WTFMove(bytecode)); 276 } 277 LOG_LARGE_STRUCTURES(universalActions, universalActions.capacity() * sizeof(unsigned)); 278 } 279 208 280 std::error_code compileRuleList(ContentExtensionCompilationClient& client, String&& ruleJSON) 209 281 { … … 213 285 Vector<ContentExtensionRule> parsedRuleList = WTFMove(ruleList.value()); 214 286 287 bool domainConditionSeen = false; 288 bool topURLConditionSeen = false; 289 for (const auto& rule : parsedRuleList) { 290 switch (rule.trigger().conditionType) { 291 case Trigger::ConditionType::None: 292 break; 293 case Trigger::ConditionType::IfDomain: 294 case Trigger::ConditionType::UnlessDomain: 295 domainConditionSeen = true; 296 break; 297 case Trigger::ConditionType::IfTopURL: 298 case Trigger::ConditionType::UnlessTopURL: 299 topURLConditionSeen = true; 300 break; 301 } 302 } 303 if (topURLConditionSeen && domainConditionSeen) 304 return ContentExtensionError::JSONTopURLAndDomainConditions; 305 215 306 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING 216 307 double patternPartitioningStart = monotonicallyIncreasingTime(); … … 219 310 Vector<SerializedActionByte> actions; 220 311 Vector<unsigned> actionLocations = serializeActions(parsedRuleList, actions); 221 client.writeActions(WTFMove(actions));222 312 LOG_LARGE_STRUCTURES(actions, actions.capacity() * sizeof(SerializedActionByte)); 223 actions.clear();313 client.writeActions(WTFMove(actions), domainConditionSeen); 224 314 225 315 UniversalActionSet universalActionsWithoutConditions; 226 316 UniversalActionSet universalActionsWithConditions; 317 UniversalActionSet universalTopURLActions; 227 318 228 319 // FIXME: These don't all need to be in memory at the same time. 229 320 CombinedURLFilters filtersWithoutConditions; 230 321 CombinedURLFilters filtersWithConditions; 231 CombinedURLFilters conditionFilters;322 CombinedURLFilters topURLFilters; 232 323 URLFilterParser filtersWithoutConditionParser(filtersWithoutConditions); 233 324 URLFilterParser filtersWithConditionParser(filtersWithConditions); 325 URLFilterParser topURLFilterParser(topURLFilters); 234 326 235 327 for (unsigned ruleIndex = 0; ruleIndex < parsedRuleList.size(); ++ruleIndex) { … … 257 349 switch (trigger.conditionType) { 258 350 case Trigger::ConditionType::IfDomain: 351 case Trigger::ConditionType::IfTopURL: 259 352 actionLocationAndFlags |= IfConditionFlag; 260 353 break; 261 354 case Trigger::ConditionType::None: 262 355 case Trigger::ConditionType::UnlessDomain: 356 case Trigger::ConditionType::UnlessTopURL: 263 357 ASSERT(!(actionLocationAndFlags & IfConditionFlag)); 264 358 break; … … 274 368 return ContentExtensionError::JSONInvalidRegex; 275 369 } 276 for (const String& condition : trigger.conditions) 277 conditionFilters.addDomain(actionLocationAndFlags, condition); 370 for (const String& condition : trigger.conditions) { 371 if (domainConditionSeen) { 372 ASSERT(!topURLConditionSeen); 373 topURLFilters.addDomain(actionLocationAndFlags, condition); 374 } else { 375 ASSERT(topURLConditionSeen); 376 status = topURLFilterParser.addPattern(condition, trigger.topURLConditionIsCaseSensitive, actionLocationAndFlags); 377 if (status == URLFilterParser::MatchesEverything) { 378 universalTopURLActions.add(actionLocationAndFlags); 379 status = URLFilterParser::Ok; 380 } 381 if (status != URLFilterParser::Ok) { 382 dataLogF("Error while parsing %s: %s\n", condition.utf8().data(), URLFilterParser::statusString(status).utf8().data()); 383 return ContentExtensionError::JSONInvalidRegex; 384 } 385 } 386 } 278 387 } 279 388 ASSERT(status == URLFilterParser::Ok); … … 291 400 LOG_LARGE_STRUCTURES(filtersWithoutConditions, filtersWithoutConditions.memoryUsed()); 292 401 LOG_LARGE_STRUCTURES(filtersWithConditions, filtersWithConditions.memoryUsed()); 293 LOG_LARGE_STRUCTURES( conditionFilters, conditionFilters.memoryUsed());402 LOG_LARGE_STRUCTURES(topURLFilters, topURLFilters.memoryUsed()); 294 403 295 404 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING 296 unsigned machinesWithoutConditionsCount = 0;297 unsigned totalBytecodeSizeForMachinesWithoutConditions = 0;298 unsigned machinesWithConditionsCount = 0;299 unsigned totalBytecodeSizeForMachinesWithConditions = 0;300 405 double totalNFAToByteCodeBuildTimeStart = monotonicallyIncreasingTime(); 301 406 #endif 302 407 303 // Smaller maxNFASizes risk high compiling and interpreting times from having too many DFAs, 304 // larger maxNFASizes use too much memory when compiling. 305 const unsigned maxNFASize = 75000; 306 307 bool firstNFAWithoutConditionsSeen = false; 308 309 auto lowerFiltersWithoutConditionsDFAToBytecode = [&](DFA&& dfa) 310 { 311 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING 312 dataLogF("filtersWithoutConditions DFA\n"); 313 dfa.debugPrintDot(); 314 #endif 315 ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), "All actions on the DFA root should come from regular expressions that match everything."); 316 317 if (!firstNFAWithoutConditionsSeen) { 318 // Put all the universal actions on the first DFA. 319 addUniversalActionsToDFA(dfa, universalActionsWithoutConditions); 320 } 321 322 Vector<DFABytecode> bytecode; 323 DFABytecodeCompiler compiler(dfa, bytecode); 324 compiler.compile(); 325 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t)); 326 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING 327 ++machinesWithoutConditionsCount; 328 totalBytecodeSizeForMachinesWithoutConditions += bytecode.size(); 329 #endif 408 compileToBytecode(WTFMove(filtersWithoutConditions), WTFMove(universalActionsWithoutConditions), [&](Vector<DFABytecode>&& bytecode) { 330 409 client.writeFiltersWithoutConditionsBytecode(WTFMove(bytecode)); 331 332 firstNFAWithoutConditionsSeen = true;333 };334 335 const unsigned smallDFASize = 100;336 DFACombiner smallFiltersWithoutConditionsDFACombiner;337 filtersWithoutConditions.processNFAs(maxNFASize, [&](NFA&& nfa) {338 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING339 dataLogF("filtersWithoutConditions NFA\n");340 nfa.debugPrintDot();341 #endif342 343 LOG_LARGE_STRUCTURES(nfa, nfa.memoryUsed());344 DFA dfa = NFAToDFA::convert(nfa);345 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed());346 347 if (dfa.graphSize() < smallDFASize)348 smallFiltersWithoutConditionsDFACombiner.addDFA(WTFMove(dfa));349 else {350 dfa.minimize();351 lowerFiltersWithoutConditionsDFAToBytecode(WTFMove(dfa));352 }353 410 }); 354 355 356 smallFiltersWithoutConditionsDFACombiner.combineDFAs(smallDFASize, [&](DFA&& dfa) { 357 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed()); 358 lowerFiltersWithoutConditionsDFAToBytecode(WTFMove(dfa)); 411 compileToBytecode(WTFMove(filtersWithConditions), WTFMove(universalActionsWithConditions), [&](Vector<DFABytecode>&& bytecode) { 412 client.writeFiltersWithConditionsBytecode(WTFMove(bytecode)); 359 413 }); 360 361 ASSERT(filtersWithoutConditions.isEmpty()); 362 363 if (!firstNFAWithoutConditionsSeen) { 364 // Our bytecode interpreter expects to have at least one DFA, so if we haven't seen any 365 // create a dummy one and add any universal actions. 366 367 DFA dummyDFA = DFA::empty(); 368 addUniversalActionsToDFA(dummyDFA, universalActionsWithoutConditions); 369 370 Vector<DFABytecode> bytecode; 371 DFABytecodeCompiler compiler(dummyDFA, bytecode); 372 compiler.compile(); 373 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t)); 374 client.writeFiltersWithoutConditionsBytecode(WTFMove(bytecode)); 375 } 376 LOG_LARGE_STRUCTURES(universalActionsWithoutConditions, universalActionsWithoutConditions.capacity() * sizeof(unsigned)); 377 universalActionsWithoutConditions.clear(); 378 379 bool firstNFAWithConditionsSeen = false; 380 auto lowerFiltersWithConditionsDFAToBytecode = [&](DFA&& dfa) 381 { 382 if (!firstNFAWithConditionsSeen) { 383 // Put all the universal actions on the first DFA. 384 addUniversalActionsToDFA(dfa, universalActionsWithConditions); 385 } 386 387 Vector<DFABytecode> bytecode; 388 DFABytecodeCompiler compiler(dfa, bytecode); 389 compiler.compile(); 390 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t)); 391 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING 392 ++machinesWithConditionsCount; 393 totalBytecodeSizeForMachinesWithConditions += bytecode.size(); 394 #endif 395 client.writeFiltersWithConditionsBytecode(WTFMove(bytecode)); 396 397 firstNFAWithConditionsSeen = true; 398 }; 399 400 DFACombiner smallFiltersWithConditionsDFACombiner; 401 filtersWithConditions.processNFAs(maxNFASize, [&](NFA&& nfa) { 402 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING 403 dataLogF("filtersWithConditions NFA\n"); 404 nfa.debugPrintDot(); 405 #endif 406 LOG_LARGE_STRUCTURES(nfa, nfa.memoryUsed()); 407 DFA dfa = NFAToDFA::convert(nfa); 408 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING 409 dataLogF("filtersWithConditions PRE MINIMIZING DFA\n"); 410 dfa.debugPrintDot(); 411 #endif 412 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed()); 413 414 ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), "Filters with Conditions that match everything are not allowed right now."); 415 416 if (dfa.graphSize() < smallDFASize) 417 smallFiltersWithConditionsDFACombiner.addDFA(WTFMove(dfa)); 418 else { 419 dfa.minimize(); 420 lowerFiltersWithConditionsDFAToBytecode(WTFMove(dfa)); 421 } 414 compileToBytecode(WTFMove(topURLFilters), WTFMove(universalTopURLActions), [&](Vector<DFABytecode>&& bytecode) { 415 client.writeTopURLFiltersBytecode(WTFMove(bytecode)); 422 416 }); 423 smallFiltersWithConditionsDFACombiner.combineDFAs(smallDFASize, [&](DFA&& dfa) {424 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed());425 lowerFiltersWithConditionsDFAToBytecode(WTFMove(dfa));426 });427 ASSERT(filtersWithConditions.isEmpty());428 429 if (!firstNFAWithConditionsSeen) {430 // Our bytecode interpreter expects to have at least one DFA, so if we haven't seen any431 // create a dummy one and add any universal actions.432 433 DFA dummyDFA = DFA::empty();434 addUniversalActionsToDFA(dummyDFA, universalActionsWithConditions);435 436 Vector<DFABytecode> bytecode;437 DFABytecodeCompiler compiler(dummyDFA, bytecode);438 compiler.compile();439 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t));440 client.writeFiltersWithConditionsBytecode(WTFMove(bytecode));441 }442 LOG_LARGE_STRUCTURES(universalActionsWithConditions, universalActionsWithConditions.capacity() * sizeof(unsigned));443 universalActionsWithConditions.clear();444 445 conditionFilters.processNFAs(maxNFASize, [&](NFA&& nfa) {446 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING447 dataLogF("conditionFilters NFA\n");448 nfa.debugPrintDot();449 #endif450 LOG_LARGE_STRUCTURES(nfa, nfa.memoryUsed());451 DFA dfa = NFAToDFA::convert(nfa);452 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING453 dataLogF("conditionFilters DFA\n");454 dfa.debugPrintDot();455 #endif456 LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed());457 // Minimizing this DFA would not be effective because all actions are unique458 // and because of the tree-like structure of this DFA.459 ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), "There should not be any conditions that match everything.");460 461 Vector<DFABytecode> bytecode;462 DFABytecodeCompiler compiler(dfa, bytecode);463 compiler.compile();464 LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t));465 client.writeConditionedFiltersBytecode(WTFMove(bytecode));466 });467 ASSERT(conditionFilters.isEmpty());468 417 469 418 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING -
trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.h
r213533 r213669 41 41 42 42 // Functions should be called in this order. All except writeActions and finalize can be called multiple times, though. 43 virtual void writeActions(Vector<SerializedActionByte>&& ) = 0;43 virtual void writeActions(Vector<SerializedActionByte>&&, bool conditionsApplyOnlyToDomain) = 0; 44 44 virtual void writeFiltersWithoutConditionsBytecode(Vector<DFABytecode>&&) = 0; 45 45 virtual void writeFiltersWithConditionsBytecode(Vector<DFABytecode>&&) = 0; 46 virtual void write ConditionedFiltersBytecode(Vector<DFABytecode>&&) = 0;46 virtual void writeTopURLFiltersBytecode(Vector<DFABytecode>&&) = 0; 47 47 virtual void finalize() = 0; 48 48 }; -
trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp
r213533 r213669 79 79 return "Invalid or unsupported regular expression."; 80 80 case ContentExtensionError::JSONInvalidConditionList: 81 return "Invalid list of if-domain or unless-domainconditions.";81 return "Invalid list of if-domain, unless-domain, if-top-url, or unless-top-url conditions."; 82 82 case ContentExtensionError::JSONTooManyRules: 83 83 return "Too many rules in JSON array."; … … 85 85 return "Domains must be lower case ASCII. Use punycode to encode non-ASCII characters."; 86 86 case ContentExtensionError::JSONMultipleConditions: 87 return "A trigger cannot have more than one condition (if-domain or unless-domain)"; 87 return "A trigger cannot have more than one condition (if-domain, unless-domain, if-top-url, or unless-top-url)"; 88 case ContentExtensionError::JSONTopURLAndDomainConditions: 89 return "A list cannot have if-domain and unless-domain mixed with if-top-url and unless-top-url"; 88 90 } 89 91 -
trunk/Source/WebCore/contentextensions/ContentExtensionError.h
r213533 r213669 53 53 JSONDomainNotLowerCaseASCII, 54 54 JSONMultipleConditions, 55 JSONTopURLAndDomainConditions, 55 56 JSONTooManyRules, 56 57 -
trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp
r213533 r213669 154 154 trigger.urlFilterIsCaseSensitive = urlFilterCaseValue.toBoolean(&exec); 155 155 156 const JSValue topURLFilterCaseValue = triggerObject.get(&exec, Identifier::fromString(&exec, "top-url-filter-is-case-sensitive")); 157 if (topURLFilterCaseValue && !scope.exception() && topURLFilterCaseValue.isBoolean()) 158 trigger.topURLConditionIsCaseSensitive = topURLFilterCaseValue.toBoolean(&exec); 159 156 160 const JSValue resourceTypeValue = triggerObject.get(&exec, Identifier::fromString(&exec, "resource-type")); 157 161 if (!scope.exception() && resourceTypeValue.isObject()) { … … 197 201 return makeUnexpected(ContentExtensionError::JSONInvalidConditionList); 198 202 203 const JSValue ifTopURLValue = triggerObject.get(&exec, Identifier::fromString(&exec, "if-top-url")); 204 if (!scope.exception() && ifTopURLValue.isObject()) { 205 if (trigger.conditionType != Trigger::ConditionType::None) 206 return makeUnexpected(ContentExtensionError::JSONMultipleConditions); 207 auto ifTopURL = getStringList(exec, asObject(ifTopURLValue)); 208 if (!ifTopURL.hasValue()) 209 return makeUnexpected(ifTopURL.error()); 210 trigger.conditions = WTFMove(ifTopURL.value()); 211 if (trigger.conditions.isEmpty()) 212 return makeUnexpected(ContentExtensionError::JSONInvalidConditionList); 213 trigger.conditionType = Trigger::ConditionType::IfTopURL; 214 } else if (!ifTopURLValue.isUndefined()) 215 return makeUnexpected(ContentExtensionError::JSONInvalidConditionList); 216 217 const JSValue unlessTopURLValue = triggerObject.get(&exec, Identifier::fromString(&exec, "unless-top-url")); 218 if (!scope.exception() && unlessTopURLValue.isObject()) { 219 if (trigger.conditionType != Trigger::ConditionType::None) 220 return makeUnexpected(ContentExtensionError::JSONMultipleConditions); 221 auto unlessTopURL = getStringList(exec, asObject(unlessTopURLValue)); 222 if (!unlessTopURL.hasValue()) 223 return makeUnexpected(unlessTopURL.error()); 224 trigger.conditions = WTFMove(unlessTopURL.value()); 225 if (trigger.conditions.isEmpty()) 226 return makeUnexpected(ContentExtensionError::JSONInvalidConditionList); 227 trigger.conditionType = Trigger::ConditionType::UnlessTopURL; 228 } else if (!unlessTopURLValue.isUndefined()) 229 return makeUnexpected(ContentExtensionError::JSONInvalidConditionList); 230 199 231 return WTFMove(trigger); 200 232 } -
trunk/Source/WebCore/contentextensions/ContentExtensionRule.h
r213533 r213669 44 44 String urlFilter; 45 45 bool urlFilterIsCaseSensitive { false }; 46 bool topURLConditionIsCaseSensitive { false }; 46 47 ResourceFlags flags { 0 }; 47 48 Vector<String> conditions; … … 50 51 IfDomain, 51 52 UnlessDomain, 52 } conditionType { ConditionType::None }; 53 IfTopURL, 54 UnlessTopURL, 55 }; 56 ConditionType conditionType { ConditionType::None }; 53 57 54 58 ~Trigger() 55 59 { 56 60 ASSERT(conditions.isEmpty() == (conditionType == ConditionType::None)); 61 if (topURLConditionIsCaseSensitive) 62 ASSERT(conditionType == ConditionType::IfTopURL || conditionType == ConditionType::UnlessTopURL); 57 63 } 58 64 -
trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp
r213533 r213669 97 97 URL topURL = resourceLoadInfo.mainDocumentURL; 98 98 DFABytecodeInterpreter withConditionsInterpreter(compiledExtension.filtersWithConditionsBytecode(), compiledExtension.filtersWithConditionsBytecodeLength()); 99 DFABytecodeInterpreter::Actions withConditionsActions = withConditionsInterpreter.interpretWithConditions(urlCString, flags, contentExtension-> cachedConditionedActions(topURL));99 DFABytecodeInterpreter::Actions withConditionsActions = withConditionsInterpreter.interpretWithConditions(urlCString, flags, contentExtension->topURLActions(topURL)); 100 100 101 101 const SerializedActionByte* actions = compiledExtension.actions(); -
trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp
r213533 r213669 99 99 || getInstruction(m_bytecode, m_bytecodeLength, programCounter) == DFABytecodeInstruction::AppendActionWithIfCondition); 100 100 uint64_t action = (ifCondition ? IfConditionFlag : 0) | static_cast<uint64_t>(getBits<uint32_t>(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecodeInstruction))); 101 if (!m_ conditionActions || matchesCondition(action, *m_conditionActions))101 if (!m_topURLActions || matchesCondition(action, *m_topURLActions)) 102 102 actions.add(action); 103 103 … … 120 120 if (loadTypeMatches && resourceTypeMatches) { 121 121 uint64_t actionAndFlags = (ifCondition ? IfConditionFlag : 0) | (static_cast<uint64_t>(flagsToCheck) << 32) | static_cast<uint64_t>(getBits<uint32_t>(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecodeInstruction) + sizeof(uint16_t))); 122 if (!m_ conditionActions || matchesCondition(actionAndFlags, *m_conditionActions))122 if (!m_topURLActions || matchesCondition(actionAndFlags, *m_topURLActions)) 123 123 actions.add(actionAndFlags); 124 124 } … … 170 170 } 171 171 172 DFABytecodeInterpreter::Actions DFABytecodeInterpreter::interpretWithConditions(const CString& urlCString, uint16_t flags, const DFABytecodeInterpreter::Actions& conditionActions)173 { 174 ASSERT(!m_ conditionActions);175 m_ conditionActions = &conditionActions;172 DFABytecodeInterpreter::Actions DFABytecodeInterpreter::interpretWithConditions(const CString& urlCString, uint16_t flags, const DFABytecodeInterpreter::Actions& topURLActions) 173 { 174 ASSERT(!m_topURLActions); 175 m_topURLActions = &topURLActions; 176 176 DFABytecodeInterpreter::Actions actions = interpret(urlCString, flags); 177 m_ conditionActions = nullptr;177 m_topURLActions = nullptr; 178 178 return actions; 179 179 } -
trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.h
r213533 r213669 61 61 const DFABytecode* m_bytecode; 62 62 const unsigned m_bytecodeLength; 63 const DFABytecodeInterpreter::Actions* m_ conditionActions { nullptr };63 const DFABytecodeInterpreter::Actions* m_topURLActions { nullptr }; 64 64 }; 65 65 -
trunk/Source/WebKit2/ChangeLog
r213665 r213669 1 2017-03-09 Alex Christensen <achristensen@webkit.org> 2 3 [Content Extensions] Introduce if-top-url and unless-top-url 4 https://bugs.webkit.org/show_bug.cgi?id=169433 5 6 Reviewed by Brady Eidson. 7 8 Rename conditionedFilters to topURLFilters to reflect the fact that they are the filters 9 that are run on the top URL, and possibly just the domain of the top url. 10 I was a bit too aggressive when renaming domain* to condition* in r213533. 11 12 * Shared/WebCompiledContentExtension.cpp: 13 (WebKit::WebCompiledContentExtension::conditionsApplyOnlyToDomain): 14 (WebKit::WebCompiledContentExtension::topURLFiltersBytecode): 15 (WebKit::WebCompiledContentExtension::topURLFiltersBytecodeLength): 16 (WebKit::WebCompiledContentExtension::conditionedFiltersBytecode): Deleted. 17 (WebKit::WebCompiledContentExtension::conditionedFiltersBytecodeLength): Deleted. 18 * Shared/WebCompiledContentExtension.h: 19 * Shared/WebCompiledContentExtensionData.cpp: 20 (WebKit::WebCompiledContentExtensionData::encode): 21 (WebKit::WebCompiledContentExtensionData::decode): 22 * Shared/WebCompiledContentExtensionData.h: 23 (WebKit::WebCompiledContentExtensionData::WebCompiledContentExtensionData): 24 * UIProcess/API/APIUserContentExtensionStore.cpp: 25 (API::encodeContentExtensionMetaData): 26 (API::decodeContentExtensionMetaData): 27 (API::compiledToFile): 28 (API::createExtension): 29 (API::UserContentExtensionStore::invalidateContentExtensionVersion): 30 (API::userContentExtensionStoreErrorCategory): 31 * UIProcess/API/APIUserContentExtensionStore.h: 32 Increment CurrentContentExtensionFileVersion because we have changed the format of the binary on disk. 33 We only added 4 bytes, but that's binary incompatible and requires re-compiling any existing content extensions. 34 1 35 2017-03-09 Brent Fulgham <bfulgham@apple.com> 2 36 -
trunk/Source/WebKit2/Shared/WebCompiledContentExtension.cpp
r213533 r213669 45 45 } 46 46 47 bool WebCompiledContentExtension::conditionsApplyOnlyToDomain() const 48 { 49 return *reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(m_data.data->data()) + m_data.conditionsApplyOnlyToDomainOffset); 50 } 51 47 52 const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension::filtersWithoutConditionsBytecode() const 48 53 { … … 65 70 } 66 71 67 const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension:: conditionedFiltersBytecode() const72 const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension::topURLFiltersBytecode() const 68 73 { 69 return static_cast<const WebCore::ContentExtensions::DFABytecode*>(m_data.data->data()) + m_data. conditionedFiltersBytecodeOffset;74 return static_cast<const WebCore::ContentExtensions::DFABytecode*>(m_data.data->data()) + m_data.topURLFiltersBytecodeOffset; 70 75 } 71 76 72 unsigned WebCompiledContentExtension:: conditionedFiltersBytecodeLength() const77 unsigned WebCompiledContentExtension::topURLFiltersBytecodeLength() const 73 78 { 74 return m_data. conditionedFiltersBytecodeSize;79 return m_data.topURLFiltersBytecodeSize; 75 80 } 76 81 -
trunk/Source/WebKit2/Shared/WebCompiledContentExtension.h
r213533 r213669 48 48 const WebCore::ContentExtensions::DFABytecode* filtersWithConditionsBytecode() const final; 49 49 unsigned filtersWithConditionsBytecodeLength() const final; 50 const WebCore::ContentExtensions::DFABytecode* conditionedFiltersBytecode() const final; 51 unsigned conditionedFiltersBytecodeLength() const final; 50 const WebCore::ContentExtensions::DFABytecode* topURLFiltersBytecode() const final; 51 unsigned topURLFiltersBytecodeLength() const final; 52 bool conditionsApplyOnlyToDomain() const final; 52 53 53 54 const WebCore::ContentExtensions::SerializedActionByte* actions() const final; -
trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.cpp
r213533 r213669 45 45 encoder << filtersWithConditionsBytecodeOffset; 46 46 encoder << filtersWithConditionsBytecodeSize; 47 encoder << conditionedFiltersBytecodeOffset;48 encoder << conditionedFiltersBytecodeSize;47 encoder << topURLFiltersBytecodeOffset; 48 encoder << topURLFiltersBytecodeSize; 49 49 } 50 50 … … 68 68 if (!decoder.decode(compiledContentExtensionData.filtersWithConditionsBytecodeSize)) 69 69 return false; 70 if (!decoder.decode(compiledContentExtensionData. conditionedFiltersBytecodeOffset))70 if (!decoder.decode(compiledContentExtensionData.topURLFiltersBytecodeOffset)) 71 71 return false; 72 if (!decoder.decode(compiledContentExtensionData. conditionedFiltersBytecodeSize))72 if (!decoder.decode(compiledContentExtensionData.topURLFiltersBytecodeSize)) 73 73 return false; 74 74 -
trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.h
r213533 r213669 43 43 WebCompiledContentExtensionData() = default; 44 44 45 WebCompiledContentExtensionData(RefPtr<SharedMemory>&& data, NetworkCache::Data fileData, unsigned actionsOffset, unsigned actionsSize, unsigned filtersWithoutConditionsBytecodeOffset, unsigned filtersWithoutConditionsBytecodeSize, unsigned filtersWithConditionsBytecodeOffset, unsigned filtersWithConditionsBytecodeSize, unsigned conditionedFiltersBytecodeOffset, unsigned conditionedFiltersBytecodeSize)45 WebCompiledContentExtensionData(RefPtr<SharedMemory>&& data, NetworkCache::Data fileData, unsigned conditionsApplyOnlyToDomainOffset, unsigned actionsOffset, unsigned actionsSize, unsigned filtersWithoutConditionsBytecodeOffset, unsigned filtersWithoutConditionsBytecodeSize, unsigned filtersWithConditionsBytecodeOffset, unsigned filtersWithConditionsBytecodeSize, unsigned topURLFiltersBytecodeOffset, unsigned topURLFiltersBytecodeSize) 46 46 : data(WTFMove(data)) 47 47 , fileData(fileData) 48 , conditionsApplyOnlyToDomainOffset(conditionsApplyOnlyToDomainOffset) 48 49 , actionsOffset(actionsOffset) 49 50 , actionsSize(actionsSize) … … 52 53 , filtersWithConditionsBytecodeOffset(filtersWithConditionsBytecodeOffset) 53 54 , filtersWithConditionsBytecodeSize(filtersWithConditionsBytecodeSize) 54 , conditionedFiltersBytecodeOffset(conditionedFiltersBytecodeOffset)55 , conditionedFiltersBytecodeSize(conditionedFiltersBytecodeSize)55 , topURLFiltersBytecodeOffset(topURLFiltersBytecodeOffset) 56 , topURLFiltersBytecodeSize(topURLFiltersBytecodeSize) 56 57 { 57 58 } … … 62 63 RefPtr<SharedMemory> data; 63 64 NetworkCache::Data fileData; 65 unsigned conditionsApplyOnlyToDomainOffset { 0 }; 64 66 unsigned actionsOffset { 0 }; 65 67 unsigned actionsSize { 0 }; … … 68 70 unsigned filtersWithConditionsBytecodeOffset { 0 }; 69 71 unsigned filtersWithConditionsBytecodeSize { 0 }; 70 unsigned conditionedFiltersBytecodeOffset { 0 };71 unsigned conditionedFiltersBytecodeSize { 0 };72 unsigned topURLFiltersBytecodeOffset { 0 }; 73 unsigned topURLFiltersBytecodeSize { 0 }; 72 74 }; 73 75 -
trunk/Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.cpp
r213533 r213669 80 80 } 81 81 82 const size_t ContentExtensionFileHeaderSize = sizeof(uint32_t) + 4 * sizeof(uint64_t); 82 // The size and offset of the densely packed bytes in the file, not sizeof and offsetof, which would 83 // represent the size and offset of the structure in memory, possibly with compiler-added padding. 84 const size_t ContentExtensionFileHeaderSize = 2 * sizeof(uint32_t) + 4 * sizeof(uint64_t); 85 const size_t ConditionsApplyOnlyToDomainOffset = sizeof(uint32_t) + 4 * sizeof(uint64_t); 86 83 87 struct ContentExtensionMetaData { 84 88 uint32_t version { UserContentExtensionStore::CurrentContentExtensionFileVersion }; … … 87 91 uint64_t filtersWithConditionsBytecodeSize { 0 }; 88 92 uint64_t conditionedFiltersBytecodeSize { 0 }; 93 uint32_t conditionsApplyOnlyToDomain { false }; 89 94 90 95 size_t fileSize() const … … 107 112 encoder << metaData.filtersWithConditionsBytecodeSize; 108 113 encoder << metaData.conditionedFiltersBytecodeSize; 114 encoder << metaData.conditionsApplyOnlyToDomain; 109 115 110 116 ASSERT(encoder.bufferSize() == ContentExtensionFileHeaderSize); … … 132 138 if (!decoder.decode(metaData.conditionedFiltersBytecodeSize)) 133 139 return false; 140 if (!decoder.decode(metaData.conditionsApplyOnlyToDomain)) 141 return false; 134 142 success = true; 135 143 return false; … … 178 186 ASSERT(!metaData.filtersWithConditionsBytecodeSize); 179 187 ASSERT(!metaData.conditionedFiltersBytecodeSize); 180 } 181 182 void writeFiltersWithoutConditionsBytecode(Vector<DFABytecode>&& bytecode) override 188 ASSERT(!metaData.conditionsApplyOnlyToDomain); 189 } 190 191 void writeFiltersWithoutConditionsBytecode(Vector<DFABytecode>&& bytecode) final 183 192 { 184 193 ASSERT(!m_filtersWithConditionBytecodeWritten); … … 188 197 } 189 198 190 void writeFiltersWithConditionsBytecode(Vector<DFABytecode>&& bytecode) override199 void writeFiltersWithConditionsBytecode(Vector<DFABytecode>&& bytecode) final 191 200 { 192 201 ASSERT(!m_conditionFiltersBytecodeWritten); … … 195 204 } 196 205 197 void write ConditionedFiltersBytecode(Vector<DFABytecode>&& bytecode) override206 void writeTopURLFiltersBytecode(Vector<DFABytecode>&& bytecode) final 198 207 { 199 208 m_conditionFiltersBytecodeWritten += bytecode.size(); … … 201 210 } 202 211 203 void writeActions(Vector<SerializedActionByte>&& actions ) override212 void writeActions(Vector<SerializedActionByte>&& actions, bool conditionsApplyOnlyToDomain) final 204 213 { 205 214 ASSERT(!m_filtersWithoutConditionsBytecodeWritten); … … 208 217 ASSERT(!m_actionsWritten); 209 218 m_actionsWritten += actions.size(); 219 m_conditionsApplyOnlyToDomain = conditionsApplyOnlyToDomain; 210 220 writeToFile(Data(actions.data(), actions.size())); 211 221 } 212 222 213 void finalize() override223 void finalize() final 214 224 { 215 225 m_metaData.actionsSize = m_actionsWritten; … … 217 227 m_metaData.filtersWithConditionsBytecodeSize = m_filtersWithConditionBytecodeWritten; 218 228 m_metaData.conditionedFiltersBytecodeSize = m_conditionFiltersBytecodeWritten; 229 m_metaData.conditionsApplyOnlyToDomain = m_conditionsApplyOnlyToDomain; 219 230 220 231 Data header = encodeContentExtensionMetaData(m_metaData); … … 243 254 size_t m_conditionFiltersBytecodeWritten { 0 }; 244 255 size_t m_actionsWritten { 0 }; 256 bool m_conditionsApplyOnlyToDomain { false }; 245 257 bool m_fileError { false }; 246 258 }; … … 286 298 WTFMove(sharedMemory), 287 299 fileData, 300 ConditionsApplyOnlyToDomainOffset, 288 301 ContentExtensionFileHeaderSize, 289 302 metaData.actionsSize, … … 384 397 if (file == WebCore::invalidPlatformFileHandle) 385 398 return; 386 ContentExtensionMetaData invalidHeader = {0, 0, 0, 0, 0};399 ContentExtensionMetaData invalidHeader; 387 400 auto bytesWritten = WebCore::writeToFile(file, reinterpret_cast<const char*>(&invalidHeader), sizeof(invalidHeader)); 388 401 ASSERT_UNUSED(bytesWritten, bytesWritten == sizeof(invalidHeader)); … … 393 406 { 394 407 class UserContentExtensionStoreErrorCategory : public std::error_category { 395 const char* name() const noexcept override408 const char* name() const noexcept final 396 409 { 397 410 return "user content extension store"; 398 411 } 399 412 400 std::string message(int errorCode) const override413 std::string message(int errorCode) const final 401 414 { 402 415 switch (static_cast<UserContentExtensionStore::Error>(errorCode)) { -
trunk/Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.h
r213533 r213669 51 51 // This should be incremented every time a functional change is made to the bytecode, file format, etc. 52 52 // to prevent crashing while loading old data. 53 const static uint32_t CurrentContentExtensionFileVersion = 7;53 const static uint32_t CurrentContentExtensionFileVersion = 8; 54 54 55 55 static UserContentExtensionStore& defaultStore(); -
trunk/Tools/ChangeLog
r213658 r213669 1 2017-03-09 Alex Christensen <achristensen@webkit.org> 2 3 [Content Extensions] Introduce if-top-url and unless-top-url 4 https://bugs.webkit.org/show_bug.cgi?id=169433 5 6 Reviewed by Brady Eidson. 7 8 * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp: 9 (TestWebKitAPI::TEST_F): 10 Add tests for new functionality and new failure types. 11 1 12 2017-03-09 Srinivasan Vijayaraghavan <svijayaraghavan@apple.com> 2 13 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp
r213533 r213669 86 86 Vector<ContentExtensions::DFABytecode> filtersWithoutConditions; 87 87 Vector<ContentExtensions::DFABytecode> filtersWithConditions; 88 Vector<ContentExtensions::DFABytecode> conditionedFilters; 88 Vector<ContentExtensions::DFABytecode> topURLFilters; 89 bool conditionsApplyOnlyToDomain { false }; 89 90 }; 90 91 … … 97 98 EXPECT_EQ(data.filtersWithoutConditions.size(), 0ull); 98 99 EXPECT_EQ(data.filtersWithConditions.size(), 0ull); 99 EXPECT_EQ(data. conditionedFilters.size(), 0ull);100 EXPECT_EQ(data.topURLFilters.size(), 0ull); 100 101 } 101 102 102 void writeActions(Vector<ContentExtensions::SerializedActionByte>&& actions ) final103 void writeActions(Vector<ContentExtensions::SerializedActionByte>&& actions, bool conditionsApplyOnlyToDomain) final 103 104 { 104 105 EXPECT_FALSE(finalized); … … 106 107 EXPECT_EQ(m_data.filtersWithoutConditions.size(), 0ull); 107 108 EXPECT_EQ(m_data.filtersWithConditions.size(), 0ull); 108 EXPECT_EQ(m_data.conditionedFilters.size(), 0ull); 109 EXPECT_EQ(m_data.topURLFilters.size(), 0ull); 110 EXPECT_EQ(m_data.actions.size(), 0ull); 109 111 m_data.actions.appendVector(actions); 112 m_data.conditionsApplyOnlyToDomain = conditionsApplyOnlyToDomain; 110 113 } 111 114 … … 114 117 EXPECT_FALSE(finalized); 115 118 EXPECT_EQ(m_data.filtersWithConditions.size(), 0ull); 116 EXPECT_EQ(m_data. conditionedFilters.size(), 0ull);119 EXPECT_EQ(m_data.topURLFilters.size(), 0ull); 117 120 m_data.filtersWithoutConditions.appendVector(bytecode); 118 121 } … … 121 124 { 122 125 EXPECT_FALSE(finalized); 123 EXPECT_EQ(m_data. conditionedFilters.size(), 0ull);126 EXPECT_EQ(m_data.topURLFilters.size(), 0ull); 124 127 m_data.filtersWithConditions.appendVector(bytecode); 125 128 } 126 129 127 void write ConditionedFiltersBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) final130 void writeTopURLFiltersBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) final 128 131 { 129 132 EXPECT_FALSE(finalized); 130 m_data. conditionedFilters.appendVector(bytecode);133 m_data.topURLFilters.appendVector(bytecode); 131 134 } 132 135 … … 172 175 const ContentExtensions::DFABytecode* filtersWithConditionsBytecode() const final { return m_data.filtersWithConditions.data(); } 173 176 unsigned filtersWithConditionsBytecodeLength() const final { return m_data.filtersWithConditions.size(); } 174 const ContentExtensions::DFABytecode* conditionedFiltersBytecode() const final { return m_data.conditionedFilters.data(); } 175 unsigned conditionedFiltersBytecodeLength() const final { return m_data.conditionedFilters.size(); } 177 const ContentExtensions::DFABytecode* topURLFiltersBytecode() const final { return m_data.topURLFilters.data(); } 178 unsigned topURLFiltersBytecodeLength() const final { return m_data.topURLFilters.size(); } 179 bool conditionsApplyOnlyToDomain() const final { return m_data.conditionsApplyOnlyToDomain; } 176 180 177 181 private: … … 789 793 testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies }); 790 794 testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies }); 791 795 } 796 797 TEST_F(ContentExtensionTest, TopURL) 798 { 799 const Vector<ContentExtensions::ActionType> blockLoad = { ContentExtensions::ActionType::BlockLoad }; 800 const Vector<ContentExtensions::ActionType> blockCookies = { ContentExtensions::ActionType::BlockCookies }; 801 802 auto ifTopURL = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org\"]}}]"); 803 testRequest(ifTopURL, mainDocumentRequest("http://webkit.org/test.html"), blockLoad); 804 testRequest(ifTopURL, mainDocumentRequest("http://webkit.org/test.not_html"), { }); 805 testRequest(ifTopURL, mainDocumentRequest("http://WEBKIT.org/test.html"), blockLoad); 806 testRequest(ifTopURL, mainDocumentRequest("http://webkit.org/TEST.html"), blockLoad); 807 testRequest(ifTopURL, mainDocumentRequest("http://web__kit.org/test.html"), blockLoad); 808 testRequest(ifTopURL, mainDocumentRequest("http://webk__it.org/test.html"), { }); 809 testRequest(ifTopURL, mainDocumentRequest("http://web__kit.org/test.not_html"), { }); 810 testRequest(ifTopURL, mainDocumentRequest("http://not_webkit.org/test.html"), { }); 811 testRequest(ifTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://webkit.org/not_test.html"), blockLoad); 812 testRequest(ifTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://not_webkit.org/not_test.html"), { }); 813 testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/not_test.html"), { }); 814 testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/test.html"), { }); 815 testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://webkit.org/test.html"), blockLoad); 816 testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://example.com/#http://webkit.org/test.html"), { }); 817 testRequest(ifTopURL, subResourceRequest("http://example.com/#http://webkit.org/test.html", "http://webkit.org/test.html"), blockLoad); 818 819 auto unlessTopURL = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\"^http://web.*kit.org\"]}}]"); 820 testRequest(unlessTopURL, mainDocumentRequest("http://webkit.org/test.html"), { }); 821 testRequest(unlessTopURL, mainDocumentRequest("http://WEBKIT.org/test.html"), { }); 822 testRequest(unlessTopURL, mainDocumentRequest("http://webkit.org/TEST.html"), { }); 823 testRequest(unlessTopURL, mainDocumentRequest("http://webkit.org/test.not_html"), { }); 824 testRequest(unlessTopURL, mainDocumentRequest("http://web__kit.org/test.html"), { }); 825 testRequest(unlessTopURL, mainDocumentRequest("http://webk__it.org/test.html"), blockLoad); 826 testRequest(unlessTopURL, mainDocumentRequest("http://web__kit.org/test.not_html"), { }); 827 testRequest(unlessTopURL, mainDocumentRequest("http://not_webkit.org/test.html"), blockLoad); 828 testRequest(unlessTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://webkit.org/not_test.html"), { }); 829 testRequest(unlessTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://not_webkit.org/not_test.html"), blockLoad); 830 testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/not_test.html"), blockLoad); 831 testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/test.html"), blockLoad); 832 testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://webkit.org/test.html"), { }); 833 testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://example.com/#http://webkit.org/test.html"), blockLoad); 834 testRequest(unlessTopURL, subResourceRequest("http://example.com/#http://webkit.org/test.html", "http://webkit.org/test.html"), { }); 835 836 auto ifTopURLMatchesEverything = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\".*\"]}}]"); 837 testRequest(ifTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.html"), blockLoad); 838 testRequest(ifTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.not_html"), { }); 839 testRequest(ifTopURLMatchesEverything, mainDocumentRequest("http://not_webkit.org/test.html"), blockLoad); 840 841 auto unlessTopURLMatchesEverything = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\".*\"]}}]"); 842 testRequest(unlessTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.html"), { }); 843 testRequest(unlessTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.not_html"), { }); 844 testRequest(unlessTopURLMatchesEverything, mainDocumentRequest("http://not_webkit.org/test.html"), { }); 845 846 auto mixedConditions = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org\"]}}," 847 "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"resource-type\":[\"document\"], \"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\"^http://web.*kit.org\"]}}]"); 848 testRequest(mixedConditions, mainDocumentRequest("http://webkit.org/test.html"), blockLoad); 849 testRequest(mixedConditions, mainDocumentRequest("http://not_webkit.org/test.html"), blockCookies); 850 testRequest(mixedConditions, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org", ResourceType::Document), blockCookies); 851 testRequest(mixedConditions, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org", ResourceType::Image), { }); 852 853 auto caseSensitive = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org/test\"], \"top-url-filter-is-case-sensitive\":true}}]"); 854 testRequest(caseSensitive, mainDocumentRequest("http://webkit.org/test.html"), blockLoad); 855 testRequest(caseSensitive, mainDocumentRequest("http://WEBKIT.org/test.html"), blockLoad); // domains are canonicalized before running regexes. 856 testRequest(caseSensitive, mainDocumentRequest("http://webkit.org/TEST.html"), { }); 857 858 auto caseInsensitive = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org/test\"]}}]"); 859 testRequest(caseInsensitive, mainDocumentRequest("http://webkit.org/test.html"), blockLoad); 860 testRequest(caseInsensitive, mainDocumentRequest("http://webkit.org/TEST.html"), blockLoad); 792 861 } 793 862 … … 1365 1434 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[\"}}]", 1366 1435 ContentExtensions::ContentExtensionError::JSONInvalidRegex); 1436 1437 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions); 1438 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"],\"unless-top-url\":[]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions); 1439 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"],\"unless-top-url\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions); 1440 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"if-top-url\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions); 1441 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions); 1442 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"],\"if-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions); 1443 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"]}}, {\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONTopURLAndDomainConditions); 1444 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"]}}, {\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONTopURLAndDomainConditions); 1445 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\"[\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidRegex); 1446 checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\", \"unexpected-identifier-should-be-ignored\":5}}]", { }); 1367 1447 } 1368 1448
Note: See TracChangeset
for help on using the changeset viewer.