2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ContentFilter.h"
29 #if ENABLE(CONTENT_FILTERING)
31 #include "CachedRawResource.h"
32 #include "ContentFilterUnblockHandler.h"
34 #include "NetworkExtensionContentFilter.h"
35 #include "ParentalControlsContentFilter.h"
36 #include "SharedBuffer.h"
37 #include <wtf/NeverDestroyed.h>
38 #include <wtf/Vector.h>
41 #include <wtf/text/CString.h>
46 Vector<ContentFilter::Type>& ContentFilter::types()
48 static NeverDestroyed<Vector<ContentFilter::Type>> types {
49 Vector<ContentFilter::Type> {
50 #if HAVE(PARENTAL_CONTROLS)
51 type<ParentalControlsContentFilter>(),
53 #if HAVE(NETWORK_EXTENSION)
54 type<NetworkExtensionContentFilter>()
61 std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded(DecisionFunction decisionFunction)
64 for (auto& type : types()) {
68 auto filter = type.create();
70 filters.append(WTF::move(filter));
73 if (filters.isEmpty())
76 return std::make_unique<ContentFilter>(WTF::move(filters), WTF::move(decisionFunction));
79 ContentFilter::ContentFilter(Container contentFilters, DecisionFunction decisionFunction)
80 : m_contentFilters { WTF::move(contentFilters) }
81 , m_decisionFunction { WTF::move(decisionFunction) }
83 LOG(ContentFiltering, "Creating ContentFilter with %zu platform content filter(s).\n", m_contentFilters.size());
84 ASSERT(!m_contentFilters.isEmpty());
87 ContentFilter::~ContentFilter()
89 LOG(ContentFiltering, "Destroying ContentFilter.\n");
92 ASSERT(m_mainResource->hasClient(this));
93 m_mainResource->removeClient(this);
96 void ContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
98 LOG(ContentFiltering, "ContentFilter received request for <%s> with redirect response from <%s>.\n", request.url().string().ascii().data(), redirectResponse.url().string().ascii().data());
99 ResourceRequest requestCopy { request };
100 ASSERT(m_state == State::Initialized || m_state == State::Filtering);
101 forEachContentFilterUntilBlocked([&requestCopy, &redirectResponse](PlatformContentFilter& contentFilter) {
102 contentFilter.willSendRequest(requestCopy, redirectResponse);
103 if (contentFilter.didBlockData())
104 requestCopy = ResourceRequest();
107 if (request != requestCopy)
108 LOG(ContentFiltering, "ContentFilter changed request url to <%s>.\n", requestCopy.url().string().ascii().data());
110 request = requestCopy;
113 void ContentFilter::startFilteringMainResource(CachedRawResource& resource)
115 LOG(ContentFiltering, "ContentFilter will start filtering main resource at <%s>.\n", resource.url().string().ascii().data());
116 ASSERT(m_state == State::Initialized);
117 m_state = State::Filtering;
118 ASSERT(!m_mainResource);
119 m_mainResource = &resource;
120 ASSERT(!m_mainResource->hasClient(this));
121 m_mainResource->addClient(this);
124 ContentFilterUnblockHandler ContentFilter::unblockHandler() const
126 ASSERT(m_state == State::Blocked);
127 ASSERT(m_blockingContentFilter);
128 ASSERT(m_blockingContentFilter->didBlockData());
129 return m_blockingContentFilter->unblockHandler();
132 Ref<SharedBuffer> ContentFilter::replacementData() const
134 ASSERT(m_state == State::Blocked);
135 ASSERT(m_blockingContentFilter);
136 ASSERT(m_blockingContentFilter->didBlockData());
137 return m_blockingContentFilter->replacementData();
140 String ContentFilter::unblockRequestDeniedScript() const
142 ASSERT(m_state == State::Blocked);
143 ASSERT(m_blockingContentFilter);
144 ASSERT(m_blockingContentFilter->didBlockData());
145 return m_blockingContentFilter->unblockRequestDeniedScript();
148 void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse& response)
150 LOG(ContentFiltering, "ContentFilter received response from <%s>.\n", response.url().string().ascii().data());
151 ASSERT(m_state == State::Filtering);
152 ASSERT_UNUSED(resource, resource == m_mainResource.get());
153 forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) {
154 contentFilter.responseReceived(response);
158 void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length)
160 LOG(ContentFiltering, "ContentFilter received %d bytes of data from <%s>.\n", length, resource->url().string().ascii().data());
161 ASSERT(m_state == State::Filtering);
162 ASSERT_UNUSED(resource, resource == m_mainResource.get());
163 forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) {
164 contentFilter.addData(data, length);
168 void ContentFilter::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
170 ASSERT(m_state == State::Filtering);
171 ASSERT_UNUSED(resource, resource == m_mainResource.get());
172 willSendRequest(request, redirectResponse);
175 void ContentFilter::notifyFinished(CachedResource* resource)
177 LOG(ContentFiltering, "ContentFilter will finish filtering main resource at <%s>.\n", resource->url().string().ascii().data());
178 ASSERT(m_state == State::Filtering);
179 ASSERT_UNUSED(resource, resource == m_mainResource.get());
180 forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) {
181 contentFilter.finishedAddingData();
185 void ContentFilter::forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)> function)
187 bool allFiltersAllowedLoad { true };
188 for (auto& contentFilter : m_contentFilters) {
189 if (!contentFilter->needsMoreData()) {
190 ASSERT(!contentFilter->didBlockData());
194 function(*contentFilter);
196 if (contentFilter->didBlockData()) {
197 ASSERT(!m_blockingContentFilter);
198 m_blockingContentFilter = contentFilter.get();
199 didDecide(State::Blocked);
201 } else if (contentFilter->needsMoreData())
202 allFiltersAllowedLoad = false;
205 if (allFiltersAllowedLoad)
206 didDecide(State::Allowed);
209 void ContentFilter::didDecide(State state)
211 ASSERT(m_state != State::Allowed);
212 ASSERT(m_state != State::Blocked);
213 ASSERT(state == State::Allowed || state == State::Blocked);
214 LOG(ContentFiltering, "ContentFilter decided load should be %s for main resource at <%s>.\n", state == State::Allowed ? "allowed" : "blocked", m_mainResource ? m_mainResource->url().string().ascii().data() : "");
217 // Calling m_decisionFunction might delete |this|.
218 if (m_decisionFunction)
219 m_decisionFunction();
222 } // namespace WebCore
224 #endif // ENABLE(CONTENT_FILTERING)