Move URL from WebCore to WTF
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebCore / ContentExtensions.cpp
1 /*
2  * Copyright (C) 2015 Apple 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 APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #include "PlatformUtilities.h"
29 #include <JavaScriptCore/InitializeThreading.h>
30 #include <WebCore/CombinedURLFilters.h>
31 #include <WebCore/ContentExtensionCompiler.h>
32 #include <WebCore/ContentExtensionError.h>
33 #include <WebCore/ContentExtensionParser.h>
34 #include <WebCore/ContentExtensionsBackend.h>
35 #include <WebCore/DFA.h>
36 #include <WebCore/DFABytecodeCompiler.h>
37 #include <WebCore/DFABytecodeInterpreter.h>
38 #include <WebCore/NFA.h>
39 #include <WebCore/NFAToDFA.h>
40 #include <WebCore/ResourceLoadInfo.h>
41 #include <WebCore/URLFilterParser.h>
42 #include <wtf/MainThread.h>
43 #include <wtf/RunLoop.h>
44 #include <wtf/URL.h>
45 #include <wtf/text/CString.h>
46 #include <wtf/text/StringBuilder.h>
47
48 namespace WebCore {
49 namespace ContentExtensions {
50 inline std::ostream& operator<<(std::ostream& os, const ActionType& action)
51 {
52     switch (action) {
53     case ActionType::BlockLoad:
54         return os << "ActionType::BlockLoad";
55     case ActionType::BlockCookies:
56         return os << "ActionType::BlockCookies";
57     case ActionType::CSSDisplayNoneSelector:
58         return os << "ActionType::CSSDisplayNone";
59     case ActionType::Notify:
60         return os << "ActionType::Notify";
61     case ActionType::IgnorePreviousRules:
62         return os << "ActionType::IgnorePreviousRules";
63     case ActionType::MakeHTTPS:
64         return os << "ActionType::MakeHTTPS";
65     }
66 }
67 }
68 }
69
70 using namespace WebCore;
71
72 namespace TestWebKitAPI {
73
74 class ContentExtensionTest : public testing::Test {
75 public:
76     virtual void SetUp()
77     {
78         JSC::initializeThreading();
79         RunLoop::initializeMainRunLoop();
80     }
81 };
82
83 struct CompiledContentExtensionData {
84     Vector<ContentExtensions::SerializedActionByte> actions;
85     Vector<ContentExtensions::DFABytecode> filtersWithoutConditions;
86     Vector<ContentExtensions::DFABytecode> filtersWithConditions;
87     Vector<ContentExtensions::DFABytecode> topURLFilters;
88     bool conditionsApplyOnlyToDomain { false };
89 };
90
91 class InMemoryContentExtensionCompilationClient final : public ContentExtensions::ContentExtensionCompilationClient {
92 public:
93     InMemoryContentExtensionCompilationClient(CompiledContentExtensionData& data)
94         : m_data(data)
95     {
96         EXPECT_EQ(data.actions.size(), 0ull);
97         EXPECT_EQ(data.filtersWithoutConditions.size(), 0ull);
98         EXPECT_EQ(data.filtersWithConditions.size(), 0ull);
99         EXPECT_EQ(data.topURLFilters.size(), 0ull);
100     }
101
102 private:
103     void writeSource(String&&) final { }
104
105     void writeActions(Vector<ContentExtensions::SerializedActionByte>&& actions, bool conditionsApplyOnlyToDomain) final
106     {
107         EXPECT_FALSE(finalized);
108         EXPECT_EQ(m_data.actions.size(), 0ull);
109         EXPECT_EQ(m_data.filtersWithoutConditions.size(), 0ull);
110         EXPECT_EQ(m_data.filtersWithConditions.size(), 0ull);
111         EXPECT_EQ(m_data.topURLFilters.size(), 0ull);
112         EXPECT_EQ(m_data.actions.size(), 0ull);
113         m_data.actions.appendVector(actions);
114         m_data.conditionsApplyOnlyToDomain = conditionsApplyOnlyToDomain;
115     }
116     
117     void writeFiltersWithoutConditionsBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) final
118     {
119         EXPECT_FALSE(finalized);
120         EXPECT_EQ(m_data.filtersWithConditions.size(), 0ull);
121         EXPECT_EQ(m_data.topURLFilters.size(), 0ull);
122         m_data.filtersWithoutConditions.appendVector(bytecode);
123     }
124     
125     void writeFiltersWithConditionsBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) final
126     {
127         EXPECT_FALSE(finalized);
128         EXPECT_EQ(m_data.topURLFilters.size(), 0ull);
129         m_data.filtersWithConditions.appendVector(bytecode);
130     }
131     
132     void writeTopURLFiltersBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) final
133     {
134         EXPECT_FALSE(finalized);
135         m_data.topURLFilters.appendVector(bytecode);
136     }
137     
138     void finalize() final
139     {
140         finalized = true;
141     }
142
143     CompiledContentExtensionData& m_data;
144     bool finalized { false };
145 };
146
147 class InMemoryCompiledContentExtension : public ContentExtensions::CompiledContentExtension {
148 public:
149     static Ref<InMemoryCompiledContentExtension> create(String&& filter)
150     {
151         CompiledContentExtensionData extensionData;
152         InMemoryContentExtensionCompilationClient client(extensionData);
153         auto parsedRules = ContentExtensions::parseRuleList(filter);
154         auto compilerError = ContentExtensions::compileRuleList(client, WTFMove(filter), WTFMove(parsedRules.value()));
155
156         // Compiling should always succeed here. We have other tests for compile failures.
157         EXPECT_FALSE(compilerError);
158
159         return adoptRef(*new InMemoryCompiledContentExtension(WTFMove(extensionData)));
160     }
161
162     const CompiledContentExtensionData& data() { return m_data; };
163
164 private:
165     const ContentExtensions::SerializedActionByte* actions() const final { return m_data.actions.data(); }
166     unsigned actionsLength() const final { return m_data.actions.size(); }
167     const ContentExtensions::DFABytecode* filtersWithoutConditionsBytecode() const final { return m_data.filtersWithoutConditions.data(); }
168     unsigned filtersWithoutConditionsBytecodeLength() const final { return m_data.filtersWithoutConditions.size(); }
169     const ContentExtensions::DFABytecode* filtersWithConditionsBytecode() const final { return m_data.filtersWithConditions.data(); }
170     unsigned filtersWithConditionsBytecodeLength() const final { return m_data.filtersWithConditions.size(); }
171     const ContentExtensions::DFABytecode* topURLFiltersBytecode() const final { return m_data.topURLFilters.data(); }
172     unsigned topURLFiltersBytecodeLength() const final { return m_data.topURLFilters.size(); }
173     bool conditionsApplyOnlyToDomain() const final { return m_data.conditionsApplyOnlyToDomain; }
174
175     InMemoryCompiledContentExtension(CompiledContentExtensionData&& data)
176         : m_data(WTFMove(data))
177     { }
178
179     CompiledContentExtensionData m_data;
180 };
181
182 void static testRequest(const ContentExtensions::ContentExtensionsBackend& contentExtensionsBackend, const ResourceLoadInfo& resourceLoadInfo, Vector<ContentExtensions::ActionType> expectedActions, size_t stylesheets = 1)
183 {
184     auto actions = contentExtensionsBackend.actionsForResourceLoad(resourceLoadInfo);
185     unsigned expectedSize = actions.first.size();
186     EXPECT_EQ(expectedActions.size(), expectedSize);
187     if (expectedActions.size() != expectedSize)
188         return;
189
190     for (unsigned i = 0; i < expectedActions.size(); ++i)
191         EXPECT_EQ(expectedActions[i], actions.first[i].type());
192     EXPECT_EQ(actions.second.size(), stylesheets);
193 }
194
195 static ResourceLoadInfo mainDocumentRequest(const char* url, ResourceType resourceType = ResourceType::Document)
196 {
197     return { URL(URL(), url), URL(URL(), url), resourceType };
198 }
199
200 static ResourceLoadInfo subResourceRequest(const char* url, const char* mainDocumentURL, ResourceType resourceType = ResourceType::Document)
201 {
202     return { URL(URL(), url), URL(URL(), mainDocumentURL), resourceType };
203 }
204
205 ContentExtensions::ContentExtensionsBackend makeBackend(const char* json)
206 {
207     AtomicString::init();
208     auto extension = InMemoryCompiledContentExtension::create(json);
209     ContentExtensions::ContentExtensionsBackend backend;
210     backend.addContentExtension("testFilter", WTFMove(extension));
211     return backend;
212 }
213
214 static Vector<ContentExtensions::NFA> createNFAs(ContentExtensions::CombinedURLFilters& combinedURLFilters)
215 {
216     Vector<ContentExtensions::NFA> nfas;
217
218     combinedURLFilters.processNFAs(std::numeric_limits<size_t>::max(), [&](ContentExtensions::NFA&& nfa) {
219         nfas.append(WTFMove(nfa));
220     });
221
222     return nfas;
223 }
224
225 TEST_F(ContentExtensionTest, Basic)
226 {
227     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]");
228
229     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
230 }
231
232 TEST_F(ContentExtensionTest, SingleCharacter)
233 {
234     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^z\"}}]");
235     testRequest(matchBackend, mainDocumentRequest("http://webkit.org/"), { });
236     testRequest(matchBackend, mainDocumentRequest("zttp://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
237
238     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"y\"}}]");
239     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/"), { });
240     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/ywebkit"), { ContentExtensions::ActionType::BlockLoad });
241 }
242
243 TEST_F(ContentExtensionTest, SingleCharacterDisjunction)
244 {
245     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^z\"}},"
246         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^c\"}}]");
247     testRequest(matchBackend, mainDocumentRequest("http://webkit.org/"), { });
248     testRequest(matchBackend, mainDocumentRequest("bttp://webkit.org/"), { });
249     testRequest(matchBackend, mainDocumentRequest("cttp://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
250     testRequest(matchBackend, mainDocumentRequest("dttp://webkit.org/"), { });
251     testRequest(matchBackend, mainDocumentRequest("zttp://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
252
253     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"x\"}},"
254         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"y\"}}]");
255     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/"), { });
256     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/dwebkit"), { });
257     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/xwebkit"), { ContentExtensions::ActionType::BlockLoad });
258     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/ywebkit"), { ContentExtensions::ActionType::BlockLoad });
259     testRequest(searchBackend, mainDocumentRequest("http://webkit.org/zwebkit"), { });
260 }
261
262 TEST_F(ContentExtensionTest, RangeBasic)
263 {
264     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"w[0-9]c\", \"url-filter-is-case-sensitive\":true}},"
265         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"[A-H][a-z]cko\", \"url-filter-is-case-sensitive\":true}}]");
266
267     testRequest(backend, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::BlockLoad });
268     testRequest(backend, mainDocumentRequest("w2c://whatwg.org/"), { ContentExtensions::ActionType::BlockLoad });
269     testRequest(backend, mainDocumentRequest("http://webkit.org/w0c"), { ContentExtensions::ActionType::BlockLoad });
270     testRequest(backend, mainDocumentRequest("http://webkit.org/wac"), { });
271     testRequest(backend, mainDocumentRequest("http://webkit.org/wAc"), { });
272
273     // Note: URL parsing and canonicalization lowercase the scheme and hostname.
274     testRequest(backend, mainDocumentRequest("Aacko://webkit.org"), { });
275     testRequest(backend, mainDocumentRequest("aacko://webkit.org"), { });
276     testRequest(backend, mainDocumentRequest("http://gCcko.org/"), { });
277     testRequest(backend, mainDocumentRequest("http://gccko.org/"), { });
278
279     testRequest(backend, mainDocumentRequest("http://webkit.org/Gecko"), { ContentExtensions::ActionType::BlockCookies });
280     testRequest(backend, mainDocumentRequest("http://webkit.org/gecko"), { });
281     testRequest(backend, mainDocumentRequest("http://webkit.org/GEcko"), { });
282 }
283
284 TEST_F(ContentExtensionTest, RangeExclusionGeneratingUniversalTransition)
285 {
286     // Transition of the type ([^X]X) effictively transition on every input.
287     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[^a]+afoobar\"}}]");
288
289     testRequest(backend, mainDocumentRequest("http://w3c.org"), { });
290
291     testRequest(backend, mainDocumentRequest("http://w3c.org/foobafoobar"), { ContentExtensions::ActionType::BlockLoad });
292     testRequest(backend, mainDocumentRequest("http://w3c.org/foobarfoobar"), { });
293     testRequest(backend, mainDocumentRequest("http://w3c.org/FOOBAFOOBAR"), { ContentExtensions::ActionType::BlockLoad });
294     testRequest(backend, mainDocumentRequest("http://w3c.org/FOOBARFOOBAR"), { });
295
296     // The character before the "a" prefix cannot be another "a".
297     testRequest(backend, mainDocumentRequest("http://w3c.org/aafoobar"), { });
298     testRequest(backend, mainDocumentRequest("http://w3c.org/Aafoobar"), { });
299     testRequest(backend, mainDocumentRequest("http://w3c.org/aAfoobar"), { });
300     testRequest(backend, mainDocumentRequest("http://w3c.org/AAfoobar"), { });
301 }
302
303 TEST_F(ContentExtensionTest, PatternStartingWithGroup)
304 {
305     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(http://whatwg\\\\.org/)?webkit\134\134.org\"}}]");
306
307     testRequest(backend, mainDocumentRequest("http://whatwg.org/webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
308     testRequest(backend, mainDocumentRequest("http://whatwg.org/webkit.org"), { ContentExtensions::ActionType::BlockLoad });
309     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
310     testRequest(backend, mainDocumentRequest("http://whatwg.org/"), { });
311     testRequest(backend, mainDocumentRequest("http://whatwg.org"), { });
312 }
313
314 TEST_F(ContentExtensionTest, PatternNestedGroups)
315 {
316     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/(foo(bar)*)+\"}}]");
317
318     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
319     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
320     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarbar"), { ContentExtensions::ActionType::BlockLoad });
321     testRequest(backend, mainDocumentRequest("http://webkit.org/foofoobar"), { ContentExtensions::ActionType::BlockLoad });
322     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
323     testRequest(backend, mainDocumentRequest("http://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
324     testRequest(backend, mainDocumentRequest("http://webkit.org/foor"), { ContentExtensions::ActionType::BlockLoad });
325
326     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
327     testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
328     testRequest(backend, mainDocumentRequest("http://webkit.org/fobar"), { });
329 }
330
331 TEST_F(ContentExtensionTest, EmptyGroups)
332 {
333     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/foo()bar\"}},"
334         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/((me)()(too))\"}}]");
335     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { });
336     testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
337     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
338     testRequest(backend, mainDocumentRequest("http://webkit.org/me"), { });
339     testRequest(backend, mainDocumentRequest("http://webkit.org/too"), { });
340     testRequest(backend, mainDocumentRequest("http://webkit.org/metoo"), { ContentExtensions::ActionType::BlockLoad });
341     testRequest(backend, mainDocumentRequest("http://webkit.org/foome"), { });
342     testRequest(backend, mainDocumentRequest("http://webkit.org/foomebar"), { });
343     testRequest(backend, mainDocumentRequest("http://webkit.org/mefoo"), { });
344     testRequest(backend, mainDocumentRequest("http://webkit.org/mefootoo"), { });
345 }
346
347 TEST_F(ContentExtensionTest, QuantifiedEmptyGroups)
348 {
349     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/foo()+bar\"}},"
350         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/(()*()?(target)()+)\"}}]");
351     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { });
352     testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
353     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
354     testRequest(backend, mainDocumentRequest("http://webkit.org/me"), { });
355     testRequest(backend, mainDocumentRequest("http://webkit.org/too"), { });
356     testRequest(backend, mainDocumentRequest("http://webkit.org/target"), { ContentExtensions::ActionType::BlockLoad });
357     testRequest(backend, mainDocumentRequest("http://webkit.org/foome"), { });
358     testRequest(backend, mainDocumentRequest("http://webkit.org/foomebar"), { });
359     testRequest(backend, mainDocumentRequest("http://webkit.org/mefoo"), { });
360     testRequest(backend, mainDocumentRequest("http://webkit.org/mefootoo"), { });
361 }
362
363 TEST_F(ContentExtensionTest, MatchPastEndOfString)
364 {
365     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".+\"}}]");
366
367     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
368     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
369     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
370     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarbar"), { ContentExtensions::ActionType::BlockLoad });
371     testRequest(backend, mainDocumentRequest("http://webkit.org/foofoobar"), { ContentExtensions::ActionType::BlockLoad });
372     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
373     testRequest(backend, mainDocumentRequest("http://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
374     testRequest(backend, mainDocumentRequest("http://webkit.org/foor"), { ContentExtensions::ActionType::BlockLoad });
375 }
376
377 TEST_F(ContentExtensionTest, StartOfLineAssertion)
378 {
379     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^foobar\"}}]");
380
381     testRequest(backend, mainDocumentRequest("foobar://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
382     testRequest(backend, mainDocumentRequest("foobars:///foobar"), { ContentExtensions::ActionType::BlockLoad });
383     testRequest(backend, mainDocumentRequest("foobarfoobar:///foobarfoobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
384
385     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoo"), { });
386     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarf"), { });
387     testRequest(backend, mainDocumentRequest("http://foobar.org/"), { });
388     testRequest(backend, mainDocumentRequest("http://foobar.org/"), { });
389 }
390
391 TEST_F(ContentExtensionTest, EndOfLineAssertion)
392 {
393     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foobar$\"}}]");
394
395     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
396     testRequest(backend, mainDocumentRequest("file:///foobar"), { ContentExtensions::ActionType::BlockLoad });
397     testRequest(backend, mainDocumentRequest("file:///foobarfoobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
398
399     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoo"), { });
400     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarf"), { });
401 }
402
403 TEST_F(ContentExtensionTest, EndOfLineAssertionWithInvertedCharacterSet)
404 {
405     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[^y]$\"}}]");
406
407     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
408     testRequest(backend, mainDocumentRequest("http://webkit.org/a"), { ContentExtensions::ActionType::BlockLoad });
409     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
410     testRequest(backend, mainDocumentRequest("http://webkit.org/Ya"), { ContentExtensions::ActionType::BlockLoad });
411     testRequest(backend, mainDocumentRequest("http://webkit.org/yFoobar"), { ContentExtensions::ActionType::BlockLoad });
412     testRequest(backend, mainDocumentRequest("http://webkit.org/y"), { });
413     testRequest(backend, mainDocumentRequest("http://webkit.org/Y"), { });
414     testRequest(backend, mainDocumentRequest("http://webkit.org/foobary"), { });
415     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarY"), { });
416 }
417
418 TEST_F(ContentExtensionTest, DotDoesNotIncludeEndOfLine)
419 {
420     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"https://webkit\\\\.org/.\"}}]");
421
422     testRequest(backend, mainDocumentRequest("https://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
423     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
424     testRequest(backend, mainDocumentRequest("https://webkit.org/A"), { ContentExtensions::ActionType::BlockLoad });
425     testRequest(backend, mainDocumentRequest("https://webkit.org/z"), { ContentExtensions::ActionType::BlockLoad });
426 }
427
428 TEST_F(ContentExtensionTest, PrefixInfixSuffixExactMatch)
429 {
430     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"infix\"}},"
431         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^prefix\"}},"
432         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"suffix$\"}},"
433         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://exact\\\\.org/$\"}}]");
434
435     testRequest(backend, mainDocumentRequest("infix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
436     testRequest(backend, mainDocumentRequest("http://infix.org/"), { ContentExtensions::ActionType::BlockLoad });
437     testRequest(backend, mainDocumentRequest("https://webkit.org/infix"), { ContentExtensions::ActionType::BlockLoad });
438
439     testRequest(backend, mainDocumentRequest("prefix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
440     testRequest(backend, mainDocumentRequest("https://prefix.org/"), { });
441     testRequest(backend, mainDocumentRequest("https://webkit.org/prefix"), { });
442
443     testRequest(backend, mainDocumentRequest("https://webkit.org/suffix"), { ContentExtensions::ActionType::BlockLoad });
444     testRequest(backend, mainDocumentRequest("https://suffix.org/"), { });
445     testRequest(backend, mainDocumentRequest("suffix://webkit.org/"), { });
446
447     testRequest(backend, mainDocumentRequest("http://exact.org/"), { ContentExtensions::ActionType::BlockLoad });
448     testRequest(backend, mainDocumentRequest("http://exact.org/oops"), { });
449 }
450
451 TEST_F(ContentExtensionTest, DuplicatedMatchAllTermsInVariousFormat)
452 {
453     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*.*(.)*(.*)(.+)*(.?)*infix\"}},"
454         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"pre(.?)+(.+)?post\"}}]");
455
456     testRequest(backend, mainDocumentRequest("infix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
457     testRequest(backend, mainDocumentRequest("http://infix.org/"), { ContentExtensions::ActionType::BlockLoad });
458     testRequest(backend, mainDocumentRequest("https://webkit.org/infix"), { ContentExtensions::ActionType::BlockLoad });
459
460     testRequest(backend, mainDocumentRequest("pre://webkit.org/post"), { ContentExtensions::ActionType::BlockLoad });
461     testRequest(backend, mainDocumentRequest("http://prepost.org/"), { ContentExtensions::ActionType::BlockLoad });
462     testRequest(backend, mainDocumentRequest("https://pre.org/posttail"), { ContentExtensions::ActionType::BlockLoad });
463     testRequest(backend, mainDocumentRequest("https://pre.pre/posttail"), { ContentExtensions::ActionType::BlockLoad });
464     testRequest(backend, mainDocumentRequest("https://pre.org/posttailpost"), { ContentExtensions::ActionType::BlockLoad });
465
466     testRequest(backend, mainDocumentRequest("https://post.org/pre"), { });
467     testRequest(backend, mainDocumentRequest("https://pre.org/pre"), { });
468     testRequest(backend, mainDocumentRequest("https://post.org/post"), { });
469 }
470
471 TEST_F(ContentExtensionTest, UndistinguishableActionInsidePrefixTree)
472 {
473     // In this case, the two actions are undistinguishable. The actions of "prefix" appear inside the prefixtree
474     // ending at "suffix".
475     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"prefix\"}},"
476         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"prefixsuffix\"}}]");
477
478     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
479     testRequest(backend, mainDocumentRequest("http://prefix.org/"), { ContentExtensions::ActionType::BlockLoad });
480     testRequest(backend, mainDocumentRequest("http://webkit.org/prefix"), { ContentExtensions::ActionType::BlockLoad });
481     testRequest(backend, mainDocumentRequest("http://webkit.org/aaaprefixaaa"), { ContentExtensions::ActionType::BlockLoad });
482     testRequest(backend, mainDocumentRequest("http://prefixsuffix.org/"), { ContentExtensions::ActionType::BlockLoad });
483     testRequest(backend, mainDocumentRequest("http://webkit.org/prefixsuffix"), { ContentExtensions::ActionType::BlockLoad });
484     testRequest(backend, mainDocumentRequest("http://webkit.org/bbbprefixsuffixbbb"), { ContentExtensions::ActionType::BlockLoad });
485
486     testRequest(backend, mainDocumentRequest("http://suffix.org/"), { });
487     testRequest(backend, mainDocumentRequest("http://webkit.org/suffix"), { });
488 }
489
490 TEST_F(ContentExtensionTest, DistinguishableActionInsidePrefixTree)
491 {
492     // In this case, the two actions are distinguishable.
493     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"prefix\"}},"
494         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"prefixsuffix\"}}]");
495
496     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
497     testRequest(backend, mainDocumentRequest("http://prefix.org/"), { ContentExtensions::ActionType::BlockLoad });
498     testRequest(backend, mainDocumentRequest("http://webkit.org/prefix"), { ContentExtensions::ActionType::BlockLoad });
499     testRequest(backend, mainDocumentRequest("http://webkit.org/aaaprefixaaa"), { ContentExtensions::ActionType::BlockLoad });
500     testRequest(backend, mainDocumentRequest("http://prefixsuffix.org/"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
501     testRequest(backend, mainDocumentRequest("http://webkit.org/prefixsuffix"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
502     testRequest(backend, mainDocumentRequest("http://webkit.org/bbbprefixsuffixbbb"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
503
504     testRequest(backend, mainDocumentRequest("http://suffix.org/"), { });
505     testRequest(backend, mainDocumentRequest("http://webkit.org/suffix"), { });
506 }
507
508 TEST_F(ContentExtensionTest, DistinguishablePrefixAreNotMerged)
509 {
510     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foo\\\\.org\"}},"
511         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar\\\\.org\"}}]");
512
513     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
514     testRequest(backend, mainDocumentRequest("http://foo.org/"), { ContentExtensions::ActionType::BlockLoad });
515     testRequest(backend, mainDocumentRequest("http://bar.org/"), { ContentExtensions::ActionType::BlockLoad });
516
517     testRequest(backend, mainDocumentRequest("http://foor.org/"), { });
518     testRequest(backend, mainDocumentRequest("http://fooar.org/"), { });
519     testRequest(backend, mainDocumentRequest("http://fooba.org/"), { });
520     testRequest(backend, mainDocumentRequest("http://foob.org/"), { });
521     testRequest(backend, mainDocumentRequest("http://foor.org/"), { });
522     testRequest(backend, mainDocumentRequest("http://foar.org/"), { });
523     testRequest(backend, mainDocumentRequest("http://foba.org/"), { });
524     testRequest(backend, mainDocumentRequest("http://fob.org/"), { });
525     testRequest(backend, mainDocumentRequest("http://barf.org/"), { });
526     testRequest(backend, mainDocumentRequest("http://barfo.org/"), { });
527     testRequest(backend, mainDocumentRequest("http://baroo.org/"), { });
528     testRequest(backend, mainDocumentRequest("http://baro.org/"), { });
529     testRequest(backend, mainDocumentRequest("http://baf.org/"), { });
530     testRequest(backend, mainDocumentRequest("http://bafo.org/"), { });
531     testRequest(backend, mainDocumentRequest("http://baoo.org/"), { });
532     testRequest(backend, mainDocumentRequest("http://bao.org/"), { });
533
534     testRequest(backend, mainDocumentRequest("http://foo.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
535     testRequest(backend, mainDocumentRequest("http://oo.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
536     testRequest(backend, mainDocumentRequest("http://o.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
537     testRequest(backend, mainDocumentRequest("http://.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
538     testRequest(backend, mainDocumentRequest("http://rgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
539     testRequest(backend, mainDocumentRequest("http://gbar.org/"), { ContentExtensions::ActionType::BlockLoad });
540     testRequest(backend, mainDocumentRequest("http://foo.orgar.org/"), { ContentExtensions::ActionType::BlockLoad });
541     testRequest(backend, mainDocumentRequest("http://foo.orgr.org/"), { ContentExtensions::ActionType::BlockLoad });
542     testRequest(backend, mainDocumentRequest("http://foo.org.org/"), { ContentExtensions::ActionType::BlockLoad });
543     testRequest(backend, mainDocumentRequest("http://foo.orgorg/"), { ContentExtensions::ActionType::BlockLoad });
544     testRequest(backend, mainDocumentRequest("http://foo.orgrg/"), { ContentExtensions::ActionType::BlockLoad });
545     testRequest(backend, mainDocumentRequest("http://foo.orgg/"), { ContentExtensions::ActionType::BlockLoad });
546 }
547
548 static void compareContents(const ContentExtensions::DFABytecodeInterpreter::Actions& a, const Vector<uint64_t>& b)
549 {
550     EXPECT_EQ(a.size(), b.size());
551     for (unsigned i = 0; i < b.size(); ++i)
552         EXPECT_TRUE(a.contains(b[i]));
553 }
554
555 TEST_F(ContentExtensionTest, SearchSuffixesWithIdenticalActionAreMerged)
556 {
557     ContentExtensions::CombinedURLFilters combinedURLFilters;
558     ContentExtensions::URLFilterParser parser(combinedURLFilters);
559     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("foo\\.org", false, 0));
560     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("ba\\.org", false, 0));
561
562     Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
563     EXPECT_EQ(1ul, nfas.size());
564     EXPECT_EQ(12ul, nfas.first().nodes.size());
565
566     ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first());
567     Vector<ContentExtensions::DFABytecode> bytecode;
568     ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
569     compiler.compile();
570     ContentExtensions::DFABytecodeInterpreter interpreter(bytecode.data(), bytecode.size());
571     compareContents(interpreter.interpret("foo.org", 0), { 0 });
572     compareContents(interpreter.interpret("ba.org", 0), { 0 });
573     compareContents(interpreter.interpret("bar.org", 0), { });
574
575     compareContents(interpreter.interpret("paddingfoo.org", 0), { 0 });
576     compareContents(interpreter.interpret("paddingba.org", 0), { 0 });
577     compareContents(interpreter.interpret("paddingbar.org", 0), { });
578 }
579
580 TEST_F(ContentExtensionTest, SearchSuffixesWithDistinguishableActionAreNotMerged)
581 {
582     ContentExtensions::CombinedURLFilters combinedURLFilters;
583     ContentExtensions::URLFilterParser parser(combinedURLFilters);
584     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("foo\\.org", false, 0));
585     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("ba\\.org", false, 1));
586
587     Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
588
589     EXPECT_EQ(1ul, nfas.size());
590     EXPECT_EQ(17ul, nfas.first().nodes.size());
591
592     ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first());
593     Vector<ContentExtensions::DFABytecode> bytecode;
594     ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
595     compiler.compile();
596     ContentExtensions::DFABytecodeInterpreter interpreter(bytecode.data(), bytecode.size());
597     compareContents(interpreter.interpret("foo.org", 0), { 0 });
598     compareContents(interpreter.interpret("ba.org", 0), { 1 });
599     compareContents(interpreter.interpret("bar.org", 0), { });
600
601     compareContents(interpreter.interpret("paddingfoo.org", 0), { 0 });
602     compareContents(interpreter.interpret("paddingba.org", 0), { 1 });
603     compareContents(interpreter.interpret("paddingba.orgfoo.org", 0), { 1, 0 });
604     compareContents(interpreter.interpret("paddingbar.org", 0), { });
605 }
606
607 TEST_F(ContentExtensionTest, DomainTriggers)
608 {
609     auto ifDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\"]}}]");
610     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
611     testRequest(ifDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
612     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
613     testRequest(ifDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
614     testRequest(ifDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
615     testRequest(ifDomainBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
616     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
617     testRequest(ifDomainBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
618     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.organization/test.html"), { });
619     
620     auto unlessDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"webkit.org\"]}}]");
621     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
622     testRequest(unlessDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
623     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
624     testRequest(unlessDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
625     testRequest(unlessDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
626     testRequest(unlessDomainBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
627     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
628     testRequest(unlessDomainBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
629     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.organization/test.html"), { ContentExtensions::ActionType::BlockLoad });
630     
631     auto ifDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"*webkit.org\"]}}]");
632     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
633     testRequest(ifDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
634     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
635     testRequest(ifDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
636     testRequest(ifDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
637     testRequest(ifDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
638     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
639     testRequest(ifDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
640     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.html"), { });
641     
642     auto unlessDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"*webkit.org\"]}}]");
643     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
644     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
645     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
646     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
647     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
648     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
649     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
650     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
651     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.html"), { ContentExtensions::ActionType::BlockLoad });
652
653     auto ifSubDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"sub1.webkit.org\"]}}]");
654     testRequest(ifSubDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
655     testRequest(ifSubDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
656     testRequest(ifSubDomainBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
657     testRequest(ifSubDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
658
659     auto ifSubDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"*sub1.webkit.org\"]}}]");
660     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
661     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
662     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
663     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
664
665     auto unlessSubDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"sub1.webkit.org\"]}}]");
666     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
667     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
668     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { });
669     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
670     
671     auto unlessSubDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"*sub1.webkit.org\"]}}]");
672     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
673     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
674     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { });
675     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
676
677     auto combinedBackend1 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test_block_load\", \"if-domain\":[\"webkit.org\"]}},"
678         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test_block_cookies\", \"unless-domain\":[\"webkit.org\"]}}]");
679     testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org"), { });
680     testRequest(combinedBackend1, mainDocumentRequest("http://not_webkit.org"), { });
681     testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org/test_block_load.html"), { ContentExtensions::ActionType::BlockLoad });
682     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_load.html", "http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
683     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://webkit.org/"), { });
684     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_load.html", "http://not_webkit.org/"), { });
685     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://not_webkit.org/"), { });
686     testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org/test_block_cookies.html"), { });
687     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_cookies.html", "http://webkit.org/"), { });
688     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://webkit.org/"), { });
689     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_cookies.html", "http://not_webkit.org/path/to/main/document.html"), { ContentExtensions::ActionType::BlockCookies });
690     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://not_webkit.org/"), { });
691     
692     auto combinedBackend2 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test_block_load\\\\.html\", \"if-domain\":[\"webkit.org\"]}},"
693         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test_block_cookies\\\\.html\", \"unless-domain\":[\"w3c.org\"]}},"
694         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"test_css\\\\.html\"}}]");
695     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
696     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_css.htm"), { });
697     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_block_load.html"), { ContentExtensions::ActionType::BlockLoad });
698     testRequest(combinedBackend2, mainDocumentRequest("http://not_webkit.org/test_block_load.html"), { });
699     testRequest(combinedBackend2, mainDocumentRequest("http://not_webkit.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
700     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/TEST_CSS.hTmL/test_block_load.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad});
701     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
702     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_block_load.html"), { });
703     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_block_cookies.html"), { });
704     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_css.html/test_block_cookies.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
705     testRequest(combinedBackend2, mainDocumentRequest("http://not_w3c.org/test_block_cookies.html"), { ContentExtensions::ActionType::BlockCookies });
706     testRequest(combinedBackend2, mainDocumentRequest("http://not_w3c.org/test_css.html/test_block_cookies.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
707
708     auto ifDomainWithFlagsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\", \"if-domain\":[\"webkit.org\"],\"resource-type\":[\"image\"]}}]");
709     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
710     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.png", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
711     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
712     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.png", ResourceType::Image), { });
713
714     auto unlessDomainWithFlagsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\", \"unless-domain\":[\"webkit.org\"],\"resource-type\":[\"image\"]}}]");
715     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
716     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.png", ResourceType::Image), { });
717     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
718     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.png", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
719
720     // Domains should not be interepted as regular expressions.
721     auto domainRegexBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"we?bkit.org\"]}}]");
722     testRequest(domainRegexBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
723     testRequest(domainRegexBackend, mainDocumentRequest("http://wbkit.org/test.html"), { });
724     
725     auto multipleIfDomainsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\", \"w3c.org\"]}}]");
726     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
727     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
728     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://w3c.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
729     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://whatwg.org/test.html"), { });
730
731     auto multipleUnlessDomainsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"webkit.org\", \"w3c.org\"]}}]");
732     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
733     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
734     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://w3c.org/test.html"), { });
735     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://whatwg.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
736
737     // FIXME: Add and test domain-specific popup-only blocking (with layout tests).
738 }
739
740 TEST_F(ContentExtensionTest, DomainTriggersAlongMergedActions)
741 {
742     auto backend = makeBackend("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test\\\\.html\"}},"
743         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\"]}},"
744         "{\"action\":{\"type\":\"css-display-none\", \"selector\": \"*\"},\"trigger\":{\"url-filter\":\"trigger-on-scripts\\\\.html\",\"resource-type\":[\"script\"]}},"
745         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore-previous\",\"resource-type\":[\"image\"]}},"
746         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"except-this\"}}]");
747
748     testRequest(backend, mainDocumentRequest("http://webkit.org/test.htm"), { });
749     testRequest(backend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
750     testRequest(backend, mainDocumentRequest("http://notwebkit.org/test.html"), { ContentExtensions::ActionType::BlockCookies });
751
752     testRequest(backend, mainDocumentRequest("http://notwebkit.org/trigger-on-scripts.html"), { });
753     testRequest(backend, mainDocumentRequest("http://webkit.org/trigger-on-scripts.html"), { });
754     testRequest(backend, mainDocumentRequest("http://notwebkit.org/trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
755     testRequest(backend, mainDocumentRequest("http://webkit.org/trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
756     testRequest(backend, mainDocumentRequest("http://notwebkit.org/trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
757     testRequest(backend, mainDocumentRequest("http://webkit.org/trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
758
759     testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html"), { });
760     testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html"), { });
761     testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
762     testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
763     testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
764     testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
765
766     testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Image), { }, 0);
767     testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Image), { }, 0);
768     testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { }, 0);
769     testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { }, 0);
770
771     testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html"), { ContentExtensions::ActionType::BlockCookies });
772     testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html"), { ContentExtensions::ActionType::BlockCookies });
773     testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockCookies });
774     testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
775     testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, 0);
776     testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, 0);
777     testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, 0);
778     testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, 0);
779     testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector });
780     testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector });
781     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 });
782     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 });
783 }
784
785 TEST_F(ContentExtensionTest, TopURL)
786 {
787     const Vector<ContentExtensions::ActionType> blockLoad = { ContentExtensions::ActionType::BlockLoad };
788     const Vector<ContentExtensions::ActionType> blockCookies = { ContentExtensions::ActionType::BlockCookies };
789
790     auto ifTopURL = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org\"]}}]");
791     testRequest(ifTopURL, mainDocumentRequest("http://webkit.org/test.html"), blockLoad);
792     testRequest(ifTopURL, mainDocumentRequest("http://webkit.org/test.not_html"), { });
793     testRequest(ifTopURL, mainDocumentRequest("http://WEBKIT.org/test.html"), blockLoad);
794     testRequest(ifTopURL, mainDocumentRequest("http://webkit.org/TEST.html"), blockLoad);
795     testRequest(ifTopURL, mainDocumentRequest("http://web__kit.org/test.html"), blockLoad);
796     testRequest(ifTopURL, mainDocumentRequest("http://webk__it.org/test.html"), { });
797     testRequest(ifTopURL, mainDocumentRequest("http://web__kit.org/test.not_html"), { });
798     testRequest(ifTopURL, mainDocumentRequest("http://not_webkit.org/test.html"), { });
799     testRequest(ifTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://webkit.org/not_test.html"), blockLoad);
800     testRequest(ifTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://not_webkit.org/not_test.html"), { });
801     testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/not_test.html"), { });
802     testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/test.html"), { });
803     testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://webkit.org/test.html"), blockLoad);
804     testRequest(ifTopURL, subResourceRequest("http://webkit.org/test.html", "http://example.com/#http://webkit.org/test.html"), { });
805     testRequest(ifTopURL, subResourceRequest("http://example.com/#http://webkit.org/test.html", "http://webkit.org/test.html"), blockLoad);
806
807     auto unlessTopURL = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\"^http://web.*kit.org\"]}}]");
808     testRequest(unlessTopURL, mainDocumentRequest("http://webkit.org/test.html"), { });
809     testRequest(unlessTopURL, mainDocumentRequest("http://WEBKIT.org/test.html"), { });
810     testRequest(unlessTopURL, mainDocumentRequest("http://webkit.org/TEST.html"), { });
811     testRequest(unlessTopURL, mainDocumentRequest("http://webkit.org/test.not_html"), { });
812     testRequest(unlessTopURL, mainDocumentRequest("http://web__kit.org/test.html"), { });
813     testRequest(unlessTopURL, mainDocumentRequest("http://webk__it.org/test.html"), blockLoad);
814     testRequest(unlessTopURL, mainDocumentRequest("http://web__kit.org/test.not_html"), { });
815     testRequest(unlessTopURL, mainDocumentRequest("http://not_webkit.org/test.html"), blockLoad);
816     testRequest(unlessTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://webkit.org/not_test.html"), { });
817     testRequest(unlessTopURL, subResourceRequest("http://not_webkit.org/test.html", "http://not_webkit.org/not_test.html"), blockLoad);
818     testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/not_test.html"), blockLoad);
819     testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org/test.html"), blockLoad);
820     testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://webkit.org/test.html"), { });
821     testRequest(unlessTopURL, subResourceRequest("http://webkit.org/test.html", "http://example.com/#http://webkit.org/test.html"), blockLoad);
822     testRequest(unlessTopURL, subResourceRequest("http://example.com/#http://webkit.org/test.html", "http://webkit.org/test.html"), { });
823
824     auto ifTopURLMatchesEverything = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\".*\"]}}]");
825     testRequest(ifTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.html"), blockLoad);
826     testRequest(ifTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.not_html"), { });
827     testRequest(ifTopURLMatchesEverything, mainDocumentRequest("http://not_webkit.org/test.html"), blockLoad);
828     
829     auto unlessTopURLMatchesEverything = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\".*\"]}}]");
830     testRequest(unlessTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.html"), { });
831     testRequest(unlessTopURLMatchesEverything, mainDocumentRequest("http://webkit.org/test.not_html"), { });
832     testRequest(unlessTopURLMatchesEverything, mainDocumentRequest("http://not_webkit.org/test.html"), { });
833     
834     auto mixedConditions = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org\"]}},"
835         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"resource-type\":[\"document\"], \"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\"^http://web.*kit.org\"]}}]");
836     testRequest(mixedConditions, mainDocumentRequest("http://webkit.org/test.html"), blockLoad);
837     testRequest(mixedConditions, mainDocumentRequest("http://not_webkit.org/test.html"), blockCookies);
838     testRequest(mixedConditions, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org", ResourceType::Document), blockCookies);
839     testRequest(mixedConditions, subResourceRequest("http://webkit.org/test.html", "http://not_webkit.org", ResourceType::Image), { });
840
841     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}}]");
842     testRequest(caseSensitive, mainDocumentRequest("http://webkit.org/test.html"), blockLoad);
843     testRequest(caseSensitive, mainDocumentRequest("http://WEBKIT.org/test.html"), blockLoad); // domains are canonicalized before running regexes.
844     testRequest(caseSensitive, mainDocumentRequest("http://webkit.org/TEST.html"), { });
845
846     auto caseInsensitive = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-top-url\":[\"^http://web.*kit.org/test\"]}}]");
847     testRequest(caseInsensitive, mainDocumentRequest("http://webkit.org/test.html"), blockLoad);
848     testRequest(caseInsensitive, mainDocumentRequest("http://webkit.org/TEST.html"), blockLoad);
849 }
850
851 TEST_F(ContentExtensionTest, MultipleExtensions)
852 {
853     auto extension1 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}}]");
854     auto extension2 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}}]");
855     ContentExtensions::ContentExtensionsBackend backend;
856     backend.addContentExtension("testFilter1", WTFMove(extension1));
857     backend.addContentExtension("testFilter2", WTFMove(extension2));
858     
859     testRequest(backend, mainDocumentRequest("http://webkit.org"), { }, 2);
860     testRequest(backend, mainDocumentRequest("http://webkit.org/block_load.html"), { ContentExtensions::ActionType::BlockLoad }, 2);
861     testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies.html"), { ContentExtensions::ActionType::BlockCookies }, 2);
862     testRequest(backend, mainDocumentRequest("http://webkit.org/block_load/block_cookies.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad }, 2);
863     testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies/block_load.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad }, 2);
864     
865     auto ignoreExtension1 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}},"
866         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore1\"}}]");
867     auto ignoreExtension2 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}},"
868         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore2\"}}]");
869     ContentExtensions::ContentExtensionsBackend backendWithIgnore;
870     backendWithIgnore.addContentExtension("testFilter1", WTFMove(ignoreExtension1));
871     backendWithIgnore.addContentExtension("testFilter2", WTFMove(ignoreExtension2));
872
873     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org"), { }, 2);
874     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/ignore1.html"), { }, 1);
875     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore1.html"), { ContentExtensions::ActionType::BlockCookies }, 1);
876     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/ignore2.html"), { ContentExtensions::ActionType::BlockLoad }, 1);
877     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore2.html"), { }, 1);
878     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/block_cookies/ignore1/ignore2.html"), { }, 0);
879 }
880
881 static bool actionsEqual(const std::pair<Vector<WebCore::ContentExtensions::Action>, Vector<String>>& actual, Vector<WebCore::ContentExtensions::Action>&& expected, bool ignorePreviousRules = false)
882 {
883     if (ignorePreviousRules) {
884         if (actual.second.size())
885             return false;
886     } else {
887         if (actual.second.size() != 1)
888             return false;
889         if (actual.second[0] != "testFilter")
890             return false;
891     }
892
893     if (actual.first.size() != expected.size())
894         return false;
895     for (size_t i = 0; i < expected.size(); ++i) {
896         if (actual.first[i].type() != expected[i].type())
897             return false;
898         if (actual.first[i].stringArgument() != expected[i].stringArgument())
899             return false;
900     }
901     return true;
902 }
903
904 static const char* jsonWithStringsToCombine = "["
905     "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\"}},"
906     "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\"}},"
907     "{\"action\":{\"type\":\"notify\",\"notification\":\"BBB\"},\"trigger\":{\"url-filter\":\"B\"}},"
908     "{\"action\":{\"type\":\"css-display-none\",\"selector\":\"CCC\"},\"trigger\":{\"url-filter\":\"C\"}},"
909     "{\"action\":{\"type\":\"css-display-none\",\"selector\":\"selectorCombinedWithC\"},\"trigger\":{\"url-filter\":\"C\"}},"
910     "{\"action\":{\"type\":\"css-display-none\",\"selector\":\"DDD\"},\"trigger\":{\"url-filter\":\"D\"}},"
911     "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"E\"}},"
912     "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"F\"}},"
913     "{\"action\":{\"type\":\"notify\",\"notification\":\"GGG\"},\"trigger\":{\"url-filter\":\"G\"}},"
914     "{\"action\":{\"type\":\"notify\",\"notification\":\"GGG\"},\"trigger\":{\"url-filter\":\"I\"}},"
915     "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"J\"}},"
916     "{\"action\":{\"type\":\"notify\",\"notification\":\"GGG\"},\"trigger\":{\"url-filter\":\"K\"}}"
917 "]";
918
919 TEST_F(ContentExtensionTest, StringParameters)
920 {
921     auto backend1 = makeBackend("[{\"action\":{\"type\":\"notify\",\"notification\":\"testnotification\"},\"trigger\":{\"url-filter\":\"matches\"}}]");
922     ASSERT_TRUE(actionsEqual(backend1.actionsForResourceLoad(mainDocumentRequest("test:///matches")), {{ ContentExtensions::ActionType::Notify, "testnotification" }}));
923
924     auto backend2 = makeBackend(jsonWithStringsToCombine);
925     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://A")), {{ ContentExtensions::ActionType::Notify, "AAA" }}));
926     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://B")), {{ ContentExtensions::ActionType::Notify, "BBB" }}));
927     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://C")), {{ ContentExtensions::ActionType::CSSDisplayNoneSelector, "CCC,selectorCombinedWithC" }}));
928     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://D")), {{ ContentExtensions::ActionType::CSSDisplayNoneSelector, "DDD" }}));
929     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://E")), { }, true));
930     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://F")), { ContentExtensions::ActionType::BlockLoad }));
931     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://G")), {{ ContentExtensions::ActionType::Notify, "GGG" }}));
932     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://GIK")), {{ ContentExtensions::ActionType::Notify, "GGG" }}));
933     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://AJ")), {
934         { ContentExtensions::ActionType::Notify, "AAA" },
935         { ContentExtensions::ActionType::Notify, "AAA" } // ignore-previous-rules makes the AAA actions need to be unique.
936     }));
937     // FIXME: Add a test that matches actions with AAA with ignore-previous-rules between them and makes sure we only get one notification.
938     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://AE")), { }, true));
939     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://ABCDE")), { }, true));
940     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://ABCDEFG")), {
941         { ContentExtensions::ActionType::Notify, "GGG" },
942         { ContentExtensions::ActionType::BlockLoad }
943     }, true));
944     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://FG")), {
945         { ContentExtensions::ActionType::Notify, "GGG" },
946         { ContentExtensions::ActionType::BlockLoad }
947     }));
948     ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://EFG")), {
949         { ContentExtensions::ActionType::Notify, "GGG" },
950         { ContentExtensions::ActionType::BlockLoad }
951     }, true));
952 }
953
954 template<typename T, size_t cStringLength>
955 static int sequenceInstances(const Vector<T> vector, const char (&sequence)[cStringLength])
956 {
957     static_assert(sizeof(T) == sizeof(char), "sequenceInstances should only be used for various byte vectors.");
958
959     size_t sequenceLength = cStringLength - 1;
960     size_t instances = 0;
961     for (size_t i = 0; i <= vector.size() - sequenceLength; ++i) {
962         for (size_t j = 0; j < sequenceLength; j++) {
963             if (vector[i + j] != sequence[j])
964                 break;
965             if (j == sequenceLength - 1)
966                 instances++;
967         }
968     }
969     return instances;
970 }
971
972 TEST_F(ContentExtensionTest, StringCombining)
973 {
974     auto extension = InMemoryCompiledContentExtension::create(jsonWithStringsToCombine);
975     const auto& data = extension->data();
976
977     ASSERT_EQ(sequenceInstances(data.actions, "AAA"), 2);
978     ASSERT_EQ(sequenceInstances(data.actions, "GGG"), 1);
979
980     ASSERT_EQ(data.actions.size(), 78u);
981     ASSERT_EQ(data.filtersWithoutConditions.size(),  313u);
982     ASSERT_EQ(data.filtersWithConditions.size(),  5u);
983     ASSERT_EQ(data.topURLFilters.size(),  5u);
984     ASSERT_FALSE(data.conditionsApplyOnlyToDomain);
985
986     auto extensionWithFlags = InMemoryCompiledContentExtension::create("["
987         "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\"}},"
988         "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"C\"}},"
989         "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\",\"resource-type\":[\"document\"]}},"
990         "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\",\"resource-type\":[\"document\",\"font\"]}},"
991         "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"B\",\"resource-type\":[\"document\"]}}"
992     "]");
993     ASSERT_EQ(sequenceInstances(extensionWithFlags->data().actions, "AAA"), 3); // There are 3 sets of unique flags for AAA actions.
994 }
995
996 TEST_F(ContentExtensionTest, TermsKnownToMatchAnything)
997 {
998     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre1.*post1$\"}},"
999         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre2(.*)post2$\"}},"
1000         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre3(.*)?post3$\"}},"
1001         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre4(.*)+post4$\"}},"
1002         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre5(.*)*post5$\"}},"
1003         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre6(.)*post6$\"}},"
1004         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre7(.+)*post7$\"}},"
1005         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre8(.?)*post8$\"}},"
1006         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre9(.+)?post9$\"}},"
1007         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre0(.?)+post0$\"}}]");
1008
1009     testRequest(backend, mainDocumentRequest("pre1://webkit.org/post1"), { ContentExtensions::ActionType::BlockLoad });
1010     testRequest(backend, mainDocumentRequest("pre2://webkit.org/post2"), { ContentExtensions::ActionType::BlockLoad });
1011     testRequest(backend, mainDocumentRequest("pre3://webkit.org/post3"), { ContentExtensions::ActionType::BlockLoad });
1012     testRequest(backend, mainDocumentRequest("pre4://webkit.org/post4"), { ContentExtensions::ActionType::BlockLoad });
1013     testRequest(backend, mainDocumentRequest("pre5://webkit.org/post5"), { ContentExtensions::ActionType::BlockLoad });
1014     testRequest(backend, mainDocumentRequest("pre6://webkit.org/post6"), { ContentExtensions::ActionType::BlockLoad });
1015     testRequest(backend, mainDocumentRequest("pre7://webkit.org/post7"), { ContentExtensions::ActionType::BlockLoad });
1016     testRequest(backend, mainDocumentRequest("pre8://webkit.org/post8"), { ContentExtensions::ActionType::BlockLoad });
1017     testRequest(backend, mainDocumentRequest("pre9://webkit.org/post9"), { ContentExtensions::ActionType::BlockLoad });
1018     testRequest(backend, mainDocumentRequest("pre0://webkit.org/post0"), { ContentExtensions::ActionType::BlockLoad });
1019
1020     testRequest(backend, mainDocumentRequest("pre1://webkit.org/post2"), { });
1021     testRequest(backend, mainDocumentRequest("pre2://webkit.org/post3"), { });
1022     testRequest(backend, mainDocumentRequest("pre3://webkit.org/post4"), { });
1023     testRequest(backend, mainDocumentRequest("pre4://webkit.org/post5"), { });
1024     testRequest(backend, mainDocumentRequest("pre5://webkit.org/post6"), { });
1025     testRequest(backend, mainDocumentRequest("pre6://webkit.org/post7"), { });
1026     testRequest(backend, mainDocumentRequest("pre7://webkit.org/post8"), { });
1027     testRequest(backend, mainDocumentRequest("pre8://webkit.org/post9"), { });
1028     testRequest(backend, mainDocumentRequest("pre9://webkit.org/post0"), { });
1029     testRequest(backend, mainDocumentRequest("pre0://webkit.org/post1"), { });
1030
1031     testRequest(backend, mainDocumentRequest("pre0://webkit.org/post1"), { });
1032     testRequest(backend, mainDocumentRequest("pre1://webkit.org/post2"), { });
1033     testRequest(backend, mainDocumentRequest("pre2://webkit.org/post3"), { });
1034     testRequest(backend, mainDocumentRequest("pre3://webkit.org/post4"), { });
1035     testRequest(backend, mainDocumentRequest("pre4://webkit.org/post5"), { });
1036     testRequest(backend, mainDocumentRequest("pre5://webkit.org/post6"), { });
1037     testRequest(backend, mainDocumentRequest("pre6://webkit.org/post7"), { });
1038     testRequest(backend, mainDocumentRequest("pre7://webkit.org/post8"), { });
1039     testRequest(backend, mainDocumentRequest("pre8://webkit.org/post9"), { });
1040     testRequest(backend, mainDocumentRequest("pre9://webkit.org/post0"), { });
1041 }
1042
1043 TEST_F(ContentExtensionTest, TrailingDotStar)
1044 {
1045     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foo.*$\"}},"
1046         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar(.*)$\"}}]");
1047
1048     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
1049
1050     testRequest(backend, mainDocumentRequest("foo://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1051     testRequest(backend, mainDocumentRequest("https://foo.org/"), { ContentExtensions::ActionType::BlockLoad });
1052     testRequest(backend, mainDocumentRequest("https://webkit.foo/"), { ContentExtensions::ActionType::BlockLoad });
1053     testRequest(backend, mainDocumentRequest("https://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
1054
1055     testRequest(backend, mainDocumentRequest("bar://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1056     testRequest(backend, mainDocumentRequest("https://bar.org/"), { ContentExtensions::ActionType::BlockLoad });
1057     testRequest(backend, mainDocumentRequest("https://webkit.bar/"), { ContentExtensions::ActionType::BlockLoad });
1058     testRequest(backend, mainDocumentRequest("https://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
1059 }
1060
1061 TEST_F(ContentExtensionTest, TrailingTermsCarryingNoData)
1062 {
1063     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foob?a?r?\"}},"
1064         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bazo(ok)?a?$\"}},"
1065         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"cats*$\"}}]");
1066
1067     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
1068
1069     // Anything is fine after foo.
1070     testRequest(backend, mainDocumentRequest("https://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
1071     testRequest(backend, mainDocumentRequest("https://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
1072     testRequest(backend, mainDocumentRequest("https://webkit.org/fooc"), { ContentExtensions::ActionType::BlockLoad });
1073     testRequest(backend, mainDocumentRequest("https://webkit.org/fooba"), { ContentExtensions::ActionType::BlockLoad });
1074     testRequest(backend, mainDocumentRequest("https://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
1075     testRequest(backend, mainDocumentRequest("https://webkit.org/foobar-stuff"), { ContentExtensions::ActionType::BlockLoad });
1076
1077     // Bazooka has to be at the tail without any character not defined by the filter.
1078     testRequest(backend, mainDocumentRequest("https://webkit.org/baz"), { });
1079     testRequest(backend, mainDocumentRequest("https://webkit.org/bazo"), { ContentExtensions::ActionType::BlockLoad });
1080     testRequest(backend, mainDocumentRequest("https://webkit.org/bazoa"), { ContentExtensions::ActionType::BlockLoad });
1081     testRequest(backend, mainDocumentRequest("https://webkit.org/bazob"), { });
1082     testRequest(backend, mainDocumentRequest("https://webkit.org/bazoo"), { });
1083     testRequest(backend, mainDocumentRequest("https://webkit.org/bazook"), { ContentExtensions::ActionType::BlockLoad });
1084     testRequest(backend, mainDocumentRequest("https://webkit.org/bazookb"), { });
1085     testRequest(backend, mainDocumentRequest("https://webkit.org/bazooka"), { ContentExtensions::ActionType::BlockLoad });
1086     testRequest(backend, mainDocumentRequest("https://webkit.org/bazookaa"), { });
1087
1088     // The pattern must finish with cat, with any number of 's' following it, but no other character.
1089     testRequest(backend, mainDocumentRequest("https://cat.org/"), { });
1090     testRequest(backend, mainDocumentRequest("https://cats.org/"), { });
1091     testRequest(backend, mainDocumentRequest("https://webkit.org/cat"), { ContentExtensions::ActionType::BlockLoad });
1092     testRequest(backend, mainDocumentRequest("https://webkit.org/cats"), { ContentExtensions::ActionType::BlockLoad });
1093     testRequest(backend, mainDocumentRequest("https://webkit.org/catss"), { ContentExtensions::ActionType::BlockLoad });
1094     testRequest(backend, mainDocumentRequest("https://webkit.org/catsss"), { ContentExtensions::ActionType::BlockLoad });
1095     testRequest(backend, mainDocumentRequest("https://webkit.org/catso"), { });
1096 }
1097
1098 TEST_F(ContentExtensionTest, UselessTermsMatchingEverythingAreEliminated)
1099 {
1100     ContentExtensions::CombinedURLFilters combinedURLFilters;
1101     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1102     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(".*web", false, 0));
1103     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.*)web", false, 0));
1104     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.)*web", false, 0));
1105     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.+)*web", false, 0));
1106     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.?)*web", false, 0));
1107     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.+)?web", false, 0));
1108     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.?)+web", false, 0));
1109
1110     Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
1111     EXPECT_EQ(1ul, nfas.size());
1112     EXPECT_EQ(7ul, nfas.first().nodes.size());
1113
1114     ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first());
1115     Vector<ContentExtensions::DFABytecode> bytecode;
1116     ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
1117     compiler.compile();
1118     ContentExtensions::DFABytecodeInterpreter interpreter(bytecode.data(), bytecode.size());
1119     compareContents(interpreter.interpret("eb", 0), { });
1120     compareContents(interpreter.interpret("we", 0), { });
1121     compareContents(interpreter.interpret("weeb", 0), { });
1122     compareContents(interpreter.interpret("web", 0), { 0 });
1123     compareContents(interpreter.interpret("wweb", 0), { 0 });
1124     compareContents(interpreter.interpret("wwebb", 0), { 0 });
1125     compareContents(interpreter.interpret("http://theweb.com/", 0), { 0 });
1126 }
1127
1128 TEST_F(ContentExtensionTest, LoadType)
1129 {
1130     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"third-party\"]}},"
1131         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"whatwg.org\",\"load-type\":[\"first-party\"]}},"
1132         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"alwaysblock.pdf\"}}]");
1133     
1134     testRequest(backend, mainDocumentRequest("http://webkit.org"), { });
1135     testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Document}, { ContentExtensions::ActionType::BlockLoad });
1136         
1137     testRequest(backend, mainDocumentRequest("http://whatwg.org"), { ContentExtensions::ActionType::BlockLoad });
1138     testRequest(backend, {URL(URL(), "http://whatwg.org"), URL(URL(), "http://not_whatwg.org"), ResourceType::Document}, { });
1139     
1140     testRequest(backend, mainDocumentRequest("http://foobar.org/alwaysblock.pdf"), { ContentExtensions::ActionType::BlockLoad });
1141     testRequest(backend, {URL(URL(), "http://foobar.org/alwaysblock.pdf"), URL(URL(), "http://not_foobar.org/alwaysblock.pdf"), ResourceType::Document}, { ContentExtensions::ActionType::BlockLoad });
1142 }
1143
1144 TEST_F(ContentExtensionTest, ResourceType)
1145 {
1146     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_all_types.org\",\"resource-type\":[\"document\",\"image\",\"style-sheet\",\"script\",\"font\",\"raw\",\"svg-document\",\"media\",\"popup\"]}},"
1147         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_only_images\",\"resource-type\":[\"image\"]}}]");
1148
1149     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Document), { ContentExtensions::ActionType::BlockLoad });
1150     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
1151     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::StyleSheet), { ContentExtensions::ActionType::BlockLoad });
1152     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
1153     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Font), { ContentExtensions::ActionType::BlockLoad });
1154     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Raw), { ContentExtensions::ActionType::BlockLoad });
1155     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::SVGDocument), { ContentExtensions::ActionType::BlockLoad });
1156     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Media), { ContentExtensions::ActionType::BlockLoad });
1157     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Popup), { ContentExtensions::ActionType::BlockLoad });
1158     testRequest(backend, mainDocumentRequest("http://block_only_images.org", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
1159     testRequest(backend, mainDocumentRequest("http://block_only_images.org", ResourceType::Document), { });
1160 }
1161
1162 TEST_F(ContentExtensionTest, ResourceAndLoadType)
1163 {
1164     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"BlockOnlyIfThirdPartyAndScript\",\"resource-type\":[\"script\"],\"load-type\":[\"third-party\"]}}]");
1165     
1166     testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.js", "http://webkit.org", ResourceType::Script), { });
1167     testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.png", "http://not_webkit.org", ResourceType::Image), { });
1168     testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.js", "http://not_webkit.org", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
1169 }
1170
1171 TEST_F(ContentExtensionTest, ResourceOrLoadTypeMatchingEverything)
1172 {
1173     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"resource-type\":[\"image\"]}},"
1174         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"third-party\"]}},"
1175         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"first-party\"]}}]");
1176     
1177     testRequest(backend, mainDocumentRequest("http://webkit.org"), { }, 0);
1178     testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Document}, { ContentExtensions::ActionType::BlockCookies });
1179     testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Image}, { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
1180 }
1181     
1182 TEST_F(ContentExtensionTest, WideNFA)
1183 {
1184     // Make an NFA with about 1400 nodes that won't be combined.
1185     StringBuilder ruleList;
1186     ruleList.append('[');
1187     for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
1188         for (char c2 = 'A'; c2 <= 'C'; ++c2) {
1189             for (char c3 = 'A'; c3 <= 'C'; ++c3) {
1190                 if (c1 != 'A' || c2 != 'A' || c3 != 'A')
1191                     ruleList.append(',');
1192                 ruleList.append("{\"action\":{\"type\":\"");
1193                 
1194                 // Make every other rule ignore-previous-rules to not combine actions.
1195                 if (!((c1 + c2 + c3) % 2))
1196                     ruleList.append("ignore-previous-rules");
1197                 else {
1198                     ruleList.append("css-display-none");
1199                     ruleList.append("\",\"selector\":\"");
1200                     ruleList.append(c1);
1201                     ruleList.append(c2);
1202                     ruleList.append(c3);
1203                 }
1204                 ruleList.append("\"},\"trigger\":{\"url-filter\":\".*");
1205                 ruleList.append(c1);
1206                 ruleList.append(c2);
1207                 ruleList.append(c3);
1208                 ruleList.append("\", \"url-filter-is-case-sensitive\":true}}");
1209             }
1210         }
1211     }
1212     ruleList.append(']');
1213     
1214     auto backend = makeBackend(ruleList.toString().utf8().data());
1215
1216     testRequest(backend, mainDocumentRequest("http://webkit.org/AAA"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
1217     testRequest(backend, mainDocumentRequest("http://webkit.org/YAA"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
1218     testRequest(backend, mainDocumentRequest("http://webkit.org/ZAA"), { }, 0);
1219     testRequest(backend, mainDocumentRequest("http://webkit.org/LAA/AAA"), { }, 0);
1220     testRequest(backend, mainDocumentRequest("http://webkit.org/LAA/MAA"), { ContentExtensions::ActionType::CSSDisplayNoneSelector }, 0);
1221     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
1222 }
1223     
1224 #ifdef NDEBUG
1225 static uint64_t expectedIndex(char c, unsigned position)
1226 {
1227     uint64_t index = c - 'A';
1228     for (unsigned i = 1; i < position; ++i)
1229         index *= (i == 1) ? ('C' - 'A' + 1) : ('Z' - 'A' + 1);
1230     return index;
1231 }
1232 #endif
1233
1234 TEST_F(ContentExtensionTest, LargeJumps)
1235 {
1236 // A large test like this is necessary to test 24 and 32 bit jumps, but it's so large it times out in debug builds.
1237 #ifdef NDEBUG
1238     ContentExtensions::CombinedURLFilters combinedURLFilters;
1239     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1240     
1241     uint64_t patternId = 0;
1242     for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
1243         for (char c2 = 'A'; c2 <= 'Z'; ++c2) {
1244             for (char c3 = 'A'; c3 <= 'Z'; ++c3) {
1245                 for (char c4 = 'A'; c4 <= 'C'; ++c4) {
1246                     StringBuilder pattern;
1247                     pattern.append(c1);
1248                     pattern.append(c2);
1249                     pattern.append(c3);
1250                     pattern.append(c4);
1251                     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(pattern.toString(), true, patternId++));
1252                 }
1253             }
1254         }
1255     }
1256     
1257     Vector<ContentExtensions::NFA> nfas;
1258     combinedURLFilters.processNFAs(std::numeric_limits<size_t>::max(), [&](ContentExtensions::NFA&& nfa) {
1259         nfas.append(WTFMove(nfa));
1260     });
1261     EXPECT_EQ(nfas.size(), 1ull);
1262     
1263     Vector<ContentExtensions::DFA> dfas;
1264     for (auto& nfa : nfas)
1265         dfas.append(ContentExtensions::NFAToDFA::convert(nfa));
1266     EXPECT_EQ(dfas.size(), 1ull);
1267     
1268     Vector<ContentExtensions::DFABytecode> combinedBytecode;
1269     for (const auto& dfa : dfas) {
1270         Vector<ContentExtensions::DFABytecode> bytecode;
1271         ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
1272         compiler.compile();
1273         combinedBytecode.appendVector(bytecode);
1274     }
1275     
1276     ContentExtensions::DFABytecodeInterpreter interpreter(&combinedBytecode[0], combinedBytecode.size());
1277     
1278     patternId = 0;
1279     for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
1280         for (char c2 = 'A'; c2 <= 'Z'; ++c2) {
1281             for (char c3 = 'A'; c3 <= 'Z'; ++c3) {
1282                 for (char c4 = 'A'; c4 <= 'C'; ++c4) {
1283                     StringBuilder pattern;
1284                     pattern.append(c1);
1285                     pattern.append(c2);
1286                     pattern.append(c3);
1287                     // Test different jumping patterns distributed throughout the DFA:
1288                     switch ((c1 + c2 + c3 + c4) % 4) {
1289                     case 0:
1290                         // This should not match.
1291                         pattern.append('x');
1292                         pattern.append(c4);
1293                         break;
1294                     case 1:
1295                         // This should jump back to the root, then match.
1296                         pattern.append('x');
1297                         pattern.append(c1);
1298                         pattern.append(c2);
1299                         pattern.append(c3);
1300                         pattern.append(c4);
1301                         break;
1302                     case 2:
1303                         // This should match at the end of the string.
1304                         pattern.append(c4);
1305                         break;
1306                     case 3:
1307                         // This should match then jump back to the root.
1308                         pattern.append(c4);
1309                         pattern.append('x');
1310                         break;
1311                     }
1312                     auto matches = interpreter.interpret(pattern.toString().utf8(), 0);
1313                     switch ((c1 + c2 + c3 + c4) % 4) {
1314                     case 0:
1315                         compareContents(matches, { });
1316                         break;
1317                     case 1:
1318                     case 2:
1319                     case 3:
1320                         compareContents(matches, {patternId});
1321                         break;
1322                     }
1323                     patternId++;
1324                 }
1325             }
1326         }
1327     }
1328
1329     compareContents(interpreter.interpret("CAAAAx", 0), {expectedIndex('C', 4), expectedIndex('A', 1)});
1330     compareContents(interpreter.interpret("KAAAAx", 0), {expectedIndex('K', 4), expectedIndex('A', 1)});
1331     compareContents(interpreter.interpret("AKAAAx", 0), {expectedIndex('K', 3), expectedIndex('K', 4)});
1332     compareContents(interpreter.interpret("AKxAAAAx", 0), {expectedIndex('A', 1)});
1333     compareContents(interpreter.interpret("AKAxAAAAx", 0), {expectedIndex('A', 1)});
1334     compareContents(interpreter.interpret("AKAxZKAxZKZxAAAAx", 0), {expectedIndex('A', 1)});
1335     compareContents(interpreter.interpret("ZAAAA", 0), {expectedIndex('Z', 4), expectedIndex('A', 1)});
1336     compareContents(interpreter.interpret("ZZxZAAAB", 0), {expectedIndex('Z', 4), expectedIndex('B', 1)});
1337 #endif
1338 }
1339
1340 TEST_F(ContentExtensionTest, DeepNFA)
1341 {
1342     const unsigned size = 100000;
1343     
1344     ContentExtensions::CombinedURLFilters combinedURLFilters;
1345     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1346     
1347     // FIXME: DFAToNFA::convert takes way too long on these deep NFAs. We should optimize for that case.
1348     
1349     StringBuilder lotsOfAs;
1350     for (unsigned i = 0; i < size; ++i)
1351         lotsOfAs.append('A');
1352     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(lotsOfAs.toString().utf8().data(), false, 0));
1353     
1354     // FIXME: Yarr ought to be able to handle 2MB regular expressions.
1355     StringBuilder tooManyAs;
1356     for (unsigned i = 0; i < size * 20; ++i)
1357         tooManyAs.append('A');
1358     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::YarrError, parser.addPattern(tooManyAs.toString().utf8().data(), false, 0));
1359     
1360     StringBuilder nestedGroups;
1361     for (unsigned i = 0; i < size; ++i)
1362         nestedGroups.append('(');
1363     for (unsigned i = 0; i < size; ++i)
1364         nestedGroups.append("B)");
1365     // FIXME: Add nestedGroups. Right now it also takes too long. It should be optimized.
1366     
1367     // This should not crash and not timeout.
1368     EXPECT_EQ(1ul, createNFAs(combinedURLFilters).size());
1369 }
1370
1371 void checkCompilerError(const char* json, std::error_code expectedError)
1372 {
1373     CompiledContentExtensionData extensionData;
1374     InMemoryContentExtensionCompilationClient client(extensionData);
1375     auto parsedRules = ContentExtensions::parseRuleList(json);
1376     std::error_code compilerError;
1377     if (parsedRules.has_value())
1378         compilerError = ContentExtensions::compileRuleList(client, json, WTFMove(parsedRules.value()));
1379     else
1380         compilerError = parsedRules.error();
1381     EXPECT_EQ(compilerError.value(), expectedError.value());
1382     if (compilerError.value())
1383         EXPECT_STREQ(compilerError.category().name(), expectedError.category().name());
1384 }
1385
1386 TEST_F(ContentExtensionTest, MatchesEverything)
1387 {
1388     // Only css-display-none rules with triggers that match everything, no domain rules, and no flags
1389     // should go in the global display:none stylesheet. css-display-none rules with domain rules or flags
1390     // are applied separately on pages where they apply.
1391     auto backend1 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]");
1392     EXPECT_TRUE(nullptr != backend1.globalDisplayNoneStyleSheet("testFilter"_s));
1393     testRequest(backend1, mainDocumentRequest("http://webkit.org"), { }); // Selector is in global stylesheet.
1394     
1395     auto backend2 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"webkit.org\"]}}]");
1396     EXPECT_EQ(nullptr, backend2.globalDisplayNoneStyleSheet("testFilter"_s));
1397     testRequest(backend2, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
1398     testRequest(backend2, mainDocumentRequest("http://w3c.org"), { });
1399     
1400     auto backend3 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"webkit.org\"]}}]");
1401     EXPECT_EQ(nullptr, backend3.globalDisplayNoneStyleSheet("testFilter"_s));
1402     testRequest(backend3, mainDocumentRequest("http://webkit.org"), { });
1403     testRequest(backend3, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
1404     
1405     auto backend4 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"third-party\"]}}]");
1406     EXPECT_EQ(nullptr, backend4.globalDisplayNoneStyleSheet("testFilter"_s));
1407     testRequest(backend4, mainDocumentRequest("http://webkit.org"), { });
1408     testRequest(backend4, subResourceRequest("http://not_webkit.org", "http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
1409
1410     // css-display-none rules after ignore-previous-rules should not be put in the default stylesheet.
1411     auto backend5 = makeBackend("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\".*\"}},"
1412         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]");
1413     EXPECT_EQ(nullptr, backend5.globalDisplayNoneStyleSheet("testFilter"_s));
1414     testRequest(backend5, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector }, 0);
1415     
1416     auto backend6 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"webkit.org\",\"*w3c.org\"],\"resource-type\":[\"document\",\"script\"]}},"
1417         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore\",\"if-domain\":[\"*webkit.org\",\"w3c.org\"]}},"
1418         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"webkit.org\",\"whatwg.org\"],\"resource-type\":[\"script\",\"image\"],\"load-type\":[\"third-party\"]}}]");
1419     EXPECT_EQ(nullptr, backend6.globalDisplayNoneStyleSheet("testFilter"_s));
1420     testRequest(backend6, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::BlockLoad });
1421     testRequest(backend6, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::BlockLoad });
1422     testRequest(backend6, mainDocumentRequest("http://whatwg.org"), { });
1423     testRequest(backend6, mainDocumentRequest("http://sub.webkit.org"), { });
1424     testRequest(backend6, mainDocumentRequest("http://sub.w3c.org"), { ContentExtensions::ActionType::BlockLoad });
1425     testRequest(backend6, mainDocumentRequest("http://sub.whatwg.org"), { });
1426     testRequest(backend6, mainDocumentRequest("http://webkit.org/ignore"), { }, 0);
1427     testRequest(backend6, mainDocumentRequest("http://w3c.org/ignore"), { }, 0);
1428     testRequest(backend6, mainDocumentRequest("http://whatwg.org/ignore"), { });
1429     testRequest(backend6, mainDocumentRequest("http://sub.webkit.org/ignore"), { }, 0);
1430     testRequest(backend6, mainDocumentRequest("http://sub.w3c.org/ignore"), { ContentExtensions::ActionType::BlockLoad });
1431     testRequest(backend6, mainDocumentRequest("http://sub.whatwg.org/ignore"), { });
1432     testRequest(backend6, subResourceRequest("http://example.com/image.png", "http://webkit.org/", ResourceType::Image), { });
1433     testRequest(backend6, subResourceRequest("http://example.com/image.png", "http://w3c.org/", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies });
1434     testRequest(backend6, subResourceRequest("http://example.com/doc.html", "http://webkit.org/", ResourceType::Document), { ContentExtensions::ActionType::BlockLoad });
1435     testRequest(backend6, subResourceRequest("http://example.com/script.js", "http://webkit.org/", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
1436     testRequest(backend6, subResourceRequest("http://example.com/script.js", "http://w3c.org/", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
1437     testRequest(backend6, subResourceRequest("http://example.com/script.js", "http://example.com/", ResourceType::Script), { });
1438     testRequest(backend6, subResourceRequest("http://example.com/ignore/image.png", "http://webkit.org/", ResourceType::Image), { }, 0);
1439     testRequest(backend6, subResourceRequest("http://example.com/ignore/image.png", "http://example.com/", ResourceType::Image), { });
1440     testRequest(backend6, subResourceRequest("http://example.com/ignore/image.png", "http://example.org/", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies });
1441     testRequest(backend6, subResourceRequest("http://example.com/doc.html", "http://example.org/", ResourceType::Document), { });
1442     testRequest(backend6, subResourceRequest("http://example.com/", "http://example.com/", ResourceType::Font), { });
1443     testRequest(backend6, subResourceRequest("http://example.com/ignore", "http://webkit.org/", ResourceType::Image), { }, 0);
1444     testRequest(backend6, subResourceRequest("http://example.com/ignore", "http://webkit.org/", ResourceType::Font), { }, 0);
1445     testRequest(backend6, subResourceRequest("http://example.com/", "http://example.com/", ResourceType::Script), { });
1446     testRequest(backend6, subResourceRequest("http://example.com/ignore", "http://example.com/", ResourceType::Script), { });
1447 }
1448     
1449 TEST_F(ContentExtensionTest, InvalidJSON)
1450 {
1451     checkCompilerError("[", ContentExtensions::ContentExtensionError::JSONInvalid);
1452     checkCompilerError("123", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnObject);
1453     checkCompilerError("{}", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnArray);
1454     // FIXME: Add unit test for JSONInvalidRule if that is possible to hit.
1455     checkCompilerError("[]", ContentExtensions::ContentExtensionError::JSONContainsNoRules);
1456
1457     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":5}]",
1458         ContentExtensions::ContentExtensionError::JSONInvalidTrigger);
1459     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"\"}}]",
1460         ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
1461     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":{}}}]",
1462         ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
1463
1464     // FIXME: Add unit test for JSONInvalidObjectInTriggerFlagsArray if that is possible to hit.
1465     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":{}}}]",
1466         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1467     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"invalid\"]}}]",
1468         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
1469     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[5]}}]",
1470         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
1471     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":5}}]",
1472         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1473     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":\"first-party\"}}]",
1474         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1475     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":null}}]",
1476         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1477     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":false}}]",
1478         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1479     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":{}}}]",
1480         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1481     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[\"invalid\"]}}]",
1482         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
1483     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[5]}}]",
1484         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
1485     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":5}}]",
1486         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1487     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":\"document\"}}]",
1488         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1489     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":null}}]",
1490         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1491     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":false}}]",
1492         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
1493     
1494     checkCompilerError("[{\"action\":{\"type\":\"notify\"},\"trigger\":{\"url-filter\":\".*\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidNotification);
1495     checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":5},\"trigger\":{\"url-filter\":\".*\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidNotification);
1496     checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":[]},\"trigger\":{\"url-filter\":\".*\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidNotification);
1497     checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":\"here's my notification\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
1498     checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":\"\\u1234\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
1499     
1500     StringBuilder rules;
1501     rules.append("[");
1502     for (unsigned i = 0; i < 49999; ++i)
1503         rules.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}},");
1504     String rules50000 = rules.toString();
1505     String rules50001 = rules.toString();
1506     rules50000.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}}]");
1507     rules50001.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}},{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}}]");
1508     checkCompilerError(rules50000.utf8().data(), { });
1509     checkCompilerError(rules50001.utf8().data(), ContentExtensions::ContentExtensionError::JSONTooManyRules);
1510     
1511     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":{}}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1512     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[5]}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1513     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"]}}]", { });
1514     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":\"a\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1515     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":false}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1516     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":null}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1517     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":{}}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1518     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[5]}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1519     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1520     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":\"a\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1521     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":null}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1522     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":false}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1523     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"A\"]}}]", ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
1524     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"\\u00DC\"]}}]", ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
1525     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"0\"]}}]", { });
1526     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"a\"]}}]", { });
1527
1528     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1529     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1530     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1531     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1532     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":5,\"unless-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1533     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONInvalidConditionList);
1534     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1535
1536     checkCompilerError("[{\"action\":5,\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
1537         ContentExtensions::ContentExtensionError::JSONInvalidAction);
1538     checkCompilerError("[{\"action\":{\"type\":\"invalid\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
1539         ContentExtensions::ContentExtensionError::JSONInvalidActionType);
1540     checkCompilerError("[{\"action\":{\"type\":\"css-display-none\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
1541         ContentExtensions::ContentExtensionError::JSONInvalidCSSDisplayNoneActionType);
1542
1543     checkCompilerError("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"webkit.org\"}},"
1544         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
1545     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"a\"]}}]", { });
1546     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"a\"]}}]", { });
1547     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[\"}}]",
1548         ContentExtensions::ContentExtensionError::JSONInvalidRegex);
1549
1550     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1551     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"],\"unless-top-url\":[]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1552     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"],\"unless-top-url\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1553     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"if-top-url\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1554     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1555     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-top-url\":[\"a\"],\"if-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONMultipleConditions);
1556     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);
1557     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);
1558     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-top-url\":[\"[\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidRegex);
1559     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\", \"unexpected-identifier-should-be-ignored\":5}}]", { });
1560 }
1561
1562 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines1)
1563 {
1564     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^.*foo\"}},"
1565         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar$\"}},"
1566         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[ab]+bang\"}}]");
1567
1568     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
1569     testRequest(backend, mainDocumentRequest("foo://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
1570     testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
1571     testRequest(backend, mainDocumentRequest("bar://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
1572
1573     testRequest(backend, mainDocumentRequest("abang://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1574     testRequest(backend, mainDocumentRequest("bbang://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1575     testRequest(backend, mainDocumentRequest("cbang://webkit.org/"), { });
1576     testRequest(backend, mainDocumentRequest("http://webkit.org/bang"), { });
1577     testRequest(backend, mainDocumentRequest("bang://webkit.org/"), { });
1578 }
1579
1580 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines1Partitioning)
1581 {
1582     ContentExtensions::CombinedURLFilters combinedURLFilters;
1583     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1584
1585     // Those two share a prefix.
1586     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^.*foo", false, 0));
1587     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("bar$", false, 1));
1588
1589     // Not this one.
1590     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^[ab]+bang", false, 0));
1591
1592     EXPECT_EQ(2ul, createNFAs(combinedURLFilters).size());
1593 }
1594
1595 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines2)
1596 {
1597     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^foo\"}},"
1598         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^.*[a-c]+bar\"}},"
1599         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^webkit:\"}},"
1600         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-c]+b+oom\"}}]");
1601
1602     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
1603     testRequest(backend, mainDocumentRequest("foo://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1604     testRequest(backend, mainDocumentRequest("webkit://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1605
1606     testRequest(backend, mainDocumentRequest("http://bar.org/"), { });
1607     testRequest(backend, mainDocumentRequest("http://abar.org/"), { ContentExtensions::ActionType::BlockLoad });
1608     testRequest(backend, mainDocumentRequest("http://bbar.org/"), { ContentExtensions::ActionType::BlockLoad });
1609     testRequest(backend, mainDocumentRequest("http://cbar.org/"), { ContentExtensions::ActionType::BlockLoad });
1610     testRequest(backend, mainDocumentRequest("http://abcbar.org/"), { ContentExtensions::ActionType::BlockLoad });
1611     testRequest(backend, mainDocumentRequest("http://dbar.org/"), { });
1612 }
1613
1614 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines2Partitioning)
1615 {
1616     ContentExtensions::CombinedURLFilters combinedURLFilters;
1617     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1618
1619     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^foo", false, 0));
1620     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^.*[a-c]+bar", false, 1));
1621     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^webkit:", false, 2));
1622     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("[a-c]+b+oom", false, 3));
1623
1624     // "^foo" and "^webkit:" can be grouped, the other two have a variable prefix.
1625     EXPECT_EQ(3ul, createNFAs(combinedURLFilters).size());
1626 }
1627
1628 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines3)
1629 {
1630     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"A*D\"}},"
1631         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"A*BA+\"}},"
1632         "{\"action\":{\"type\":\"make-https\"},\"trigger\":{\"url-filter\":\"A*BC\"}}]");
1633     
1634     testRequest(backend, mainDocumentRequest("http://webkit.org/D"), { ContentExtensions::ActionType::BlockLoad });
1635     testRequest(backend, mainDocumentRequest("http://webkit.org/AAD"), { ContentExtensions::ActionType::BlockLoad });
1636     testRequest(backend, mainDocumentRequest("http://webkit.org/AB"), { });
1637     testRequest(backend, mainDocumentRequest("http://webkit.org/ABA"), { }, 0);
1638     testRequest(backend, mainDocumentRequest("http://webkit.org/ABAD"), { }, 0);
1639     testRequest(backend, mainDocumentRequest("http://webkit.org/BC"), { ContentExtensions::ActionType::MakeHTTPS });
1640     testRequest(backend, mainDocumentRequest("http://webkit.org/ABC"), { ContentExtensions::ActionType::MakeHTTPS });
1641     testRequest(backend, mainDocumentRequest("http://webkit.org/ABABC"), { ContentExtensions::ActionType::MakeHTTPS }, 0);
1642     testRequest(backend, mainDocumentRequest("http://webkit.org/ABABCAD"), { ContentExtensions::ActionType::MakeHTTPS }, 0);
1643     testRequest(backend, mainDocumentRequest("http://webkit.org/ABCAD"), { ContentExtensions::ActionType::MakeHTTPS, ContentExtensions::ActionType::BlockLoad });
1644 }
1645     
1646 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines3Partitioning)
1647 {
1648     ContentExtensions::CombinedURLFilters combinedURLFilters;
1649     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1650     
1651     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*D", false, 0));
1652     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*BA+", false, 1));
1653     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*BC", false, 2));
1654     
1655     // "A*A" and "A*BC" can be grouped, "A*BA+" should not.
1656     EXPECT_EQ(2ul, createNFAs(combinedURLFilters).size());
1657 }
1658
1659 TEST_F(ContentExtensionTest, SplittingLargeNFAs)
1660 {
1661     const size_t expectedNFACounts[16] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1};
1662     
1663     for (size_t i = 0; i < 16; i++) {
1664         ContentExtensions::CombinedURLFilters combinedURLFilters;
1665         ContentExtensions::URLFilterParser parser(combinedURLFilters);
1666         
1667         EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+BBB", false, 1));
1668         EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+CCC", false, 2));
1669         EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+DDD", false, 2));
1670         
1671         Vector<ContentExtensions::NFA> nfas;
1672         combinedURLFilters.processNFAs(i, [&](ContentExtensions::NFA&& nfa) {
1673             nfas.append(WTFMove(nfa));
1674         });
1675         EXPECT_EQ(nfas.size(), expectedNFACounts[i]);
1676         
1677         Vector<ContentExtensions::DFA> dfas;
1678         for (auto& nfa : nfas)
1679             dfas.append(ContentExtensions::NFAToDFA::convert(nfa));
1680         
1681         Vector<ContentExtensions::DFABytecode> combinedBytecode;
1682         for (const auto& dfa : dfas) {
1683             Vector<ContentExtensions::DFABytecode> bytecode;
1684             ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
1685             compiler.compile();
1686             combinedBytecode.appendVector(bytecode);
1687         }
1688         
1689         ContentExtensions::DFABytecodeInterpreter interpreter(&combinedBytecode[0], combinedBytecode.size());
1690         
1691         EXPECT_EQ(interpreter.interpret("ABBBX", 0).size(), 1ull);
1692         EXPECT_EQ(interpreter.interpret("ACCCX", 0).size(), 1ull);
1693         EXPECT_EQ(interpreter.interpret("ADDDX", 0).size(), 1ull);
1694         EXPECT_EQ(interpreter.interpret("XBBBX", 0).size(), 0ull);
1695         EXPECT_EQ(interpreter.interpret("ABBX", 0).size(), 0ull);
1696         EXPECT_EQ(interpreter.interpret("ACCX", 0).size(), 0ull);
1697         EXPECT_EQ(interpreter.interpret("ADDX", 0).size(), 0ull);
1698     }
1699 }
1700     
1701 TEST_F(ContentExtensionTest, QuantifierInGroup)
1702 {
1703     ContentExtensions::CombinedURLFilters combinedURLFilters;
1704     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1705     
1706     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A+)B)C)", false, 0));
1707     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B+)C)", false, 1));
1708     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B+)C)D", false, 2));
1709     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B)C+)", false, 3));
1710     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B)C)", false, 4));
1711     
1712     // (((A)B+)C) and (((A)B+)C)D should be in the same NFA.
1713     EXPECT_EQ(4ul, createNFAs(combinedURLFilters).size());
1714 }
1715
1716 static void testPatternStatus(String pattern, ContentExtensions::URLFilterParser::ParseStatus status)
1717 {
1718     ContentExtensions::CombinedURLFilters combinedURLFilters;
1719     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1720     EXPECT_EQ(status, parser.addPattern(pattern, false, 0));
1721 }
1722     
1723 TEST_F(ContentExtensionTest, ParsingFailures)
1724 {
1725     testPatternStatus("a*b?.*.?[a-z]?[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1726     testPatternStatus("a*b?.*.?[a-z]?[a-z]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1727     testPatternStatus("a*b?.*.?[a-z]?[a-z]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1728     testPatternStatus(".*?a", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1729     testPatternStatus(".*a", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1730     
1731     testPatternStatus("(?!)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1732     testPatternStatus("(?=)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1733     testPatternStatus("(?!a)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1734     testPatternStatus("(?=a)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1735     testPatternStatus("(regex)", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1736     testPatternStatus("(regex", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1737     testPatternStatus("((regex)", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1738     testPatternStatus("(?:regex)", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1739     testPatternStatus("(?:regex", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1740     testPatternStatus("[^.]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1741     
1742     testPatternStatus("a++", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1743     testPatternStatus("[a]++", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1744     testPatternStatus("+", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1745     
1746     testPatternStatus("[", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1747     testPatternStatus("[a}", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1748     
1749     // FIXME: Look into why these do not cause YARR parsing errors.  They probably should.
1750     testPatternStatus("a]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1751     testPatternStatus("{", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1752     testPatternStatus("{[a]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1753     testPatternStatus("{0", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1754     testPatternStatus("{0,", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1755     testPatternStatus("{0,1", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1756     testPatternStatus("a{0,1", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1757     testPatternStatus("a{a,b}", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1758
1759     const char nonASCII[2] = {-1, '\0'};
1760     testPatternStatus(nonASCII, ContentExtensions::URLFilterParser::ParseStatus::NonASCII);
1761     testPatternStatus("\\xff", ContentExtensions::URLFilterParser::ParseStatus::NonASCII);
1762     
1763     testPatternStatus("\\x\\r\\n", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1764     testPatternStatus("\\b", ContentExtensions::URLFilterParser::ParseStatus::WordBoundary);
1765     testPatternStatus("[\\d]", ContentExtensions::URLFilterParser::ParseStatus::AtomCharacter);
1766     testPatternStatus("\\d\\D\\w\\s\\v\\h\\i\\c", ContentExtensions::URLFilterParser::ParseStatus::UnsupportedCharacterClass);
1767     
1768     testPatternStatus("this|that", ContentExtensions::URLFilterParser::ParseStatus::Disjunction);
1769     testPatternStatus("a{0,1}b", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1770     testPatternStatus("a{0,2}b", ContentExtensions::URLFilterParser::ParseStatus::InvalidQuantifier);
1771     testPatternStatus("", ContentExtensions::URLFilterParser::ParseStatus::EmptyPattern);
1772     testPatternStatus("$$", ContentExtensions::URLFilterParser::ParseStatus::MisplacedEndOfLine);
1773     testPatternStatus("a^", ContentExtensions::URLFilterParser::ParseStatus::MisplacedStartOfLine);
1774     testPatternStatus("(^)", ContentExtensions::URLFilterParser::ParseStatus::MisplacedStartOfLine);
1775     
1776     testPatternStatus("(a)\\1", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Back references are disabled, it parse as octal 1
1777     testPatternStatus("(<A>a)\\k<A>", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Named back references aren't handled, it parse as "k<A>"
1778     testPatternStatus("\\1(a)", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Forward references are disabled, it parse as octal 1
1779     testPatternStatus("\\8(a)", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Forward references are disabled, it parse as '8'
1780     testPatternStatus("\\9(a)", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Forward references are disabled, it parse as '9'
1781     testPatternStatus("\\k<A>(<A>a)", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Named forward references aren't handled, it parse as "k<A>"
1782     testPatternStatus("\\k<A>(a)", ContentExtensions::URLFilterParser::ParseStatus::Ok); // Unmatched named forward references aren't handled, it parse as "k<A>"
1783 }
1784
1785 TEST_F(ContentExtensionTest, PatternMatchingTheEmptyString)
1786 {
1787     // Simple atoms.
1788     testPatternStatus(".*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1789     testPatternStatus("a*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1790     testPatternStatus(".?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1791     testPatternStatus("a?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1792
1793     // Character sets.
1794     testPatternStatus("[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1795     testPatternStatus("[a-z]?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1796
1797     // Groups.
1798     testPatternStatus("(foobar)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1799     testPatternStatus("(foobar)?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1800     testPatternStatus("(.*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1801     testPatternStatus("(a*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1802     testPatternStatus("(.?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1803     testPatternStatus("(a?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1804     testPatternStatus("([a-z]*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1805     testPatternStatus("([a-z]?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1806
1807     testPatternStatus("(.)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1808     testPatternStatus("(.+)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1809     testPatternStatus("(.?)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1810     testPatternStatus("(.*)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1811     testPatternStatus("(.+)?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1812     testPatternStatus("(.?)+", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1813
1814     // Nested groups.
1815     testPatternStatus("((foo)?((.)*)(bar)*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1816 }
1817
1818 TEST_F(ContentExtensionTest, MinimizingWithMoreFinalStatesThanNonFinalStates)
1819 {
1820     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^h[a-z://]+\"}},"
1821         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://foo.com/\"}},"
1822         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://bar.com/\"}}]");
1823
1824     testRequest(backend, mainDocumentRequest("http://foo.com/"), { ContentExtensions::ActionType::BlockLoad });
1825     testRequest(backend, mainDocumentRequest("http://bar.com/"), { ContentExtensions::ActionType::BlockLoad });
1826     testRequest(backend, mainDocumentRequest("attp://foo.com/"), { });
1827     testRequest(backend, mainDocumentRequest("attp://bar.com/"), { });
1828
1829     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1830     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1831     testRequest(backend, mainDocumentRequest("bttp://webkit.org/"), { });
1832     testRequest(backend, mainDocumentRequest("bttps://webkit.org/"), { });
1833     testRequest(backend, mainDocumentRequest("http://webkit.org/b"), { ContentExtensions::ActionType::BlockLoad });
1834     testRequest(backend, mainDocumentRequest("https://webkit.org/b"), { ContentExtensions::ActionType::BlockLoad });
1835     testRequest(backend, mainDocumentRequest("cttp://webkit.org/B"), { });
1836     testRequest(backend, mainDocumentRequest("cttps://webkit.org/B"), { });
1837 }
1838
1839 TEST_F(ContentExtensionTest, StatesWithDifferentActionsAreNotUnified1)
1840 {
1841     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://www.webkit.org/\"}},"
1842         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}},"
1843         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^attps://www.webkit.org/\"}}]");
1844
1845     testRequest(backend, mainDocumentRequest("http://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1846     testRequest(backend, mainDocumentRequest("https://www.webkit.org/"), { ContentExtensions::ActionType::BlockCookies });
1847     testRequest(backend, mainDocumentRequest("attps://www.webkit.org/"), { ContentExtensions::ActionType::BlockCookies });
1848     testRequest(backend, mainDocumentRequest("http://www.webkit.org/a"), { ContentExtensions::ActionType::BlockLoad });
1849     testRequest(backend, mainDocumentRequest("https://www.webkit.org/B"), { ContentExtensions::ActionType::BlockCookies });
1850     testRequest(backend, mainDocumentRequest("attps://www.webkit.org/c"), { ContentExtensions::ActionType::BlockCookies });
1851     testRequest(backend, mainDocumentRequest("http://www.whatwg.org/"), { });
1852     testRequest(backend, mainDocumentRequest("https://www.whatwg.org/"), { });
1853     testRequest(backend, mainDocumentRequest("attps://www.whatwg.org/"), { });
1854 }
1855
1856 TEST_F(ContentExtensionTest, StatesWithDifferentActionsAreNotUnified2)
1857 {
1858     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://www.webkit.org/\"}},"
1859         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}},"
1860         "{\"action\":{\"type\":\"css-display-none\", \"selector\":\"#foo\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}}]");
1861
1862     testRequest(backend, mainDocumentRequest("http://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1863     testRequest(backend, mainDocumentRequest("https://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
1864     testRequest(backend, mainDocumentRequest("https://www.whatwg.org/"), { });
1865     testRequest(backend, mainDocumentRequest("attps://www.whatwg.org/"), { });
1866 }
1867
1868 // The order in which transitions from the root will be processed is unpredictable.
1869 // To exercises the various options, this test exists in various version exchanging the transition to the final state.
1870 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge1)
1871 {
1872     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.a\"}},"
1873         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.a\"}},"
1874         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bac\"}},"
1875         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bbc\"}},"
1876         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCC\"}}]");
1877
1878     testRequest(backend, mainDocumentRequest("aza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1879     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1880     testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1881     testRequest(backend, mainDocumentRequest("bbc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1882     testRequest(backend, mainDocumentRequest("bcc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1883
1884     testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { });
1885     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { });
1886     testRequest(backend, mainDocumentRequest("acc://www.webkit.org/"), { });
1887
1888     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1889     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1890     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1891 }
1892 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge2)
1893 {
1894     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bac\"}},"
1895         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bbc\"}},"
1896         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCC\"}},"
1897         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.a\"}},"
1898         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.a\"}}]");
1899
1900     testRequest(backend, mainDocumentRequest("aza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1901     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1902     testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1903     testRequest(backend, mainDocumentRequest("bbc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1904     testRequest(backend, mainDocumentRequest("bcc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1905
1906     testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { });
1907     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { });
1908     testRequest(backend, mainDocumentRequest("acc://www.webkit.org/"), { });
1909
1910     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1911     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1912     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1913 }
1914 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge3)
1915 {
1916     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
1917         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}},"
1918         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^baa\"}},"
1919         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bba\"}},"
1920         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCA\"}}]");
1921
1922     testRequest(backend, mainDocumentRequest("azc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1923     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1924     testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1925     testRequest(backend, mainDocumentRequest("bba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1926     testRequest(backend, mainDocumentRequest("bca://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1927
1928     testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
1929     testRequest(backend, mainDocumentRequest("aba://www.webkit.org/"), { });
1930     testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
1931
1932     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1933     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1934     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1935 }
1936 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge4)
1937 {
1938     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^baa\"}},"
1939         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bba\"}},"
1940         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCA\"}},"
1941         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
1942         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}}]");
1943
1944     testRequest(backend, mainDocumentRequest("azc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1945     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1946     testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1947     testRequest(backend, mainDocumentRequest("bba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1948     testRequest(backend, mainDocumentRequest("bca://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1949
1950     testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
1951     testRequest(backend, mainDocumentRequest("aba://www.webkit.org/"), { });
1952     testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
1953
1954     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1955     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1956     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1957 }
1958
1959 TEST_F(ContentExtensionTest, FallbackTransitionsToOtherNodeInSameGroupDoesNotDifferentiateGroup)
1960 {
1961     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^aac\"}},"
1962         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
1963         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}}]");
1964
1965     testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1966     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1967     testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1968     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1969
1970     testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
1971     testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
1972     testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { });
1973 }
1974
1975 TEST_F(ContentExtensionTest, SimpleFallBackTransitionDifferentiator1)
1976 {
1977     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.bc.de\"}},"
1978         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.bd.ef\"}}]");
1979
1980     testRequest(backend, mainDocumentRequest("abbccde://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1981     testRequest(backend, mainDocumentRequest("aabcdde://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1982     testRequest(backend, mainDocumentRequest("aabddef://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1983     testRequest(backend, mainDocumentRequest("aabddef://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1984
1985     testRequest(backend, mainDocumentRequest("abcde://www.webkit.org/"), { });
1986     testRequest(backend, mainDocumentRequest("abdef://www.webkit.org/"), { });
1987 }
1988
1989 TEST_F(ContentExtensionTest, SimpleFallBackTransitionDifferentiator2)
1990 {
1991     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^cb.\"}},"
1992         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^db.b\"}}]");
1993
1994     testRequest(backend, mainDocumentRequest("cba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1995     testRequest(backend, mainDocumentRequest("cbb://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1996     testRequest(backend, mainDocumentRequest("dbab://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1997     testRequest(backend, mainDocumentRequest("dbxb://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1998
1999     testRequest(backend, mainDocumentRequest("cca://www.webkit.org/"), { });
2000     testRequest(backend, mainDocumentRequest("dddd://www.webkit.org/"), { });
2001     testRequest(backend, mainDocumentRequest("bbbb://www.webkit.org/"), { });
2002 }
2003
2004 // *** We have the following ranges intersections: ***
2005 // Full overlap.
2006 // 1)
2007 // A: |-----|
2008 // B:  |---|
2009 // 2)
2010 // A: |-----|
2011 // B:    |
2012 // 3)
2013 // A:  |---|
2014 // B: |-----|
2015 // 4)
2016 // A:    |
2017 // B: |-----|
2018 // One edge in common
2019 // 5)
2020 // A: |-|
2021 // B:   |-|
2022 // 6)
2023 // A: |
2024 // B: |-|
2025 // 7)
2026 // A: |-|
2027 // B:   |
2028 // 8)
2029 // A:   |-|
2030 // B: |-|
2031 // 9)
2032 // A:   |
2033 // B: |-|
2034 // 10)
2035 // A: |-|
2036 // B: |
2037 // B overlap on the left side of A.
2038 // 11)
2039 // A:   |---|
2040 // B: |---|
2041 // 12)
2042 // A:   |---|
2043 // B: |-----|
2044 // A overlap on the left side of B
2045 // 13)
2046 // A: |---|
2047 // B:   |---|
2048 // 14)
2049 // A: |-----|
2050 // B:   |---|
2051 // Equal ranges
2052 // 15)
2053 // A: |---|
2054 // B: |---|
2055 // 16)
2056 // A: |
2057 // B: |
2058
2059 TEST_F(ContentExtensionTest, RangeOverlapCase1)
2060 {
2061     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}},"
2062         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^[c-e]\"}}]");
2063
2064     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2065     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2066     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { }, 0);
2067     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { }, 0);
2068     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { }, 0);
2069     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2070     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2071     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2072
2073     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-m]\"}},"
2074         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"[c-e]\"}}]");
2075     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2076     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2077     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { }, 0);
2078     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { }, 0);
2079     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { }, 0);
2080     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2081     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2082     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2083 }
2084
2085 TEST_F(ContentExtensionTest, RangeOverlapCase2)
2086 {
2087     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}},"
2088         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^b\"}}]");
2089
2090     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2091     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { }, 0);
2092     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2093     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2094     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2095
2096     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-m]\"}},"
2097         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"l\"}}]");
2098     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2099     testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2100     testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { }, 0);
2101     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2102     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2103 }
2104
2105 TEST_F(ContentExtensionTest, RangeOverlapCase3)
2106 {
2107     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[b-d]\"}},"
2108         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}}]");
2109
2110     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2111     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2112     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2113     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2114     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2115     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2116
2117     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[b-d]\"}},"
2118         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-m]\"}}]");
2119     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2120     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2121     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2122     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2123     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2124     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2125 }
2126
2127 TEST_F(ContentExtensionTest, RangeOverlapCase4)
2128 {
2129     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^l\"}},"
2130         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}}]");
2131
2132     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2133     testRequest(matchBackend, mainDocumentRequest("k://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2134     testRequest(matchBackend, mainDocumentRequest("l://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2135     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2136     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2137
2138     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"l\"}},"
2139         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-m]\"}}]");
2140     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2141     testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2142     testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2143     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2144     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2145 }
2146
2147 TEST_F(ContentExtensionTest, RangeOverlapCase5)
2148 {
2149     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}},"
2150         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}}]");
2151
2152     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2153     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2154     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2155     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2156     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2157     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2158
2159     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-e]\"}},"
2160         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[e-h]\"}}]");
2161     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2162     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2163     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2164     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2165     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2166     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2167 }
2168
2169 TEST_F(ContentExtensionTest, RangeOverlapCase6)
2170 {
2171     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^e\"}},"
2172         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}}]");
2173
2174     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2175     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
2176     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2177     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2178     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2179     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2180
2181     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"e\"}},"
2182         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[e-h]\"}}]");
2183     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2184     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
2185     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2186     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2187     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2188     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2189 }
2190
2191 TEST_F(ContentExtensionTest, RangeOverlapCase7)
2192 {
2193     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}},"
2194         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^e\"}}]");
2195
2196     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2197     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2198     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2199     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
2200
2201     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-e]\"}},"
2202         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"e\"}}]");
2203     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2204     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2205     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2206     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
2207 }
2208
2209 TEST_F(ContentExtensionTest, RangeOverlapCase8)
2210 {
2211     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}},"
2212         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}}]");
2213
2214     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2215     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2216     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2217     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2218     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2219     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2220
2221     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-h]\"}},"
2222         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-e]\"}}]");
2223     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2224     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2225     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2226     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2227     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2228     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2229 }
2230
2231 TEST_F(ContentExtensionTest, RangeOverlapCase9)
2232 {
2233     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^e\"}},"
2234         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}}]");
2235
2236     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2237     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2238     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2239     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
2240
2241     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"e\"}},"
2242         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-e]\"}}]");
2243     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2244     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2245     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2246     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
2247 }
2248
2249 TEST_F(ContentExtensionTest, RangeOverlapCase10)
2250 {
2251     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}},"
2252         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^e\"}}]");
2253
2254     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2255     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
2256     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2257     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2258     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2259     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2260
2261     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-h]\"}},"
2262         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"e\"}}]");
2263     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2264     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
2265     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2266     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2267     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2268     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2269 }
2270
2271 TEST_F(ContentExtensionTest, RangeOverlapCase11)
2272 {
2273     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-g]\"}},"
2274         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[d-f]\"}}]");
2275
2276     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
2277     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2278     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2279     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2280     testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2281     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2282
2283     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-g]\"}},"
2284         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[d-f]\"}}]");
2285     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
2286     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2287     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2288     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2289     testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2290     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2291 }
2292
2293
2294 TEST_F(ContentExtensionTest, RangeOverlapCase12)
2295 {
2296     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-g]\"}},"
2297         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[d-g]\"}}]");
2298
2299     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
2300     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2301     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2302     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2303     testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2304     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2305
2306     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-g]\"}},"
2307         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[d-g]\"}}]");
2308     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
2309     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2310     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2311     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2312     testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2313     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2314 }
2315
2316 TEST_F(ContentExtensionTest, RangeOverlapCase13)
2317 {
2318     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[b-d]\"}},"
2319         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[c-e]\"}}]");
2320
2321     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2322     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2323     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2324     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2325     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2326     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2327
2328     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[b-d]\"}},"
2329         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[c-e]\"}}]");
2330     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2331     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2332     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2333     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2334     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2335     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2336 }
2337
2338 TEST_F(ContentExtensionTest, RangeOverlapCase14)
2339 {
2340     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[b-e]\"}},"
2341         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[c-e]\"}}]");
2342
2343     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2344     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2345     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2346     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2347     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2348     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2349
2350     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[b-e]\"}},"
2351         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[c-e]\"}}]");
2352     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2353     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2354     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2355     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2356     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2357     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2358 }
2359
2360 TEST_F(ContentExtensionTest, RangeOverlapCase15)
2361 {
2362     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[c-f]\"}},"
2363         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[c-f]\"}}]");
2364
2365     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2366     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { });
2367     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2368     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2369     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2370     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2371     testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { });
2372
2373     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[c-f]\"}},"
2374         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[c-f]\"}}]");
2375     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2376     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { });
2377     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2378     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2379     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2380     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2381     testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { });
2382 }
2383
2384 TEST_F(ContentExtensionTest, RangeOverlapCase16)
2385 {
2386     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^c\"}},"
2387         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^c\"}}]");
2388
2389     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2390     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { });
2391     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2392     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
2393     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { });
2394
2395     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"c\"}},"
2396         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"c\"}}]");
2397     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2398     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { });
2399     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2400     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
2401     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { });
2402 }
2403
2404 TEST_F(ContentExtensionTest, QuantifiedOneOrMoreRangesCase11And13)
2405 {
2406     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[c-e]+[g-i]+YYY\"}},"
2407         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[b-d]+[h-j]+YYY\"}}]");
2408
2409     // The interesting ranges only match between 'b' and 'k', plus a gap in 'f'.
2410     testRequest(searchBackend, mainDocumentRequest("zzz://www.aayyy.xxx/"), { });
2411     testRequest(searchBackend, mainDocumentRequest("zzz://www.abyyy.xxx/"), { });
2412     testRequest(searchBackend, mainDocumentRequest("zzz://www.acyyy.xxx/"), { });
2413     testRequest(searchBackend, mainDocumentRequest("zzz://www.adyyy.xxx/"), { });
2414     testRequest(searchBackend, mainDocumentRequest("zzz://www.aeyyy.xxx/"), { });
2415     testRequest(searchBackend, mainDocumentRequest("zzz://www.afyyy.xxx/"), { });
2416     testRequest(searchBackend, mainDocumentRequest("zzz://www.agyyy.xxx/"), { });
2417     testRequest(searchBackend, mainDocumentRequest("zzz://www.ahyyy.xxx/"), { });
2418     testRequest(searchBackend, mainDocumentRequest("zzz://www.aiyyy.xxx/"), { });
2419     testRequest(searchBackend, mainDocumentRequest("zzz://www.ajyyy.xxx/"), { });
2420     testRequest(searchBackend, mainDocumentRequest("zzz://www.akyyy.xxx/"), { });
2421
2422     // 'b' is the first character of the second rule.
2423     testRequest(searchBackend, mainDocumentRequest("zzz://www.byyy.xxx/"), { });
2424     testRequest(searchBackend, mainDocumentRequest("zzz://www.bayyy.xxx/"), { });
2425     testRequest(searchBackend, mainDocumentRequest("zzz://www.bbyyy.xxx/"), { });
2426     testRequest(searchBackend, mainDocumentRequest("zzz://www.bcyyy.xxx/"), { });
2427     testRequest(searchBackend, mainDocumentRequest("zzz://www.bdyyy.xxx/"), { });
2428     testRequest(searchBackend, mainDocumentRequest("zzz://www.beyyy.xxx/"), { });
2429     testRequest(searchBackend, mainDocumentRequest("zzz://www.bfyyy.xxx/"), { });
2430     testRequest(searchBackend, mainDocumentRequest("zzz://www.bgyyy.xxx/"), { });
2431     testRequest(searchBackend, mainDocumentRequest("zzz://www.bhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2432     testRequest(searchBackend, mainDocumentRequest("zzz://www.biyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2433     testRequest(searchBackend, mainDocumentRequest("zzz://www.bjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2434     testRequest(searchBackend, mainDocumentRequest("zzz://www.bkyyy.xxx/"), { });
2435
2436     // 'c' is the first character of the first rule, and it overlaps the first character of the second rule.
2437     testRequest(searchBackend, mainDocumentRequest("zzz://www.cyyy.xxx/"), { });
2438     testRequest(searchBackend, mainDocumentRequest("zzz://www.cayyy.xxx/"), { });
2439     testRequest(searchBackend, mainDocumentRequest("zzz://www.cbyyy.xxx/"), { });
2440     testRequest(searchBackend, mainDocumentRequest("zzz://www.ccyyy.xxx/"), { });
2441     testRequest(searchBackend, mainDocumentRequest("zzz://www.cdyyy.xxx/"), { });
2442     testRequest(searchBackend, mainDocumentRequest("zzz://www.ceyyy.xxx/"), { });
2443     testRequest(searchBackend, mainDocumentRequest("zzz://www.cfyyy.xxx/"), { });
2444     testRequest(searchBackend, mainDocumentRequest("zzz://www.cgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2445     testRequest(searchBackend, mainDocumentRequest("zzz://www.chyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2446     testRequest(searchBackend, mainDocumentRequest("zzz://www.ciyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2447     testRequest(searchBackend, mainDocumentRequest("zzz://www.cjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2448     testRequest(searchBackend, mainDocumentRequest("zzz://www.ckyyy.xxx/"), { });
2449
2450     // 'd' is in the first range of both rule. This series cover overlaps between the two rules.
2451     testRequest(searchBackend, mainDocumentRequest("zzz://www.dgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2452     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2453     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2454     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2455     testRequest(searchBackend, mainDocumentRequest("zzz://www.degyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2456     testRequest(searchBackend, mainDocumentRequest("zzz://www.dehyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2457     testRequest(searchBackend, mainDocumentRequest("zzz://www.dfgyyy.xxx/"), { });
2458     testRequest(searchBackend, mainDocumentRequest("zzz://www.dfhyyy.xxx/"), { });
2459     testRequest(searchBackend, mainDocumentRequest("zzz://www.djyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2460     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2461     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2462 }
2463
2464 TEST_F(ContentExtensionTest, QuantifiedOneOrMoreRangesCase11And13InGroups)
2465 {
2466     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"([c-e])+([g-i]+YYY)\"}},"
2467         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[b-d]+[h-j]+YYY\"}}]");
2468
2469     // The interesting ranges only match between 'b' and 'k', plus a gap in 'f'.
2470     testRequest(searchBackend, mainDocumentRequest("zzz://www.aayyy.xxx/"), { });
2471     testRequest(searchBackend, mainDocumentRequest("zzz://www.abyyy.xxx/"), { });
2472     testRequest(searchBackend, mainDocumentRequest("zzz://www.acyyy.xxx/"), { });
2473     testRequest(searchBackend, mainDocumentRequest("zzz://www.adyyy.xxx/"), { });
2474     testRequest(searchBackend, mainDocumentRequest("zzz://www.aeyyy.xxx/"), { });
2475     testRequest(searchBackend, mainDocumentRequest("zzz://www.afyyy.xxx/"), { });
2476     testRequest(searchBackend, mainDocumentRequest("zzz://www.agyyy.xxx/"), { });
2477     testRequest(searchBackend, mainDocumentRequest("zzz://www.ahyyy.xxx/"), { });
2478     testRequest(searchBackend, mainDocumentRequest("zzz://www.aiyyy.xxx/"), { });
2479     testRequest(searchBackend, mainDocumentRequest("zzz://www.ajyyy.xxx/"), { });
2480     testRequest(searchBackend, mainDocumentRequest("zzz://www.akyyy.xxx/"), { });
2481
2482     // 'b' is the first character of the second rule.
2483     testRequest(searchBackend, mainDocumentRequest("zzz://www.byyy.xxx/"), { });
2484     testRequest(searchBackend, mainDocumentRequest("zzz://www.bayyy.xxx/"), { });
2485     testRequest(searchBackend, mainDocumentRequest("zzz://www.bbyyy.xxx/"), { });
2486     testRequest(searchBackend, mainDocumentRequest("zzz://www.bcyyy.xxx/"), { });
2487     testRequest(searchBackend, mainDocumentRequest("zzz://www.bdyyy.xxx/"), { });
2488     testRequest(searchBackend, mainDocumentRequest("zzz://www.beyyy.xxx/"), { });
2489     testRequest(searchBackend, mainDocumentRequest("zzz://www.bfyyy.xxx/"), { });
2490     testRequest(searchBackend, mainDocumentRequest("zzz://www.bgyyy.xxx/"), { });
2491     testRequest(searchBackend, mainDocumentRequest("zzz://www.bhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2492     testRequest(searchBackend, mainDocumentRequest("zzz://www.biyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2493     testRequest(searchBackend, mainDocumentRequest("zzz://www.bjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2494     testRequest(searchBackend, mainDocumentRequest("zzz://www.bkyyy.xxx/"), { });
2495
2496     // 'c' is the first character of the first rule, and it overlaps the first character of the second rule.
2497     testRequest(searchBackend, mainDocumentRequest("zzz://www.cyyy.xxx/"), { });
2498     testRequest(searchBackend, mainDocumentRequest("zzz://www.cayyy.xxx/"), { });
2499     testRequest(searchBackend, mainDocumentRequest("zzz://www.cbyyy.xxx/"), { });
2500     testRequest(searchBackend, mainDocumentRequest("zzz://www.ccyyy.xxx/"), { });
2501     testRequest(searchBackend, mainDocumentRequest("zzz://www.cdyyy.xxx/"), { });
2502     testRequest(searchBackend, mainDocumentRequest("zzz://www.ceyyy.xxx/"), { });
2503     testRequest(searchBackend, mainDocumentRequest("zzz://www.cfyyy.xxx/"), { });
2504     testRequest(searchBackend, mainDocumentRequest("zzz://www.cgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2505     testRequest(searchBackend, mainDocumentRequest("zzz://www.chyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2506     testRequest(searchBackend, mainDocumentRequest("zzz://www.ciyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2507     testRequest(searchBackend, mainDocumentRequest("zzz://www.cjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2508     testRequest(searchBackend, mainDocumentRequest("zzz://www.ckyyy.xxx/"), { });
2509
2510     // 'd' is in the first range of both rule. This series cover overlaps between the two rules.
2511     testRequest(searchBackend, mainDocumentRequest("zzz://www.dgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2512     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2513     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2514     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2515     testRequest(searchBackend, mainDocumentRequest("zzz://www.degyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2516     testRequest(searchBackend, mainDocumentRequest("zzz://www.dehyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2517     testRequest(searchBackend, mainDocumentRequest("zzz://www.dfgyyy.xxx/"), { });
2518     testRequest(searchBackend, mainDocumentRequest("zzz://www.dfhyyy.xxx/"), { });
2519     testRequest(searchBackend, mainDocumentRequest("zzz://www.djyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2520     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2521     testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2522 }
2523
2524 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase1)
2525 {
2526     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-m]\"}},"
2527         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-e]\"}}]");
2528
2529     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2530     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2531     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { }, 0);
2532     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { }, 0);
2533     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { }, 0);
2534     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2535     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2536     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2537
2538     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-m]\"}},"
2539         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"(bar)*[c-e]\"}}]");
2540     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2541     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2542     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { }, 0);
2543     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { }, 0);
2544     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { }, 0);
2545     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2546     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2547     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2548 }
2549
2550
2551 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase2)
2552 {
2553     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-m]\"}},"
2554         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^(bar)*b\"}}]");
2555
2556     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2557     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { }, 0);
2558     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2559     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2560     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2561
2562     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-m]\"}},"
2563         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"(bar)*l\"}}]");
2564     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2565     testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2566     testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { }, 0);
2567     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2568     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2569 }
2570
2571 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase3)
2572 {
2573     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[b-d]\"}},"
2574         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-m]\"}}]");
2575
2576     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2577     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2578     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2579     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2580     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2581     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2582
2583     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[b-d]\"}},"
2584         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-m]\"}}]");
2585     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2586     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2587     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2588     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2589     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2590     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2591 }
2592
2593 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase4)
2594 {
2595     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*l\"}},"
2596         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-m]\"}}]");
2597
2598     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2599     testRequest(matchBackend, mainDocumentRequest("k://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2600     testRequest(matchBackend, mainDocumentRequest("l://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2601     testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2602     testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
2603
2604     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*l\"}},"
2605         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-m]\"}}]");
2606     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2607     testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2608     testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2609     testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2610     testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
2611 }
2612
2613 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase5)
2614 {
2615     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-e]\"}},"
2616         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[e-h]\"}}]");
2617
2618     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2619     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2620     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2621     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2622     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2623     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2624
2625     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-e]\"}},"
2626         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[e-h]\"}}]");
2627     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2628     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2629     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2630     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2631     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2632     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2633 }
2634
2635 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase6)
2636 {
2637     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*e\"}},"
2638         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[e-h]\"}}]");
2639
2640     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2641     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
2642     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2643     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2644     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2645     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2646
2647     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*e\"}},"
2648         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[e-h]\"}}]");
2649     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2650     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
2651     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2652     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2653     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2654     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2655 }
2656
2657 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase7)
2658 {
2659     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-e]\"}},"
2660         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*e\"}}]");
2661
2662     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2663     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2664     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2665     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
2666
2667     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-e]\"}},"
2668         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*e\"}}]");
2669     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2670     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2671     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2672     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
2673 }
2674
2675 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase8)
2676 {
2677     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-h]\"}},"
2678         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-e]\"}}]");
2679
2680     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2681     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2682     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2683     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2684     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2685     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2686
2687     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-h]\"}},"
2688         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-e]\"}}]");
2689     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2690     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2691     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2692     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2693     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2694     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2695 }
2696
2697 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase9)
2698 {
2699     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*e\"}},"
2700         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-e]\"}}]");
2701
2702     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2703     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2704     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2705     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
2706
2707     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*e\"}},"
2708         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-e]\"}}]");
2709     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2710     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2711     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2712     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
2713 }
2714
2715 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase10)
2716 {
2717     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-h]\"}},"
2718         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*e\"}}]");
2719
2720     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2721     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
2722     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2723     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2724     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2725     testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
2726
2727     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-h]\"}},"
2728         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*e\"}}]");
2729     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2730     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
2731     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2732     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2733     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2734     testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
2735 }
2736
2737 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase11)
2738 {
2739     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-g]\"}},"
2740         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[d-f]\"}}]");
2741
2742     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
2743     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2744     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2745     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2746     testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2747     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2748
2749     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-g]\"}},"
2750         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[d-f]\"}}]");
2751     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
2752     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2753     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2754     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2755     testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2756     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2757 }
2758
2759
2760 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase12)
2761 {
2762     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-g]\"}},"
2763         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[d-g]\"}}]");
2764
2765     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
2766     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2767     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2768     testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2769     testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2770     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2771
2772     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-g]\"}},"
2773         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[d-g]\"}}]");
2774     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
2775     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2776     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2777     testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2778     testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2779     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2780 }
2781
2782 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase13)
2783 {
2784     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[b-d]\"}},"
2785         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-e]\"}}]");
2786
2787     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2788     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2789     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2790     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2791     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2792     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2793
2794     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[b-d]\"}},"
2795         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[c-e]\"}}]");
2796     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2797     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2798     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2799     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2800     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
2801     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2802 }
2803
2804 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase14)
2805 {
2806     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[b-e]\"}},"
2807         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-e]\"}}]");
2808
2809     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
2810     testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
2811     testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2812     testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2813     testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2814     testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
2815
2816     auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[b-e]\"}},"
2817         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[c-e]\"}}]");
2818     testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
2819     testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
2820     testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2821     testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2822     testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
2823     testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
2824 }
2825
2826 TEST_F(ContentExtensionTest, CombinedRangeOverlapCase15)
2827 {
2828     auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[c-f]\"}},"
2829         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-f]\"}}]");
2830
2831     testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"