[Content Filtering] Add tests for unblock requests
[WebKit-https.git] / Source / WebCore / loader / ContentFilter.cpp
1 /*
2  * Copyright (C) 2013 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 #include "ContentFilter.h"
28
29 #if ENABLE(CONTENT_FILTERING)
30
31 #include "DocumentLoader.h"
32 #include "Frame.h"
33 #include "NetworkExtensionContentFilter.h"
34 #include "ParentalControlsContentFilter.h"
35 #include "ScriptController.h"
36 #include <bindings/ScriptValue.h>
37 #include <wtf/NeverDestroyed.h>
38 #include <wtf/Vector.h>
39
40 namespace WebCore {
41
42 Vector<ContentFilter::Type>& ContentFilter::types()
43 {
44     static NeverDestroyed<Vector<ContentFilter::Type>> types {
45         Vector<ContentFilter::Type> {
46             type<ParentalControlsContentFilter>(),
47 #if HAVE(NETWORK_EXTENSION)
48             type<NetworkExtensionContentFilter>()
49 #endif
50         }
51     };
52     return types;
53 }
54
55 std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded(const ResourceResponse& response, DocumentLoader& documentLoader)
56 {
57     Container filters;
58     for (auto& type : types()) {
59         if (type.canHandleResponse(response))
60             filters.append(type.create(response));
61     }
62
63     if (filters.isEmpty())
64         return nullptr;
65
66     return std::make_unique<ContentFilter>(WTF::move(filters), documentLoader);
67 }
68
69 ContentFilter::ContentFilter(Container contentFilters, DocumentLoader& documentLoader)
70     : m_contentFilters { WTF::move(contentFilters) }
71     , m_documentLoader { documentLoader }
72 {
73     ASSERT(!m_contentFilters.isEmpty());
74 }
75
76 void ContentFilter::addData(const char* data, int length)
77 {
78     ASSERT(needsMoreData());
79
80     for (auto& contentFilter : m_contentFilters)
81         contentFilter->addData(data, length);
82 }
83     
84 void ContentFilter::finishedAddingData()
85 {
86     ASSERT(needsMoreData());
87
88     for (auto& contentFilter : m_contentFilters)
89         contentFilter->finishedAddingData();
90
91     ASSERT(!needsMoreData());
92 }
93
94 bool ContentFilter::needsMoreData() const
95 {
96     for (auto& contentFilter : m_contentFilters) {
97         if (contentFilter->needsMoreData())
98             return true;
99     }
100
101     return false;
102 }
103
104 bool ContentFilter::didBlockData() const
105 {
106     for (auto& contentFilter : m_contentFilters) {
107         if (contentFilter->didBlockData())
108             return true;
109     }
110
111     return false;
112 }
113
114 const char* ContentFilter::getReplacementData(int& length) const
115 {
116     ASSERT(!needsMoreData());
117
118     for (auto& contentFilter : m_contentFilters) {
119         if (contentFilter->didBlockData())
120             return contentFilter->getReplacementData(length);
121     }
122
123     return m_contentFilters[0]->getReplacementData(length);
124 }
125
126 ContentFilterUnblockHandler ContentFilter::unblockHandler() const
127 {
128     ASSERT(didBlockData());
129
130     PlatformContentFilter* blockingFilter = nullptr;
131     for (auto& contentFilter : m_contentFilters) {
132         if (contentFilter->didBlockData()) {
133             blockingFilter = contentFilter.get();
134             break;
135         }
136     }
137     ASSERT(blockingFilter);
138
139     StringCapture unblockRequestDeniedScript { blockingFilter->unblockRequestDeniedScript() };
140     if (unblockRequestDeniedScript.string().isEmpty())
141         return blockingFilter->unblockHandler();
142
143     // It would be a layering violation for the unblock handler to access its frame,
144     // so we will execute the unblock denied script on its behalf.
145     ContentFilterUnblockHandler unblockHandler { blockingFilter->unblockHandler() };
146     RefPtr<Frame> frame { m_documentLoader.frame() };
147     return ContentFilterUnblockHandler {
148         unblockHandler.unblockURLHost(), [unblockHandler, frame, unblockRequestDeniedScript](ContentFilterUnblockHandler::DecisionHandlerFunction decisionHandler) {
149             unblockHandler.requestUnblockAsync([decisionHandler, frame, unblockRequestDeniedScript](bool unblocked) {
150                 decisionHandler(unblocked);
151                 if (!unblocked && frame)
152                     frame->script().executeScript(unblockRequestDeniedScript.string());
153             });
154         }
155     };
156 }
157
158 } // namespace WebCore
159
160 #endif // ENABLE(CONTENT_FILTERING)