2b1d68196b03c0dc68f123d16ddab7cddee4f969
[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 "CachedRawResource.h"
32 #include "ContentFilterUnblockHandler.h"
33 #include "NetworkExtensionContentFilter.h"
34 #include "ParentalControlsContentFilter.h"
35 #include "SharedBuffer.h"
36 #include <wtf/NeverDestroyed.h>
37 #include <wtf/Vector.h>
38
39 namespace WebCore {
40
41 Vector<ContentFilter::Type>& ContentFilter::types()
42 {
43     static NeverDestroyed<Vector<ContentFilter::Type>> types {
44         Vector<ContentFilter::Type> {
45             type<ParentalControlsContentFilter>(),
46 #if HAVE(NETWORK_EXTENSION)
47             type<NetworkExtensionContentFilter>()
48 #endif
49         }
50     };
51     return types;
52 }
53
54 std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded(DecisionFunction decisionFunction)
55 {
56     Container filters;
57     for (auto& type : types()) {
58         if (!type.enabled())
59             continue;
60
61         auto filter = type.create();
62         ASSERT(filter);
63         filters.append(WTF::move(filter));
64     }
65
66     if (filters.isEmpty())
67         return nullptr;
68
69     return std::make_unique<ContentFilter>(WTF::move(filters), WTF::move(decisionFunction));
70 }
71
72 ContentFilter::ContentFilter(Container contentFilters, DecisionFunction decisionFunction)
73     : m_contentFilters { WTF::move(contentFilters) }
74     , m_decisionFunction { WTF::move(decisionFunction) }
75 {
76     ASSERT(!m_contentFilters.isEmpty());
77 }
78
79 ContentFilter::~ContentFilter()
80 {
81     if (!m_mainResource)
82         return;
83     ASSERT(m_mainResource->hasClient(this));
84     m_mainResource->removeClient(this);
85 }
86
87 void ContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
88 {
89     ResourceRequest requestCopy { request };
90     ASSERT(m_state == State::Initialized || m_state == State::Filtering);
91     forEachContentFilterUntilBlocked([&requestCopy, &redirectResponse](PlatformContentFilter& contentFilter) {
92         contentFilter.willSendRequest(requestCopy, redirectResponse);
93         if (contentFilter.didBlockData())
94             requestCopy = ResourceRequest();
95     });
96     request = requestCopy;
97 }
98
99 void ContentFilter::startFilteringMainResource(CachedRawResource& resource)
100 {
101     ASSERT(m_state == State::Initialized);
102     m_state = State::Filtering;
103     ASSERT(!m_mainResource);
104     m_mainResource = &resource;
105     ASSERT(!m_mainResource->hasClient(this));
106     m_mainResource->addClient(this);
107 }
108
109 ContentFilterUnblockHandler ContentFilter::unblockHandler() const
110 {
111     ASSERT(m_state == State::Blocked);
112     ASSERT(m_blockingContentFilter);
113     ASSERT(m_blockingContentFilter->didBlockData());
114     return m_blockingContentFilter->unblockHandler();
115 }
116
117 Ref<SharedBuffer> ContentFilter::replacementData() const
118 {
119     ASSERT(m_state == State::Blocked);
120     ASSERT(m_blockingContentFilter);
121     ASSERT(m_blockingContentFilter->didBlockData());
122     return m_blockingContentFilter->replacementData();
123 }
124
125 String ContentFilter::unblockRequestDeniedScript() const
126 {
127     ASSERT(m_state == State::Blocked);
128     ASSERT(m_blockingContentFilter);
129     ASSERT(m_blockingContentFilter->didBlockData());
130     return m_blockingContentFilter->unblockRequestDeniedScript();
131 }
132
133 void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse& response)
134 {
135     ASSERT(m_state == State::Filtering);
136     ASSERT_UNUSED(resource, resource == m_mainResource.get());
137     forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) {
138         contentFilter.responseReceived(response);
139     });
140 }
141
142 void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length)
143 {
144     ASSERT(m_state == State::Filtering);
145     ASSERT_UNUSED(resource, resource == m_mainResource.get());
146     forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) {
147         contentFilter.addData(data, length);
148     });
149 }
150
151 void ContentFilter::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
152 {
153     ASSERT(m_state == State::Filtering);
154     ASSERT_UNUSED(resource, resource == m_mainResource.get());
155     willSendRequest(request, redirectResponse);
156 }
157
158 void ContentFilter::notifyFinished(CachedResource* resource)
159 {
160     ASSERT(m_state == State::Filtering);
161     ASSERT_UNUSED(resource, resource == m_mainResource.get());
162     forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) {
163         contentFilter.finishedAddingData();
164     });
165 }
166
167 void ContentFilter::forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)> function)
168 {
169     bool allFiltersAllowedLoad { true };
170     for (auto& contentFilter : m_contentFilters) {
171         if (!contentFilter->needsMoreData()) {
172             ASSERT(!contentFilter->didBlockData());
173             continue;
174         }
175
176         function(*contentFilter);
177
178         if (contentFilter->didBlockData()) {
179             ASSERT(!m_blockingContentFilter);
180             m_blockingContentFilter = contentFilter.get();
181             didDecide(State::Blocked);
182             return;
183         } else if (contentFilter->needsMoreData())
184             allFiltersAllowedLoad = false;
185     }
186
187     if (allFiltersAllowedLoad)
188         didDecide(State::Allowed);
189 }
190
191 void ContentFilter::didDecide(State state)
192 {
193     ASSERT(m_state != State::Allowed);
194     ASSERT(m_state != State::Blocked);
195     ASSERT(state == State::Allowed || state == State::Blocked);
196     m_state = state;
197
198     // Calling m_decisionFunction might delete |this|.
199     if (m_decisionFunction)
200         m_decisionFunction();
201 }
202
203 } // namespace WebCore
204
205 #endif // ENABLE(CONTENT_FILTERING)