Replace WTF::move with WTFMove
[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 "DocumentLoader.h"
34 #include "Logging.h"
35 #include "NetworkExtensionContentFilter.h"
36 #include "ParentalControlsContentFilter.h"
37 #include "SharedBuffer.h"
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/Vector.h>
40
41 #if !LOG_DISABLED
42 #include <wtf/text/CString.h>
43 #endif
44
45 namespace WebCore {
46
47 Vector<ContentFilter::Type>& ContentFilter::types()
48 {
49     static NeverDestroyed<Vector<ContentFilter::Type>> types {
50         Vector<ContentFilter::Type> {
51 #if HAVE(PARENTAL_CONTROLS)
52             type<ParentalControlsContentFilter>(),
53 #endif
54 #if HAVE(NETWORK_EXTENSION)
55             type<NetworkExtensionContentFilter>()
56 #endif
57         }
58     };
59     return types;
60 }
61
62 std::unique_ptr<ContentFilter> ContentFilter::createIfEnabled(DocumentLoader& documentLoader)
63 {
64     Container filters;
65     for (auto& type : types()) {
66         if (!type.enabled())
67             continue;
68
69         auto filter = type.create();
70         ASSERT(filter);
71         filters.append(WTFMove(filter));
72     }
73
74     if (filters.isEmpty())
75         return nullptr;
76
77     return std::make_unique<ContentFilter>(WTFMove(filters), documentLoader);
78 }
79
80 ContentFilter::ContentFilter(Container contentFilters, DocumentLoader& documentLoader)
81     : m_contentFilters { WTFMove(contentFilters) }
82     , m_documentLoader { documentLoader }
83 {
84     LOG(ContentFiltering, "Creating ContentFilter with %zu platform content filter(s).\n", m_contentFilters.size());
85     ASSERT(!m_contentFilters.isEmpty());
86 }
87
88 ContentFilter::~ContentFilter()
89 {
90     LOG(ContentFiltering, "Destroying ContentFilter.\n");
91     if (!m_mainResource)
92         return;
93     ASSERT(m_mainResource->hasClient(this));
94     m_mainResource->removeClient(this);
95 }
96
97 void ContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
98 {
99     LOG(ContentFiltering, "ContentFilter received request for <%s> with redirect response from <%s>.\n", request.url().string().ascii().data(), redirectResponse.url().string().ascii().data());
100     ResourceRequest requestCopy { request };
101     ASSERT(m_state == State::Initialized || m_state == State::Filtering);
102     forEachContentFilterUntilBlocked([&requestCopy, &redirectResponse](PlatformContentFilter& contentFilter) {
103         contentFilter.willSendRequest(requestCopy, redirectResponse);
104         if (contentFilter.didBlockData())
105             requestCopy = ResourceRequest();
106     });
107 #if !LOG_DISABLED
108     if (request != requestCopy)
109         LOG(ContentFiltering, "ContentFilter changed request url to <%s>.\n", requestCopy.url().string().ascii().data());
110 #endif
111     request = requestCopy;
112 }
113
114 void ContentFilter::startFilteringMainResource(CachedRawResource& resource)
115 {
116     LOG(ContentFiltering, "ContentFilter will start filtering main resource at <%s>.\n", resource.url().string().ascii().data());
117     ASSERT(m_state == State::Initialized);
118     m_state = State::Filtering;
119     ASSERT(!m_mainResource);
120     m_mainResource = &resource;
121     ASSERT(!m_mainResource->hasClient(this));
122     m_mainResource->addClient(this);
123 }
124
125 void ContentFilter::stopFilteringMainResource()
126 {
127     m_state = State::Stopped;
128     if (!m_mainResource)
129         return;
130
131     ASSERT(m_mainResource->hasClient(this));
132     m_mainResource->removeClient(this);
133     m_mainResource = nullptr;
134 }
135
136 ContentFilterUnblockHandler ContentFilter::unblockHandler() const
137 {
138     ASSERT(m_state == State::Blocked);
139     ASSERT(m_blockingContentFilter);
140     ASSERT(m_blockingContentFilter->didBlockData());
141     return m_blockingContentFilter->unblockHandler();
142 }
143
144 Ref<SharedBuffer> ContentFilter::replacementData() const
145 {
146     ASSERT(m_state == State::Blocked);
147     ASSERT(m_blockingContentFilter);
148     ASSERT(m_blockingContentFilter->didBlockData());
149     return m_blockingContentFilter->replacementData();
150 }
151
152 String ContentFilter::unblockRequestDeniedScript() const
153 {
154     ASSERT(m_state == State::Blocked);
155     ASSERT(m_blockingContentFilter);
156     ASSERT(m_blockingContentFilter->didBlockData());
157     return m_blockingContentFilter->unblockRequestDeniedScript();
158 }
159
160 void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse& response)
161 {
162     ASSERT(resource);
163     ASSERT(resource == m_mainResource);
164     ASSERT(m_state != State::Initialized);
165     LOG(ContentFiltering, "ContentFilter received response from <%s>.\n", response.url().string().ascii().data());
166
167     if (m_state == State::Filtering) {
168         forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) {
169             contentFilter.responseReceived(response);
170         });
171     }
172
173     if (m_state != State::Blocked)
174         m_documentLoader.responseReceived(resource, response);
175 }
176
177 void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length)
178 {
179     ASSERT(resource);
180     ASSERT(resource == m_mainResource);
181     ASSERT(m_state != State::Initialized);
182     LOG(ContentFiltering, "ContentFilter received %d bytes of data from <%s>.\n", length, resource->url().string().ascii().data());
183
184     if (m_state == State::Filtering) {
185         forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) {
186             contentFilter.addData(data, length);
187         });
188
189         if (m_state == State::Allowed)
190             deliverResourceData(*resource);
191         return;
192     }
193
194     if (m_state == State::Allowed)
195         m_documentLoader.dataReceived(resource, data, length);
196 }
197
198 void ContentFilter::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
199 {
200     ASSERT(resource);
201     ASSERT(resource == m_mainResource);
202     ASSERT(m_state != State::Initialized);
203
204     if (m_state == State::Filtering)
205         willSendRequest(request, redirectResponse);
206
207     if (m_state != State::Blocked)
208         m_documentLoader.redirectReceived(resource, request, redirectResponse);
209 }
210
211 void ContentFilter::notifyFinished(CachedResource* resource)
212 {
213     ASSERT(resource);
214     ASSERT(resource == m_mainResource);
215     ASSERT(m_state != State::Initialized);
216     LOG(ContentFiltering, "ContentFilter will finish filtering main resource at <%s>.\n", resource->url().string().ascii().data());
217
218     if (resource->errorOccurred()) {
219         m_documentLoader.notifyFinished(resource);
220         return;
221     }
222
223     if (m_state == State::Filtering) {
224         forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) {
225             contentFilter.finishedAddingData();
226         });
227
228         if (m_state != State::Blocked)
229             deliverResourceData(*resource);
230         
231         if (m_state == State::Stopped)
232             return;
233     }
234
235     if (m_state != State::Blocked)
236         m_documentLoader.notifyFinished(resource);
237 }
238
239 void ContentFilter::forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)> function)
240 {
241     bool allFiltersAllowedLoad { true };
242     for (auto& contentFilter : m_contentFilters) {
243         if (!contentFilter->needsMoreData()) {
244             ASSERT(!contentFilter->didBlockData());
245             continue;
246         }
247
248         function(*contentFilter);
249
250         if (contentFilter->didBlockData()) {
251             ASSERT(!m_blockingContentFilter);
252             m_blockingContentFilter = contentFilter.get();
253             didDecide(State::Blocked);
254             return;
255         } else if (contentFilter->needsMoreData())
256             allFiltersAllowedLoad = false;
257     }
258
259     if (allFiltersAllowedLoad)
260         didDecide(State::Allowed);
261 }
262
263 void ContentFilter::didDecide(State state)
264 {
265     ASSERT(m_state != State::Allowed);
266     ASSERT(m_state != State::Blocked);
267     ASSERT(state == State::Allowed || state == State::Blocked);
268     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() : "");
269     m_state = state;
270     m_documentLoader.contentFilterDidDecide();
271 }
272
273 void ContentFilter::deliverResourceData(CachedResource& resource)
274 {
275     ASSERT(resource.dataBufferingPolicy() == BufferData);
276     if (auto* resourceBuffer = resource.resourceBuffer())
277         m_documentLoader.dataReceived(&resource, resourceBuffer->data(), resourceBuffer->size());
278 }
279
280 } // namespace WebCore
281
282 #endif // ENABLE(CONTENT_FILTERING)