[Content Extensions] Add a way to match a domain but not subdomains
[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/ContentExtensionsBackend.h>
34 #include <WebCore/DFA.h>
35 #include <WebCore/DFABytecodeCompiler.h>
36 #include <WebCore/DFABytecodeInterpreter.h>
37 #include <WebCore/NFA.h>
38 #include <WebCore/NFAToDFA.h>
39 #include <WebCore/ResourceLoadInfo.h>
40 #include <WebCore/URL.h>
41 #include <WebCore/URLFilterParser.h>
42 #include <wtf/MainThread.h>
43 #include <wtf/RunLoop.h>
44 #include <wtf/text/CString.h>
45 #include <wtf/text/StringBuilder.h>
46
47 namespace WebCore {
48 namespace ContentExtensions {
49 inline std::ostream& operator<<(std::ostream& os, const ActionType& action)
50 {
51     switch (action) {
52     case ActionType::BlockLoad:
53         return os << "ContentFilterAction::BlockLoad";
54     case ActionType::BlockCookies:
55         return os << "ContentFilterAction::BlockCookies";
56     case ActionType::CSSDisplayNoneSelector:
57         return os << "ContentFilterAction::CSSDisplayNone";
58     case ActionType::CSSDisplayNoneStyleSheet:
59         return os << "ContentFilterAction::CSSDisplayNoneStyleSheet";
60     case ActionType::IgnorePreviousRules:
61         return os << "ContentFilterAction::IgnorePreviousRules";
62     case ActionType::InvalidAction:
63         return os << "ContentFilterAction::InvalidAction";
64     }
65 }
66 }
67 }
68
69 using namespace WebCore;
70
71 namespace TestWebKitAPI {
72
73 class ContentExtensionTest : public testing::Test {
74 public:
75     virtual void SetUp()
76     {
77         WTF::initializeMainThread();
78         JSC::initializeThreading();
79         RunLoop::initializeMainRunLoop();
80     }
81 };
82
83 struct CompiledContentExtensionData {
84     Vector<ContentExtensions::SerializedActionByte> actions;
85     Vector<ContentExtensions::DFABytecode> filtersWithoutDomains;
86     Vector<ContentExtensions::DFABytecode> filtersWithDomains;
87     Vector<ContentExtensions::DFABytecode> domainFilters;
88 };
89
90 class InMemoryContentExtensionCompilationClient final : public ContentExtensions::ContentExtensionCompilationClient {
91 public:
92     InMemoryContentExtensionCompilationClient(CompiledContentExtensionData& data)
93         : m_data(data)
94     {
95         EXPECT_EQ(data.actions.size(), 0ull);
96         EXPECT_EQ(data.filtersWithoutDomains.size(), 0ull);
97         EXPECT_EQ(data.filtersWithDomains.size(), 0ull);
98         EXPECT_EQ(data.domainFilters.size(), 0ull);
99     }
100
101     virtual void writeActions(Vector<ContentExtensions::SerializedActionByte>&& actions) override
102     {
103         EXPECT_FALSE(finalized);
104         EXPECT_EQ(m_data.actions.size(), 0ull);
105         EXPECT_EQ(m_data.filtersWithoutDomains.size(), 0ull);
106         EXPECT_EQ(m_data.filtersWithDomains.size(), 0ull);
107         EXPECT_EQ(m_data.domainFilters.size(), 0ull);
108         m_data.actions.appendVector(actions);
109     }
110     
111     virtual void writeFiltersWithoutDomainsBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) override
112     {
113         EXPECT_FALSE(finalized);
114         EXPECT_EQ(m_data.filtersWithDomains.size(), 0ull);
115         EXPECT_EQ(m_data.domainFilters.size(), 0ull);
116         m_data.filtersWithoutDomains.appendVector(bytecode);
117     }
118     
119     virtual void writeFiltersWithDomainsBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) override
120     {
121         EXPECT_FALSE(finalized);
122         EXPECT_EQ(m_data.domainFilters.size(), 0ull);
123         m_data.filtersWithDomains.appendVector(bytecode);
124     }
125     
126     virtual void writeDomainFiltersBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) override
127     {
128         EXPECT_FALSE(finalized);
129         m_data.domainFilters.appendVector(bytecode);
130     }
131     
132     virtual void finalize() override
133     {
134         finalized = true;
135     }
136
137 private:
138     CompiledContentExtensionData& m_data;
139     bool finalized { false };
140 };
141
142 class InMemoryCompiledContentExtension : public ContentExtensions::CompiledContentExtension {
143 public:
144     static RefPtr<InMemoryCompiledContentExtension> createFromFilter(String&& filter)
145     {
146         CompiledContentExtensionData extensionData;
147         InMemoryContentExtensionCompilationClient client(extensionData);
148         auto compilerError = ContentExtensions::compileRuleList(client, WTF::move(filter));
149         if (compilerError) {
150             // Compiling should always succeed here. We have other tests for compile failures.
151             EXPECT_TRUE(false);
152             return nullptr;
153         }
154
155         return InMemoryCompiledContentExtension::create(WTF::move(extensionData));
156     }
157
158     static RefPtr<InMemoryCompiledContentExtension> create(CompiledContentExtensionData&& data)
159     {
160         return adoptRef(new InMemoryCompiledContentExtension(WTF::move(data)));
161     }
162
163     virtual ~InMemoryCompiledContentExtension()
164     {
165     }
166
167     virtual const ContentExtensions::SerializedActionByte* actions() const override { return m_data.actions.data(); }
168     virtual unsigned actionsLength() const override { return m_data.actions.size(); }
169     virtual const ContentExtensions::DFABytecode* filtersWithoutDomainsBytecode() const override { return m_data.filtersWithoutDomains.data(); }
170     virtual unsigned filtersWithoutDomainsBytecodeLength() const override { return m_data.filtersWithoutDomains.size(); }
171     virtual const ContentExtensions::DFABytecode* filtersWithDomainsBytecode() const override { return m_data.filtersWithDomains.data(); }
172     virtual unsigned filtersWithDomainsBytecodeLength() const override { return m_data.filtersWithDomains.size(); }
173     virtual const ContentExtensions::DFABytecode* domainFiltersBytecode() const override { return m_data.domainFilters.data(); }
174     virtual unsigned domainFiltersBytecodeLength() const override { return m_data.domainFilters.size(); }
175
176 private:
177     InMemoryCompiledContentExtension(CompiledContentExtensionData&& data)
178         : m_data(WTF::move(data))
179     {
180     }
181
182     CompiledContentExtensionData m_data;
183 };
184
185 void static testRequest(ContentExtensions::ContentExtensionsBackend contentExtensionsBackend, const ResourceLoadInfo& resourceLoadInfo, Vector<ContentExtensions::ActionType> expectedActions, bool ignorePreviousRules = false)
186 {
187     auto actions = contentExtensionsBackend.actionsForResourceLoad(resourceLoadInfo);
188     unsigned expectedSize = actions.size();
189     if (!ignorePreviousRules)
190         expectedSize--; // The last action is applying the compiled stylesheet.
191     
192     EXPECT_EQ(expectedActions.size(), expectedSize);
193     if (expectedActions.size() != expectedSize)
194         return;
195
196     for (unsigned i = 0; i < expectedActions.size(); ++i)
197         EXPECT_EQ(expectedActions[i], actions[i].type());
198     if (!ignorePreviousRules)
199         EXPECT_EQ(actions[actions.size() - 1].type(), ContentExtensions::ActionType::CSSDisplayNoneStyleSheet);
200 }
201
202 static ResourceLoadInfo mainDocumentRequest(const char* url, ResourceType resourceType = ResourceType::Document)
203 {
204     return { URL(URL(), url), URL(URL(), url), resourceType };
205 }
206
207 static ResourceLoadInfo subResourceRequest(const char* url, const char* mainDocumentURL, ResourceType resourceType = ResourceType::Document)
208 {
209     return { URL(URL(), url), URL(URL(), mainDocumentURL), resourceType };
210 }
211
212 ContentExtensions::ContentExtensionsBackend makeBackend(const char* json)
213 {
214     auto extension = InMemoryCompiledContentExtension::createFromFilter(json);
215     ContentExtensions::ContentExtensionsBackend backend;
216     backend.addContentExtension("testFilter", extension);
217     return backend;
218 }
219
220 static Vector<ContentExtensions::NFA> createNFAs(ContentExtensions::CombinedURLFilters& combinedURLFilters)
221 {
222     Vector<ContentExtensions::NFA> nfas;
223
224     combinedURLFilters.processNFAs(std::numeric_limits<size_t>::max(), [&](ContentExtensions::NFA&& nfa) {
225         nfas.append(WTF::move(nfa));
226     });
227
228     return nfas;
229 }
230
231 TEST_F(ContentExtensionTest, Basic)
232 {
233     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]");
234
235     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
236 }
237
238 TEST_F(ContentExtensionTest, RangeBasic)
239 {
240     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"w[0-9]c\", \"url-filter-is-case-sensitive\":true}},"
241         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"[A-H][a-z]cko\", \"url-filter-is-case-sensitive\":true}}]");
242
243     testRequest(backend, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::BlockLoad });
244     testRequest(backend, mainDocumentRequest("w2c://whatwg.org/"), { ContentExtensions::ActionType::BlockLoad });
245     testRequest(backend, mainDocumentRequest("http://webkit.org/w0c"), { ContentExtensions::ActionType::BlockLoad });
246     testRequest(backend, mainDocumentRequest("http://webkit.org/wac"), { });
247     testRequest(backend, mainDocumentRequest("http://webkit.org/wAc"), { });
248
249     // Note: URL parsing and canonicalization lowercase the scheme and hostname.
250     testRequest(backend, mainDocumentRequest("Aacko://webkit.org"), { });
251     testRequest(backend, mainDocumentRequest("aacko://webkit.org"), { });
252     testRequest(backend, mainDocumentRequest("http://gCcko.org/"), { });
253     testRequest(backend, mainDocumentRequest("http://gccko.org/"), { });
254
255     testRequest(backend, mainDocumentRequest("http://webkit.org/Gecko"), { ContentExtensions::ActionType::BlockCookies });
256     testRequest(backend, mainDocumentRequest("http://webkit.org/gecko"), { });
257     testRequest(backend, mainDocumentRequest("http://webkit.org/GEcko"), { });
258 }
259
260 TEST_F(ContentExtensionTest, RangeExclusionGeneratingUniversalTransition)
261 {
262     // Transition of the type ([^X]X) effictively transition on every input.
263     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[^a]+afoobar\"}}]");
264
265     testRequest(backend, mainDocumentRequest("http://w3c.org"), { });
266
267     testRequest(backend, mainDocumentRequest("http://w3c.org/foobafoobar"), { ContentExtensions::ActionType::BlockLoad });
268     testRequest(backend, mainDocumentRequest("http://w3c.org/foobarfoobar"), { });
269     testRequest(backend, mainDocumentRequest("http://w3c.org/FOOBAFOOBAR"), { ContentExtensions::ActionType::BlockLoad });
270     testRequest(backend, mainDocumentRequest("http://w3c.org/FOOBARFOOBAR"), { });
271
272     // The character before the "a" prefix cannot be another "a".
273     testRequest(backend, mainDocumentRequest("http://w3c.org/aafoobar"), { });
274     testRequest(backend, mainDocumentRequest("http://w3c.org/Aafoobar"), { });
275     testRequest(backend, mainDocumentRequest("http://w3c.org/aAfoobar"), { });
276     testRequest(backend, mainDocumentRequest("http://w3c.org/AAfoobar"), { });
277 }
278
279 TEST_F(ContentExtensionTest, PatternStartingWithGroup)
280 {
281     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(http://whatwg\\\\.org/)?webkit\134\134.org\"}}]");
282
283     testRequest(backend, mainDocumentRequest("http://whatwg.org/webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
284     testRequest(backend, mainDocumentRequest("http://whatwg.org/webkit.org"), { ContentExtensions::ActionType::BlockLoad });
285     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
286     testRequest(backend, mainDocumentRequest("http://whatwg.org/"), { });
287     testRequest(backend, mainDocumentRequest("http://whatwg.org"), { });
288 }
289
290 TEST_F(ContentExtensionTest, PatternNestedGroups)
291 {
292     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/(foo(bar)*)+\"}}]");
293
294     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
295     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
296     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarbar"), { ContentExtensions::ActionType::BlockLoad });
297     testRequest(backend, mainDocumentRequest("http://webkit.org/foofoobar"), { ContentExtensions::ActionType::BlockLoad });
298     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
299     testRequest(backend, mainDocumentRequest("http://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
300     testRequest(backend, mainDocumentRequest("http://webkit.org/foor"), { ContentExtensions::ActionType::BlockLoad });
301
302     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
303     testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
304     testRequest(backend, mainDocumentRequest("http://webkit.org/fobar"), { });
305 }
306
307 TEST_F(ContentExtensionTest, MatchPastEndOfString)
308 {
309     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".+\"}}]");
310
311     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
312     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
313     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
314     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarbar"), { ContentExtensions::ActionType::BlockLoad });
315     testRequest(backend, mainDocumentRequest("http://webkit.org/foofoobar"), { ContentExtensions::ActionType::BlockLoad });
316     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
317     testRequest(backend, mainDocumentRequest("http://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
318     testRequest(backend, mainDocumentRequest("http://webkit.org/foor"), { ContentExtensions::ActionType::BlockLoad });
319 }
320
321 TEST_F(ContentExtensionTest, StartOfLineAssertion)
322 {
323     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^foobar\"}}]");
324
325     testRequest(backend, mainDocumentRequest("foobar://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
326     testRequest(backend, mainDocumentRequest("foobars:///foobar"), { ContentExtensions::ActionType::BlockLoad });
327     testRequest(backend, mainDocumentRequest("foobarfoobar:///foobarfoobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
328
329     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoo"), { });
330     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarf"), { });
331     testRequest(backend, mainDocumentRequest("http://foobar.org/"), { });
332     testRequest(backend, mainDocumentRequest("http://foobar.org/"), { });
333 }
334
335 TEST_F(ContentExtensionTest, EndOfLineAssertion)
336 {
337     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foobar$\"}}]");
338
339     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
340     testRequest(backend, mainDocumentRequest("file:///foobar"), { ContentExtensions::ActionType::BlockLoad });
341     testRequest(backend, mainDocumentRequest("file:///foobarfoobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
342
343     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoo"), { });
344     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarf"), { });
345 }
346
347 TEST_F(ContentExtensionTest, EndOfLineAssertionWithInvertedCharacterSet)
348 {
349     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[^y]$\"}}]");
350
351     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
352     testRequest(backend, mainDocumentRequest("http://webkit.org/a"), { ContentExtensions::ActionType::BlockLoad });
353     testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
354     testRequest(backend, mainDocumentRequest("http://webkit.org/Ya"), { ContentExtensions::ActionType::BlockLoad });
355     testRequest(backend, mainDocumentRequest("http://webkit.org/yFoobar"), { ContentExtensions::ActionType::BlockLoad });
356     testRequest(backend, mainDocumentRequest("http://webkit.org/y"), { });
357     testRequest(backend, mainDocumentRequest("http://webkit.org/Y"), { });
358     testRequest(backend, mainDocumentRequest("http://webkit.org/foobary"), { });
359     testRequest(backend, mainDocumentRequest("http://webkit.org/foobarY"), { });
360 }
361
362 TEST_F(ContentExtensionTest, PrefixInfixSuffixExactMatch)
363 {
364     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"infix\"}},"
365         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^prefix\"}},"
366         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"suffix$\"}},"
367         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://exact\\\\.org/$\"}}]");
368
369     testRequest(backend, mainDocumentRequest("infix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
370     testRequest(backend, mainDocumentRequest("http://infix.org/"), { ContentExtensions::ActionType::BlockLoad });
371     testRequest(backend, mainDocumentRequest("https://webkit.org/infix"), { ContentExtensions::ActionType::BlockLoad });
372
373     testRequest(backend, mainDocumentRequest("prefix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
374     testRequest(backend, mainDocumentRequest("https://prefix.org/"), { });
375     testRequest(backend, mainDocumentRequest("https://webkit.org/prefix"), { });
376
377     testRequest(backend, mainDocumentRequest("https://webkit.org/suffix"), { ContentExtensions::ActionType::BlockLoad });
378     testRequest(backend, mainDocumentRequest("https://suffix.org/"), { });
379     testRequest(backend, mainDocumentRequest("suffix://webkit.org/"), { });
380
381     testRequest(backend, mainDocumentRequest("http://exact.org/"), { ContentExtensions::ActionType::BlockLoad });
382     testRequest(backend, mainDocumentRequest("http://exact.org/oops"), { });
383 }
384
385 TEST_F(ContentExtensionTest, DuplicatedMatchAllTermsInVariousFormat)
386 {
387     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*.*(.)*(.*)(.+)*(.?)*infix\"}},"
388         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"pre(.?)+(.+)?post\"}}]");
389
390     testRequest(backend, mainDocumentRequest("infix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
391     testRequest(backend, mainDocumentRequest("http://infix.org/"), { ContentExtensions::ActionType::BlockLoad });
392     testRequest(backend, mainDocumentRequest("https://webkit.org/infix"), { ContentExtensions::ActionType::BlockLoad });
393
394     testRequest(backend, mainDocumentRequest("pre://webkit.org/post"), { ContentExtensions::ActionType::BlockLoad });
395     testRequest(backend, mainDocumentRequest("http://prepost.org/"), { ContentExtensions::ActionType::BlockLoad });
396     testRequest(backend, mainDocumentRequest("https://pre.org/posttail"), { ContentExtensions::ActionType::BlockLoad });
397     testRequest(backend, mainDocumentRequest("https://pre.pre/posttail"), { ContentExtensions::ActionType::BlockLoad });
398     testRequest(backend, mainDocumentRequest("https://pre.org/posttailpost"), { ContentExtensions::ActionType::BlockLoad });
399
400     testRequest(backend, mainDocumentRequest("https://post.org/pre"), { });
401     testRequest(backend, mainDocumentRequest("https://pre.org/pre"), { });
402     testRequest(backend, mainDocumentRequest("https://post.org/post"), { });
403 }
404
405 TEST_F(ContentExtensionTest, DomainTriggers)
406 {
407     auto ifDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\"]}}]");
408     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
409     testRequest(ifDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
410     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
411     testRequest(ifDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
412     testRequest(ifDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
413     testRequest(ifDomainBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
414     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
415     testRequest(ifDomainBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
416     testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.organization/test.html"), { });
417     
418     auto unlessDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"webkit.org\"]}}]");
419     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
420     testRequest(unlessDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
421     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
422     testRequest(unlessDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
423     testRequest(unlessDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
424     testRequest(unlessDomainBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
425     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
426     testRequest(unlessDomainBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
427     testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.organization/test.html"), { ContentExtensions::ActionType::BlockLoad });
428     
429     auto ifDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"*webkit.org\"]}}]");
430     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
431     testRequest(ifDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
432     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
433     testRequest(ifDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
434     testRequest(ifDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
435     testRequest(ifDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
436     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
437     testRequest(ifDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
438     testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.html"), { });
439     
440     auto unlessDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"*webkit.org\"]}}]");
441     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
442     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
443     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
444     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
445     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
446     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
447     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
448     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
449     testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.html"), { ContentExtensions::ActionType::BlockLoad });
450
451     auto ifSubDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"sub1.webkit.org\"]}}]");
452     testRequest(ifSubDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
453     testRequest(ifSubDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
454     testRequest(ifSubDomainBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
455     testRequest(ifSubDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
456
457     auto ifSubDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"*sub1.webkit.org\"]}}]");
458     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
459     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
460     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
461     testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
462
463     auto unlessSubDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"sub1.webkit.org\"]}}]");
464     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
465     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
466     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { });
467     testRequest(unlessSubDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
468     
469     auto unlessSubDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"*sub1.webkit.org\"]}}]");
470     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
471     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
472     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { });
473     testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
474
475     auto combinedBackend1 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test_block_load\", \"if-domain\":[\"webkit.org\"]}},"
476         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test_block_cookies\", \"unless-domain\":[\"webkit.org\"]}}]");
477     testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org"), { });
478     testRequest(combinedBackend1, mainDocumentRequest("http://not_webkit.org"), { });
479     testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org/test_block_load.html"), { ContentExtensions::ActionType::BlockLoad });
480     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_load.html", "http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
481     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://webkit.org/"), { });
482     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_load.html", "http://not_webkit.org/"), { });
483     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://not_webkit.org/"), { });
484     testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org/test_block_cookies.html"), { });
485     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_cookies.html", "http://webkit.org/"), { });
486     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://webkit.org/"), { });
487     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_cookies.html", "http://not_webkit.org/path/to/main/document.html"), { ContentExtensions::ActionType::BlockCookies });
488     testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://not_webkit.org/"), { });
489     
490     auto combinedBackend2 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test_block_load\\\\.html\", \"if-domain\":[\"webkit.org\"]}},"
491         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test_block_cookies\\\\.html\", \"unless-domain\":[\"w3c.org\"]}},"
492         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"test_css\\\\.html\"}}]");
493     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
494     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_css.htm"), { });
495     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_block_load.html"), { ContentExtensions::ActionType::BlockLoad });
496     testRequest(combinedBackend2, mainDocumentRequest("http://not_webkit.org/test_block_load.html"), { });
497     testRequest(combinedBackend2, mainDocumentRequest("http://not_webkit.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
498     testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/TEST_CSS.hTmL/test_block_load.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad});
499     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
500     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_block_load.html"), { });
501     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_block_cookies.html"), { });
502     testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_css.html/test_block_cookies.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
503     testRequest(combinedBackend2, mainDocumentRequest("http://not_w3c.org/test_block_cookies.html"), { ContentExtensions::ActionType::BlockCookies });
504     testRequest(combinedBackend2, mainDocumentRequest("http://not_w3c.org/test_css.html/test_block_cookies.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
505
506     auto ifDomainWithFlagsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\", \"if-domain\":[\"webkit.org\"],\"resource-type\":[\"image\"]}}]");
507     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
508     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.png", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
509     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
510     testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.png", ResourceType::Image), { });
511
512     auto unlessDomainWithFlagsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\", \"unless-domain\":[\"webkit.org\"],\"resource-type\":[\"image\"]}}]");
513     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
514     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.png", ResourceType::Image), { });
515     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
516     testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.png", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
517
518     // Domains should not be interepted as regular expressions.
519     auto domainRegexBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"we?bkit.org\"]}}]");
520     testRequest(domainRegexBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
521     testRequest(domainRegexBackend, mainDocumentRequest("http://wbkit.org/test.html"), { });
522     
523     auto multipleIfDomainsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\", \"w3c.org\"]}}]");
524     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
525     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
526     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://w3c.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
527     testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://whatwg.org/test.html"), { });
528
529     auto multipleUnlessDomainsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"webkit.org\", \"w3c.org\"]}}]");
530     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
531     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
532     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://w3c.org/test.html"), { });
533     testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://whatwg.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
534
535     // FIXME: Add and test domain-specific popup-only blocking (with layout tests).
536 }
537     
538 TEST_F(ContentExtensionTest, MultipleExtensions)
539 {
540     auto extension1 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}}]");
541     auto extension2 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}}]");
542     ContentExtensions::ContentExtensionsBackend backend;
543     backend.addContentExtension("testFilter1", extension1);
544     backend.addContentExtension("testFilter2", extension2);
545     
546     // These each have two display:none stylesheets. The second one is implied by using the default parameter ignorePreviousRules = false.
547     testRequest(backend, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet });
548     testRequest(backend, mainDocumentRequest("http://webkit.org/block_load.html"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::BlockLoad});
549     testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet});
550     testRequest(backend, mainDocumentRequest("http://webkit.org/block_load/block_cookies.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::BlockLoad });
551     testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies/block_load.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::BlockLoad });
552     
553     auto ignoreExtension1 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}},"
554         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore1\"}}]");
555     auto ignoreExtension2 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}},"
556         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore2\"}}]");
557     ContentExtensions::ContentExtensionsBackend backendWithIgnore;
558     backendWithIgnore.addContentExtension("testFilter1", ignoreExtension1);
559     backendWithIgnore.addContentExtension("testFilter2", ignoreExtension2);
560     
561     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet }, true);
562     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/ignore1.html"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet }, true);
563     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore1.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet}, true);
564     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/ignore2.html"), { ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet }, true);
565     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore2.html"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet}, true);
566     testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/block_cookies/ignore1/ignore2.html"), { }, true);
567 }
568
569 TEST_F(ContentExtensionTest, TermsKnownToMatchAnything)
570 {
571     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre1.*post1$\"}},"
572         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre2(.*)post2$\"}},"
573         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre3(.*)?post3$\"}},"
574         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre4(.*)+post4$\"}},"
575         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre5(.*)*post5$\"}},"
576         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre6(.)*post6$\"}},"
577         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre7(.+)*post7$\"}},"
578         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre8(.?)*post8$\"}},"
579         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre9(.+)?post9$\"}},"
580         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre0(.?)+post0$\"}}]");
581
582     testRequest(backend, mainDocumentRequest("pre1://webkit.org/post1"), { ContentExtensions::ActionType::BlockLoad });
583     testRequest(backend, mainDocumentRequest("pre2://webkit.org/post2"), { ContentExtensions::ActionType::BlockLoad });
584     testRequest(backend, mainDocumentRequest("pre3://webkit.org/post3"), { ContentExtensions::ActionType::BlockLoad });
585     testRequest(backend, mainDocumentRequest("pre4://webkit.org/post4"), { ContentExtensions::ActionType::BlockLoad });
586     testRequest(backend, mainDocumentRequest("pre5://webkit.org/post5"), { ContentExtensions::ActionType::BlockLoad });
587     testRequest(backend, mainDocumentRequest("pre6://webkit.org/post6"), { ContentExtensions::ActionType::BlockLoad });
588     testRequest(backend, mainDocumentRequest("pre7://webkit.org/post7"), { ContentExtensions::ActionType::BlockLoad });
589     testRequest(backend, mainDocumentRequest("pre8://webkit.org/post8"), { ContentExtensions::ActionType::BlockLoad });
590     testRequest(backend, mainDocumentRequest("pre9://webkit.org/post9"), { ContentExtensions::ActionType::BlockLoad });
591     testRequest(backend, mainDocumentRequest("pre0://webkit.org/post0"), { ContentExtensions::ActionType::BlockLoad });
592
593     testRequest(backend, mainDocumentRequest("pre1://webkit.org/post2"), { });
594     testRequest(backend, mainDocumentRequest("pre2://webkit.org/post3"), { });
595     testRequest(backend, mainDocumentRequest("pre3://webkit.org/post4"), { });
596     testRequest(backend, mainDocumentRequest("pre4://webkit.org/post5"), { });
597     testRequest(backend, mainDocumentRequest("pre5://webkit.org/post6"), { });
598     testRequest(backend, mainDocumentRequest("pre6://webkit.org/post7"), { });
599     testRequest(backend, mainDocumentRequest("pre7://webkit.org/post8"), { });
600     testRequest(backend, mainDocumentRequest("pre8://webkit.org/post9"), { });
601     testRequest(backend, mainDocumentRequest("pre9://webkit.org/post0"), { });
602     testRequest(backend, mainDocumentRequest("pre0://webkit.org/post1"), { });
603
604     testRequest(backend, mainDocumentRequest("pre0://webkit.org/post1"), { });
605     testRequest(backend, mainDocumentRequest("pre1://webkit.org/post2"), { });
606     testRequest(backend, mainDocumentRequest("pre2://webkit.org/post3"), { });
607     testRequest(backend, mainDocumentRequest("pre3://webkit.org/post4"), { });
608     testRequest(backend, mainDocumentRequest("pre4://webkit.org/post5"), { });
609     testRequest(backend, mainDocumentRequest("pre5://webkit.org/post6"), { });
610     testRequest(backend, mainDocumentRequest("pre6://webkit.org/post7"), { });
611     testRequest(backend, mainDocumentRequest("pre7://webkit.org/post8"), { });
612     testRequest(backend, mainDocumentRequest("pre8://webkit.org/post9"), { });
613     testRequest(backend, mainDocumentRequest("pre9://webkit.org/post0"), { });
614 }
615
616 TEST_F(ContentExtensionTest, TrailingDotStar)
617 {
618     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foo.*$\"}},"
619         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar(.*)$\"}}]");
620
621     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
622
623     testRequest(backend, mainDocumentRequest("foo://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
624     testRequest(backend, mainDocumentRequest("https://foo.org/"), { ContentExtensions::ActionType::BlockLoad });
625     testRequest(backend, mainDocumentRequest("https://webkit.foo/"), { ContentExtensions::ActionType::BlockLoad });
626     testRequest(backend, mainDocumentRequest("https://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
627
628     testRequest(backend, mainDocumentRequest("bar://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
629     testRequest(backend, mainDocumentRequest("https://bar.org/"), { ContentExtensions::ActionType::BlockLoad });
630     testRequest(backend, mainDocumentRequest("https://webkit.bar/"), { ContentExtensions::ActionType::BlockLoad });
631     testRequest(backend, mainDocumentRequest("https://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
632 }
633
634 TEST_F(ContentExtensionTest, TrailingTermsCarryingNoData)
635 {
636     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foob?a?r?\"}},"
637         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bazo(ok)?a?$\"}},"
638         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"cats*$\"}}]");
639
640     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
641
642     // Anything is fine after foo.
643     testRequest(backend, mainDocumentRequest("https://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
644     testRequest(backend, mainDocumentRequest("https://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
645     testRequest(backend, mainDocumentRequest("https://webkit.org/fooc"), { ContentExtensions::ActionType::BlockLoad });
646     testRequest(backend, mainDocumentRequest("https://webkit.org/fooba"), { ContentExtensions::ActionType::BlockLoad });
647     testRequest(backend, mainDocumentRequest("https://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
648     testRequest(backend, mainDocumentRequest("https://webkit.org/foobar-stuff"), { ContentExtensions::ActionType::BlockLoad });
649
650     // Bazooka has to be at the tail without any character not defined by the filter.
651     testRequest(backend, mainDocumentRequest("https://webkit.org/baz"), { });
652     testRequest(backend, mainDocumentRequest("https://webkit.org/bazo"), { ContentExtensions::ActionType::BlockLoad });
653     testRequest(backend, mainDocumentRequest("https://webkit.org/bazoa"), { ContentExtensions::ActionType::BlockLoad });
654     testRequest(backend, mainDocumentRequest("https://webkit.org/bazob"), { });
655     testRequest(backend, mainDocumentRequest("https://webkit.org/bazoo"), { });
656     testRequest(backend, mainDocumentRequest("https://webkit.org/bazook"), { ContentExtensions::ActionType::BlockLoad });
657     testRequest(backend, mainDocumentRequest("https://webkit.org/bazookb"), { });
658     testRequest(backend, mainDocumentRequest("https://webkit.org/bazooka"), { ContentExtensions::ActionType::BlockLoad });
659     testRequest(backend, mainDocumentRequest("https://webkit.org/bazookaa"), { });
660
661     // The pattern must finish with cat, with any number of 's' following it, but no other character.
662     testRequest(backend, mainDocumentRequest("https://cat.org/"), { });
663     testRequest(backend, mainDocumentRequest("https://cats.org/"), { });
664     testRequest(backend, mainDocumentRequest("https://webkit.org/cat"), { ContentExtensions::ActionType::BlockLoad });
665     testRequest(backend, mainDocumentRequest("https://webkit.org/cats"), { ContentExtensions::ActionType::BlockLoad });
666     testRequest(backend, mainDocumentRequest("https://webkit.org/catss"), { ContentExtensions::ActionType::BlockLoad });
667     testRequest(backend, mainDocumentRequest("https://webkit.org/catsss"), { ContentExtensions::ActionType::BlockLoad });
668     testRequest(backend, mainDocumentRequest("https://webkit.org/catso"), { });
669 }
670
671 TEST_F(ContentExtensionTest, LoadType)
672 {
673     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"third-party\"]}},"
674         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"whatwg.org\",\"load-type\":[\"first-party\"]}},"
675         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"alwaysblock.pdf\"}}]");
676     
677     testRequest(backend, mainDocumentRequest("http://webkit.org"), { });
678     testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Document}, { ContentExtensions::ActionType::BlockLoad });
679         
680     testRequest(backend, mainDocumentRequest("http://whatwg.org"), { ContentExtensions::ActionType::BlockLoad });
681     testRequest(backend, {URL(URL(), "http://whatwg.org"), URL(URL(), "http://not_whatwg.org"), ResourceType::Document}, { });
682     
683     testRequest(backend, mainDocumentRequest("http://foobar.org/alwaysblock.pdf"), { ContentExtensions::ActionType::BlockLoad });
684     testRequest(backend, {URL(URL(), "http://foobar.org/alwaysblock.pdf"), URL(URL(), "http://not_foobar.org/alwaysblock.pdf"), ResourceType::Document}, { ContentExtensions::ActionType::BlockLoad });
685 }
686
687 TEST_F(ContentExtensionTest, ResourceType)
688 {
689     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\"]}},"
690         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_only_images\",\"resource-type\":[\"image\"]}}]");
691
692     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Document), { ContentExtensions::ActionType::BlockLoad });
693     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
694     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::StyleSheet), { ContentExtensions::ActionType::BlockLoad });
695     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
696     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Font), { ContentExtensions::ActionType::BlockLoad });
697     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Raw), { ContentExtensions::ActionType::BlockLoad });
698     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::SVGDocument), { ContentExtensions::ActionType::BlockLoad });
699     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Media), { ContentExtensions::ActionType::BlockLoad });
700     testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Popup), { ContentExtensions::ActionType::BlockLoad });
701     testRequest(backend, mainDocumentRequest("http://block_only_images.org", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
702     testRequest(backend, mainDocumentRequest("http://block_only_images.org", ResourceType::Document), { });
703 }
704
705 TEST_F(ContentExtensionTest, ResourceAndLoadType)
706 {
707     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"BlockOnlyIfThirdPartyAndScript\",\"resource-type\":[\"script\"],\"load-type\":[\"third-party\"]}}]");
708     
709     testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.js", "http://webkit.org", ResourceType::Script), { });
710     testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.png", "http://not_webkit.org", ResourceType::Image), { });
711     testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.js", "http://not_webkit.org", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
712 }
713
714 TEST_F(ContentExtensionTest, ResourceOrLoadTypeMatchingEverything)
715 {
716     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"resource-type\":[\"image\"]}},"
717         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"third-party\"]}},"
718         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"first-party\"]}}]");
719     
720     testRequest(backend, mainDocumentRequest("http://webkit.org"), { }, true);
721     testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Document}, { ContentExtensions::ActionType::BlockCookies });
722     testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Image}, { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
723 }
724     
725 TEST_F(ContentExtensionTest, WideNFA)
726 {
727     // Make an NFA with about 1400 nodes.
728     StringBuilder ruleList;
729     ruleList.append('[');
730     for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
731         for (char c2 = 'A'; c2 <= 'C'; ++c2) {
732             for (char c3 = 'A'; c3 <= 'C'; ++c3) {
733                 if (c1 != 'A' || c2 != 'A' || c3 != 'A')
734                     ruleList.append(',');
735                 ruleList.append("{\"action\":{\"type\":\"");
736                 
737                 // Put an ignore-previous-rules near the middle.
738                 if (c1 == 'L' && c2 == 'A' && c3 == 'A')
739                     ruleList.append("ignore-previous-rules");
740                 else
741                     ruleList.append("block");
742                 
743                 ruleList.append("\"},\"trigger\":{\"url-filter\":\".*");
744                 ruleList.append(c1);
745                 ruleList.append(c2);
746                 ruleList.append(c3);
747                 ruleList.append("\", \"url-filter-is-case-sensitive\":true}}");
748             }
749         }
750     }
751     ruleList.append(']');
752     
753     auto backend = makeBackend(ruleList.toString().utf8().data());
754
755     testRequest(backend, mainDocumentRequest("http://webkit.org/AAA"), { ContentExtensions::ActionType::BlockLoad });
756     testRequest(backend, mainDocumentRequest("http://webkit.org/ZAA"), { ContentExtensions::ActionType::BlockLoad });
757     testRequest(backend, mainDocumentRequest("http://webkit.org/LAA/AAA"), { }, true);
758     testRequest(backend, mainDocumentRequest("http://webkit.org/LAA/MAA"), { ContentExtensions::ActionType::BlockLoad }, true);
759     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
760 }
761
762 TEST_F(ContentExtensionTest, DeepNFA)
763 {
764     const unsigned size = 100000;
765     
766     ContentExtensions::CombinedURLFilters combinedURLFilters;
767     ContentExtensions::URLFilterParser parser(combinedURLFilters);
768     
769     // FIXME: DFAToNFA::convert takes way too long on these deep NFAs. We should optimize for that case.
770     
771     StringBuilder lotsOfAs;
772     for (unsigned i = 0; i < size; ++i)
773         lotsOfAs.append('A');
774     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(lotsOfAs.toString().utf8().data(), false, 0));
775     
776     // FIXME: Yarr ought to be able to handle 2MB regular expressions.
777     StringBuilder tooManyAs;
778     for (unsigned i = 0; i < size * 20; ++i)
779         tooManyAs.append('A');
780     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::YarrError, parser.addPattern(tooManyAs.toString().utf8().data(), false, 0));
781     
782     StringBuilder nestedGroups;
783     for (unsigned i = 0; i < size; ++i)
784         nestedGroups.append('(');
785     for (unsigned i = 0; i < size; ++i)
786         nestedGroups.append("B)");
787     // FIXME: Add nestedGroups. Right now it also takes too long. It should be optimized.
788     
789     // This should not crash and not timeout.
790     EXPECT_EQ(1ul, createNFAs(combinedURLFilters).size());
791 }
792
793 void checkCompilerError(const char* json, std::error_code expectedError)
794 {
795     CompiledContentExtensionData extensionData;
796     InMemoryContentExtensionCompilationClient client(extensionData);
797     std::error_code compilerError = ContentExtensions::compileRuleList(client, json);
798     EXPECT_EQ(compilerError.value(), expectedError.value());
799     if (compilerError.value())
800         EXPECT_STREQ(compilerError.category().name(), expectedError.category().name());
801 }
802
803 TEST_F(ContentExtensionTest, MatchesEverything)
804 {
805     // Only css-display-none rules with triggers that match everything, no domain rules, and no flags
806     // should go in the global display:none stylesheet. css-display-none rules with domain rules or flags
807     // are applied separately on pages where they apply.
808     auto backend1 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]");
809     EXPECT_TRUE(nullptr != backend1.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
810     testRequest(backend1, mainDocumentRequest("http://webkit.org"), { }); // Selector is in global stylesheet.
811     
812     auto backend2 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"webkit.org\"]}}]");
813     EXPECT_EQ(nullptr, backend2.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
814     testRequest(backend2, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
815     testRequest(backend2, mainDocumentRequest("http://w3c.org"), { });
816     
817     auto backend3 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"webkit.org\"]}}]");
818     EXPECT_EQ(nullptr, backend3.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
819     testRequest(backend3, mainDocumentRequest("http://webkit.org"), { });
820     testRequest(backend3, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
821     
822     auto backend4 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"third-party\"]}}]");
823     EXPECT_EQ(nullptr, backend4.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
824     testRequest(backend4, mainDocumentRequest("http://webkit.org"), { });
825     testRequest(backend4, subResourceRequest("http://not_webkit.org", "http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
826
827     // css-display-none rules after ignore-previous-rules should not be put in the default stylesheet.
828     auto backend5 = makeBackend("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\".*\"}},"
829         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]");
830     EXPECT_EQ(nullptr, backend5.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
831     testRequest(backend5, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector }, true);
832 }
833     
834 TEST_F(ContentExtensionTest, InvalidJSON)
835 {
836     checkCompilerError("[", ContentExtensions::ContentExtensionError::JSONInvalid);
837     checkCompilerError("123", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnObject);
838     checkCompilerError("{}", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnArray);
839     // FIXME: Add unit test for JSONInvalidRule if that is possible to hit.
840     checkCompilerError("[]", ContentExtensions::ContentExtensionError::JSONContainsNoRules);
841
842     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":5}]",
843         ContentExtensions::ContentExtensionError::JSONInvalidTrigger);
844     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"\"}}]",
845         ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
846     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":{}}}]",
847         ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
848
849     // FIXME: Add unit test for JSONInvalidObjectInTriggerFlagsArray if that is possible to hit.
850     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":{}}}]",
851         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
852     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"invalid\"]}}]",
853         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
854     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[5]}}]",
855         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
856     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":5}}]",
857         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
858     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":\"first-party\"}}]",
859         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
860     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":null}}]",
861         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
862     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":false}}]",
863         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
864     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":{}}}]",
865         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
866     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[\"invalid\"]}}]",
867         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
868     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[5]}}]",
869         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
870     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":5}}]",
871         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
872     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":\"document\"}}]",
873         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
874     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":null}}]",
875         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
876     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":false}}]",
877         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
878     
879     StringBuilder rules;
880     rules.append("[");
881     for (unsigned i = 0; i < 49999; ++i)
882         rules.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}},");
883     String rules50000 = rules.toString();
884     String rules50001 = rules.toString();
885     rules50000.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}}]");
886     rules50001.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}},{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}}]");
887     checkCompilerError(rules50000.utf8().data(), { });
888     checkCompilerError(rules50001.utf8().data(), ContentExtensions::ContentExtensionError::JSONTooManyRules);
889     
890     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":{}}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
891     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[5]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
892     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"]}}]", { });
893     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":\"a\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
894     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":false}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
895     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":null}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
896     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":{}}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
897     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[5]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
898     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
899     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":\"a\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
900     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":null}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
901     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":false}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
902     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"A\"]}}]", ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
903     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"\\u00DC\"]}}]", ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
904     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"0\"]}}]", { });
905     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"a\"]}}]", { });
906
907     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
908     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
909     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
910     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
911     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":5,\"unless-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
912     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
913     
914     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONUnlessAndIfDomain);
915     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONUnlessAndIfDomain);
916
917     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\", \"unexpected-identifier-should-be-ignored\":5}}]", { });
918
919     checkCompilerError("[{\"action\":5,\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
920         ContentExtensions::ContentExtensionError::JSONInvalidAction);
921     checkCompilerError("[{\"action\":{\"type\":\"invalid\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
922         ContentExtensions::ContentExtensionError::JSONInvalidActionType);
923     checkCompilerError("[{\"action\":{\"type\":\"css-display-none\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
924         ContentExtensions::ContentExtensionError::JSONInvalidCSSDisplayNoneActionType);
925
926     checkCompilerError("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"webkit.org\"}},"
927         "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
928     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"a\"]}}]", { });
929     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"a\"]}}]", { });
930     checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[\"}}]",
931         ContentExtensions::ContentExtensionError::JSONInvalidRegex);
932 }
933
934 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines1)
935 {
936     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^.*foo\"}},"
937         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar$\"}},"
938         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[ab]+bang\"}}]");
939
940     testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
941     testRequest(backend, mainDocumentRequest("foo://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
942     testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
943     testRequest(backend, mainDocumentRequest("bar://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
944
945     testRequest(backend, mainDocumentRequest("abang://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
946     testRequest(backend, mainDocumentRequest("bbang://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
947     testRequest(backend, mainDocumentRequest("cbang://webkit.org/"), { });
948     testRequest(backend, mainDocumentRequest("http://webkit.org/bang"), { });
949     testRequest(backend, mainDocumentRequest("bang://webkit.org/"), { });
950 }
951
952 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines1Partitioning)
953 {
954     ContentExtensions::CombinedURLFilters combinedURLFilters;
955     ContentExtensions::URLFilterParser parser(combinedURLFilters);
956
957     // Those two share a prefix.
958     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^.*foo", false, 0));
959     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("bar$", false, 1));
960
961     // Not this one.
962     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^[ab]+bang", false, 0));
963
964     EXPECT_EQ(2ul, createNFAs(combinedURLFilters).size());
965 }
966
967 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines2)
968 {
969     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^foo\"}},"
970         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^.*[a-c]+bar\"}},"
971         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^webkit:\"}},"
972         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-c]+b+oom\"}}]");
973
974     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
975     testRequest(backend, mainDocumentRequest("foo://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
976     testRequest(backend, mainDocumentRequest("webkit://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
977
978     testRequest(backend, mainDocumentRequest("http://bar.org/"), { });
979     testRequest(backend, mainDocumentRequest("http://abar.org/"), { ContentExtensions::ActionType::BlockLoad });
980     testRequest(backend, mainDocumentRequest("http://bbar.org/"), { ContentExtensions::ActionType::BlockLoad });
981     testRequest(backend, mainDocumentRequest("http://cbar.org/"), { ContentExtensions::ActionType::BlockLoad });
982     testRequest(backend, mainDocumentRequest("http://abcbar.org/"), { ContentExtensions::ActionType::BlockLoad });
983     testRequest(backend, mainDocumentRequest("http://dbar.org/"), { });
984 }
985
986 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines2Partitioning)
987 {
988     ContentExtensions::CombinedURLFilters combinedURLFilters;
989     ContentExtensions::URLFilterParser parser(combinedURLFilters);
990
991     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^foo", false, 0));
992     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^.*[a-c]+bar", false, 1));
993     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^webkit:", false, 2));
994     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("[a-c]+b+oom", false, 3));
995
996     // "^foo" and "^webkit:" can be grouped, the other two have a variable prefix.
997     EXPECT_EQ(3ul, createNFAs(combinedURLFilters).size());
998 }
999
1000 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines3)
1001 {
1002     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"A*D\"}},"
1003         "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"A*BA+\"}},"
1004         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"A*BC\"}}]");
1005     
1006     testRequest(backend, mainDocumentRequest("http://webkit.org/D"), { ContentExtensions::ActionType::BlockLoad });
1007     testRequest(backend, mainDocumentRequest("http://webkit.org/AAD"), { ContentExtensions::ActionType::BlockLoad });
1008     testRequest(backend, mainDocumentRequest("http://webkit.org/AB"), { });
1009     testRequest(backend, mainDocumentRequest("http://webkit.org/ABA"), { }, true);
1010     testRequest(backend, mainDocumentRequest("http://webkit.org/ABAD"), { }, true);
1011     testRequest(backend, mainDocumentRequest("http://webkit.org/BC"), { ContentExtensions::ActionType::BlockCookies });
1012     testRequest(backend, mainDocumentRequest("http://webkit.org/ABC"), { ContentExtensions::ActionType::BlockCookies });
1013     testRequest(backend, mainDocumentRequest("http://webkit.org/ABABC"), { ContentExtensions::ActionType::BlockCookies }, true);
1014     testRequest(backend, mainDocumentRequest("http://webkit.org/ABABCAD"), { ContentExtensions::ActionType::BlockCookies }, true);
1015     testRequest(backend, mainDocumentRequest("http://webkit.org/ABCAD"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
1016 }
1017     
1018 TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines3Partitioning)
1019 {
1020     ContentExtensions::CombinedURLFilters combinedURLFilters;
1021     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1022     
1023     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*D", false, 0));
1024     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*BA+", false, 1));
1025     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*BC", false, 2));
1026     
1027     // "A*A" and "A*BC" can be grouped, "A*BA+" should not.
1028     EXPECT_EQ(2ul, createNFAs(combinedURLFilters).size());
1029 }
1030
1031 TEST_F(ContentExtensionTest, SplittingLargeNFAs)
1032 {
1033     const size_t expectedNFACounts[16] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1};
1034     
1035     for (size_t i = 0; i < 16; i++) {
1036         ContentExtensions::CombinedURLFilters combinedURLFilters;
1037         ContentExtensions::URLFilterParser parser(combinedURLFilters);
1038         
1039         EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+BBB", false, 1));
1040         EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+CCC", false, 2));
1041         EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+DDD", false, 2));
1042         
1043         Vector<ContentExtensions::NFA> nfas;
1044         combinedURLFilters.processNFAs(i, [&](ContentExtensions::NFA&& nfa) {
1045             nfas.append(WTF::move(nfa));
1046         });
1047         EXPECT_EQ(nfas.size(), expectedNFACounts[i]);
1048         
1049         Vector<ContentExtensions::DFA> dfas;
1050         for (auto& nfa : nfas)
1051             dfas.append(ContentExtensions::NFAToDFA::convert(nfa));
1052         
1053         Vector<ContentExtensions::DFABytecode> combinedBytecode;
1054         for (const auto& dfa : dfas) {
1055             Vector<ContentExtensions::DFABytecode> bytecode;
1056             ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
1057             compiler.compile();
1058             combinedBytecode.appendVector(bytecode);
1059         }
1060         
1061         Vector<bool> pagesUsed;
1062         ContentExtensions::DFABytecodeInterpreter interpreter(&combinedBytecode[0], combinedBytecode.size(), pagesUsed);
1063         
1064         EXPECT_EQ(interpreter.interpret("ABBBX", 0).size(), 1ull);
1065         EXPECT_EQ(interpreter.interpret("ACCCX", 0).size(), 1ull);
1066         EXPECT_EQ(interpreter.interpret("ADDDX", 0).size(), 1ull);
1067         EXPECT_EQ(interpreter.interpret("XBBBX", 0).size(), 0ull);
1068         EXPECT_EQ(interpreter.interpret("ABBX", 0).size(), 0ull);
1069         EXPECT_EQ(interpreter.interpret("ACCX", 0).size(), 0ull);
1070         EXPECT_EQ(interpreter.interpret("ADDX", 0).size(), 0ull);
1071     }
1072 }
1073     
1074 TEST_F(ContentExtensionTest, QuantifierInGroup)
1075 {
1076     ContentExtensions::CombinedURLFilters combinedURLFilters;
1077     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1078     
1079     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A+)B)C)", false, 0));
1080     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B+)C)", false, 1));
1081     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B+)C)D", false, 2));
1082     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B)C+)", false, 3));
1083     EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B)C)", false, 4));
1084     
1085     // (((A)B+)C) and (((A)B+)C)D should be in the same NFA.
1086     EXPECT_EQ(4ul, createNFAs(combinedURLFilters).size());
1087 }
1088
1089 static void testPatternStatus(String pattern, ContentExtensions::URLFilterParser::ParseStatus status)
1090 {
1091     ContentExtensions::CombinedURLFilters combinedURLFilters;
1092     ContentExtensions::URLFilterParser parser(combinedURLFilters);
1093     EXPECT_EQ(status, parser.addPattern(pattern, false, 0));
1094 }
1095     
1096 TEST_F(ContentExtensionTest, ParsingFailures)
1097 {
1098     testPatternStatus("a*b?.*.?[a-z]?[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1099     testPatternStatus("a*b?.*.?[a-z]?[a-z]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1100     testPatternStatus("a*b?.*.?[a-z]?[a-z]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1101     testPatternStatus(".*?a", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1102     testPatternStatus(".*a", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1103     
1104     testPatternStatus("(?!)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1105     testPatternStatus("(?=)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1106     testPatternStatus("(?!a)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1107     testPatternStatus("(?=a)", ContentExtensions::URLFilterParser::ParseStatus::Group);
1108     testPatternStatus("(regex)", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1109     testPatternStatus("(regex", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1110     testPatternStatus("((regex)", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1111     testPatternStatus("(?:regex)", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1112     testPatternStatus("(?:regex", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1113     testPatternStatus("[^.]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1114     
1115     testPatternStatus("a++", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1116     testPatternStatus("[a]++", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1117     testPatternStatus("+", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1118     
1119     testPatternStatus("[", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1120     testPatternStatus("[a}", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
1121     
1122     // FIXME: Look into why these do not cause YARR parsing errors.  They probably should.
1123     testPatternStatus("a]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1124     testPatternStatus("{", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1125     testPatternStatus("{[a]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1126     testPatternStatus("{0", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1127     testPatternStatus("{0,", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1128     testPatternStatus("{0,1", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1129     testPatternStatus("a{0,1", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1130     testPatternStatus("a{a,b}", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1131
1132     const char nonASCII[2] = {-1, '\0'};
1133     testPatternStatus(nonASCII, ContentExtensions::URLFilterParser::ParseStatus::NonASCII);
1134     testPatternStatus("\\xff", ContentExtensions::URLFilterParser::ParseStatus::NonASCII);
1135     
1136     testPatternStatus("\\x\\r\\n", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1137     testPatternStatus("\\b", ContentExtensions::URLFilterParser::ParseStatus::WordBoundary);
1138     testPatternStatus("[\\d]", ContentExtensions::URLFilterParser::ParseStatus::AtomCharacter);
1139     testPatternStatus("\\d\\D\\w\\s\\v\\h\\i\\c", ContentExtensions::URLFilterParser::ParseStatus::UnsupportedCharacterClass);
1140     
1141     testPatternStatus("this|that", ContentExtensions::URLFilterParser::ParseStatus::Disjunction);
1142     testPatternStatus("a{0,1}b", ContentExtensions::URLFilterParser::ParseStatus::Ok);
1143     testPatternStatus("a{0,2}b", ContentExtensions::URLFilterParser::ParseStatus::InvalidQuantifier);
1144     testPatternStatus("", ContentExtensions::URLFilterParser::ParseStatus::EmptyPattern);
1145     testPatternStatus("$$", ContentExtensions::URLFilterParser::ParseStatus::MisplacedEndOfLine);
1146     testPatternStatus("a^", ContentExtensions::URLFilterParser::ParseStatus::MisplacedStartOfLine);
1147     testPatternStatus("(^)", ContentExtensions::URLFilterParser::ParseStatus::MisplacedStartOfLine);
1148     
1149     testPatternStatus("(a)\\1", ContentExtensions::URLFilterParser::ParseStatus::Ok); // This should be BackReference, right?
1150 }
1151
1152 TEST_F(ContentExtensionTest, PatternMatchingTheEmptyString)
1153 {
1154     // Simple atoms.
1155     testPatternStatus(".*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1156     testPatternStatus("a*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1157     testPatternStatus(".?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1158     testPatternStatus("a?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1159
1160     // Character sets.
1161     testPatternStatus("[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1162     testPatternStatus("[a-z]?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1163
1164     // Groups.
1165     testPatternStatus("(foobar)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1166     testPatternStatus("(foobar)?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1167     testPatternStatus("(.*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1168     testPatternStatus("(a*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1169     testPatternStatus("(.?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1170     testPatternStatus("(a?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1171     testPatternStatus("([a-z]*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1172     testPatternStatus("([a-z]?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1173
1174     testPatternStatus("(.)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1175     testPatternStatus("(.+)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1176     testPatternStatus("(.?)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1177     testPatternStatus("(.*)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1178     testPatternStatus("(.+)?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1179     testPatternStatus("(.?)+", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1180
1181     // Nested groups.
1182     testPatternStatus("((foo)?((.)*)(bar)*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
1183 }
1184
1185 TEST_F(ContentExtensionTest, MinimizingWithMoreFinalStatesThanNonFinalStates)
1186 {
1187     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^h[a-z://]+\"}},"
1188         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://foo.com/\"}},"
1189         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://bar.com/\"}}]");
1190
1191     testRequest(backend, mainDocumentRequest("http://foo.com/"), { ContentExtensions::ActionType::BlockLoad });
1192     testRequest(backend, mainDocumentRequest("http://bar.com/"), { ContentExtensions::ActionType::BlockLoad });
1193     testRequest(backend, mainDocumentRequest("attp://foo.com/"), { });
1194     testRequest(backend, mainDocumentRequest("attp://bar.com/"), { });
1195
1196     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1197     testRequest(backend, mainDocumentRequest("https://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1198     testRequest(backend, mainDocumentRequest("bttp://webkit.org/"), { });
1199     testRequest(backend, mainDocumentRequest("bttps://webkit.org/"), { });
1200     testRequest(backend, mainDocumentRequest("http://webkit.org/b"), { ContentExtensions::ActionType::BlockLoad });
1201     testRequest(backend, mainDocumentRequest("https://webkit.org/b"), { ContentExtensions::ActionType::BlockLoad });
1202     testRequest(backend, mainDocumentRequest("cttp://webkit.org/B"), { });
1203     testRequest(backend, mainDocumentRequest("cttps://webkit.org/B"), { });
1204 }
1205
1206 TEST_F(ContentExtensionTest, StatesWithDifferentActionsAreNotUnified1)
1207 {
1208     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://www.webkit.org/\"}},"
1209         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}},"
1210         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^attps://www.webkit.org/\"}}]");
1211
1212     testRequest(backend, mainDocumentRequest("http://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1213     testRequest(backend, mainDocumentRequest("https://www.webkit.org/"), { ContentExtensions::ActionType::BlockCookies });
1214     testRequest(backend, mainDocumentRequest("attps://www.webkit.org/"), { ContentExtensions::ActionType::BlockCookies });
1215     testRequest(backend, mainDocumentRequest("http://www.webkit.org/a"), { ContentExtensions::ActionType::BlockLoad });
1216     testRequest(backend, mainDocumentRequest("https://www.webkit.org/B"), { ContentExtensions::ActionType::BlockCookies });
1217     testRequest(backend, mainDocumentRequest("attps://www.webkit.org/c"), { ContentExtensions::ActionType::BlockCookies });
1218     testRequest(backend, mainDocumentRequest("http://www.whatwg.org/"), { });
1219     testRequest(backend, mainDocumentRequest("https://www.whatwg.org/"), { });
1220     testRequest(backend, mainDocumentRequest("attps://www.whatwg.org/"), { });
1221 }
1222
1223 TEST_F(ContentExtensionTest, StatesWithDifferentActionsAreNotUnified2)
1224 {
1225     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://www.webkit.org/\"}},"
1226         "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}},"
1227         "{\"action\":{\"type\":\"css-display-none\", \"selector\":\"#foo\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}}]");
1228
1229     testRequest(backend, mainDocumentRequest("http://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1230     testRequest(backend, mainDocumentRequest("https://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
1231     testRequest(backend, mainDocumentRequest("https://www.whatwg.org/"), { });
1232     testRequest(backend, mainDocumentRequest("attps://www.whatwg.org/"), { });
1233 }
1234
1235 // The order in which transitions from the root will be processed is unpredictable.
1236 // To exercises the various options, this test exists in various version exchanging the transition to the final state.
1237 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge1)
1238 {
1239     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.a\"}},"
1240         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.a\"}},"
1241         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bac\"}},"
1242         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bbc\"}},"
1243         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCC\"}}]");
1244
1245     testRequest(backend, mainDocumentRequest("aza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1246     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1247     testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1248     testRequest(backend, mainDocumentRequest("bbc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1249     testRequest(backend, mainDocumentRequest("bcc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1250
1251     testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { });
1252     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { });
1253     testRequest(backend, mainDocumentRequest("acc://www.webkit.org/"), { });
1254
1255     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1256     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1257     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1258 }
1259 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge2)
1260 {
1261     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bac\"}},"
1262         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bbc\"}},"
1263         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCC\"}},"
1264         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.a\"}},"
1265         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.a\"}}]");
1266
1267     testRequest(backend, mainDocumentRequest("aza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1268     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1269     testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1270     testRequest(backend, mainDocumentRequest("bbc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1271     testRequest(backend, mainDocumentRequest("bcc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1272
1273     testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { });
1274     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { });
1275     testRequest(backend, mainDocumentRequest("acc://www.webkit.org/"), { });
1276
1277     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1278     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1279     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
1280 }
1281 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge3)
1282 {
1283     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
1284         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}},"
1285         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^baa\"}},"
1286         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bba\"}},"
1287         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCA\"}}]");
1288
1289     testRequest(backend, mainDocumentRequest("azc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1290     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1291     testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1292     testRequest(backend, mainDocumentRequest("bba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1293     testRequest(backend, mainDocumentRequest("bca://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1294
1295     testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
1296     testRequest(backend, mainDocumentRequest("aba://www.webkit.org/"), { });
1297     testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
1298
1299     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1300     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1301     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1302 }
1303 TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge4)
1304 {
1305     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^baa\"}},"
1306         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bba\"}},"
1307         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCA\"}},"
1308         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
1309         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}}]");
1310
1311     testRequest(backend, mainDocumentRequest("azc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1312     testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1313     testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1314     testRequest(backend, mainDocumentRequest("bba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1315     testRequest(backend, mainDocumentRequest("bca://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1316
1317     testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
1318     testRequest(backend, mainDocumentRequest("aba://www.webkit.org/"), { });
1319     testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
1320
1321     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1322     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1323     testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
1324 }
1325
1326 TEST_F(ContentExtensionTest, FallbackTransitionsToOtherNodeInSameGroupDoesNotDifferentiateGroup)
1327 {
1328     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^aac\"}},"
1329         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
1330         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}}]");
1331
1332     testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1333     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1334     testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1335     testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1336
1337     testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
1338     testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
1339     testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { });
1340 }
1341
1342 TEST_F(ContentExtensionTest, SimpleFallBackTransitionDifferentiator1)
1343 {
1344     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.bc.de\"}},"
1345         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.bd.ef\"}}]");
1346
1347     testRequest(backend, mainDocumentRequest("abbccde://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1348     testRequest(backend, mainDocumentRequest("aabcdde://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1349     testRequest(backend, mainDocumentRequest("aabddef://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1350     testRequest(backend, mainDocumentRequest("aabddef://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1351
1352     testRequest(backend, mainDocumentRequest("abcde://www.webkit.org/"), { });
1353     testRequest(backend, mainDocumentRequest("abdef://www.webkit.org/"), { });
1354 }
1355
1356 TEST_F(ContentExtensionTest, SimpleFallBackTransitionDifferentiator2)
1357 {
1358     auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^cb.\"}},"
1359         "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^db.b\"}}]");
1360
1361     testRequest(backend, mainDocumentRequest("cba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1362     testRequest(backend, mainDocumentRequest("cbb://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1363     testRequest(backend, mainDocumentRequest("dbab://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1364     testRequest(backend, mainDocumentRequest("dbxb://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
1365
1366     testRequest(backend, mainDocumentRequest("cca://www.webkit.org/"), { });
1367     testRequest(backend, mainDocumentRequest("dddd://www.webkit.org/"), { });
1368     testRequest(backend, mainDocumentRequest("bbbb://www.webkit.org/"), { });
1369 }
1370
1371 } // namespace TestWebKitAPI