Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / contentextensions / ContentExtensionsBackend.cpp
1 /*
2  * Copyright (C) 2014 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 "ContentExtensionsBackend.h"
28
29 #if ENABLE(CONTENT_EXTENSIONS)
30
31 #include "CompiledContentExtension.h"
32 #include "ContentExtension.h"
33 #include "ContentExtensionsDebugging.h"
34 #include "DFABytecodeInterpreter.h"
35 #include "Document.h"
36 #include "DocumentLoader.h"
37 #include "ExtensionStyleSheets.h"
38 #include "Frame.h"
39 #include "FrameLoaderClient.h"
40 #include "MainFrame.h"
41 #include "ResourceLoadInfo.h"
42 #include "URL.h"
43 #include "UserContentController.h"
44 #include <wtf/NeverDestroyed.h>
45 #include <wtf/text/CString.h>
46
47 namespace WebCore {
48
49 namespace ContentExtensions {
50     
51 void ContentExtensionsBackend::addContentExtension(const String& identifier, RefPtr<CompiledContentExtension> compiledContentExtension)
52 {
53     ASSERT(!identifier.isEmpty());
54     if (identifier.isEmpty())
55         return;
56
57     if (!compiledContentExtension) {
58         removeContentExtension(identifier);
59         return;
60     }
61
62     RefPtr<ContentExtension> extension = ContentExtension::create(identifier, adoptRef(*compiledContentExtension.leakRef()));
63     m_contentExtensions.set(identifier, WTFMove(extension));
64 }
65
66 void ContentExtensionsBackend::removeContentExtension(const String& identifier)
67 {
68     m_contentExtensions.remove(identifier);
69 }
70
71 void ContentExtensionsBackend::removeAllContentExtensions()
72 {
73     m_contentExtensions.clear();
74 }
75
76 Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLoadInfo& resourceLoadInfo) const
77 {
78 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
79     double addedTimeStart = monotonicallyIncreasingTime();
80 #endif
81     if (resourceLoadInfo.resourceURL.protocolIsData())
82         return Vector<Action>();
83
84     const String& urlString = resourceLoadInfo.resourceURL.string();
85     ASSERT_WITH_MESSAGE(urlString.containsOnlyASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
86     const CString& urlCString = urlString.utf8();
87
88     Vector<Action> finalActions;
89     ResourceFlags flags = resourceLoadInfo.getResourceFlags();
90     for (auto& contentExtension : m_contentExtensions.values()) {
91         RELEASE_ASSERT(contentExtension);
92         const CompiledContentExtension& compiledExtension = contentExtension->compiledExtension();
93         
94         DFABytecodeInterpreter withoutDomainsInterpreter(compiledExtension.filtersWithoutDomainsBytecode(), compiledExtension.filtersWithoutDomainsBytecodeLength());
95         DFABytecodeInterpreter::Actions withoutDomainsActions = withoutDomainsInterpreter.interpret(urlCString, flags);
96         
97         String domain = resourceLoadInfo.mainDocumentURL.host();
98         DFABytecodeInterpreter withDomainsInterpreter(compiledExtension.filtersWithDomainsBytecode(), compiledExtension.filtersWithDomainsBytecodeLength());
99         DFABytecodeInterpreter::Actions withDomainsActions = withDomainsInterpreter.interpretWithDomains(urlCString, flags, contentExtension->cachedDomainActions(domain));
100         
101         const SerializedActionByte* actions = compiledExtension.actions();
102         const unsigned actionsLength = compiledExtension.actionsLength();
103         
104         bool sawIgnorePreviousRules = false;
105         const Vector<uint32_t>& universalWithDomains = contentExtension->universalActionsWithDomains(domain);
106         const Vector<uint32_t>& universalWithoutDomains = contentExtension->universalActionsWithoutDomains();
107         if (!withoutDomainsActions.isEmpty() || !withDomainsActions.isEmpty() || !universalWithDomains.isEmpty() || !universalWithoutDomains.isEmpty()) {
108             Vector<uint32_t> actionLocations;
109             actionLocations.reserveInitialCapacity(withoutDomainsActions.size() + withDomainsActions.size() + universalWithoutDomains.size() + universalWithDomains.size());
110             for (uint64_t actionLocation : withoutDomainsActions)
111                 actionLocations.uncheckedAppend(static_cast<uint32_t>(actionLocation));
112             for (uint64_t actionLocation : withDomainsActions)
113                 actionLocations.uncheckedAppend(static_cast<uint32_t>(actionLocation));
114             for (uint32_t actionLocation : universalWithoutDomains)
115                 actionLocations.uncheckedAppend(actionLocation);
116             for (uint32_t actionLocation : universalWithDomains)
117                 actionLocations.uncheckedAppend(actionLocation);
118             std::sort(actionLocations.begin(), actionLocations.end());
119
120             // Add actions in reverse order to properly deal with IgnorePreviousRules.
121             for (unsigned i = actionLocations.size(); i; i--) {
122                 Action action = Action::deserialize(actions, actionsLength, actionLocations[i - 1]);
123                 action.setExtensionIdentifier(contentExtension->identifier());
124                 if (action.type() == ActionType::IgnorePreviousRules) {
125                     sawIgnorePreviousRules = true;
126                     break;
127                 }
128                 finalActions.append(action);
129             }
130         }
131         if (!sawIgnorePreviousRules) {
132             finalActions.append(Action(ActionType::CSSDisplayNoneStyleSheet, contentExtension->identifier()));
133             finalActions.last().setExtensionIdentifier(contentExtension->identifier());
134         }
135     }
136 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
137     double addedTimeEnd = monotonicallyIncreasingTime();
138     dataLogF("Time added: %f microseconds %s \n", (addedTimeEnd - addedTimeStart) * 1.0e6, resourceLoadInfo.resourceURL.string().utf8().data());
139 #endif
140     return finalActions;
141 }
142
143 StyleSheetContents* ContentExtensionsBackend::globalDisplayNoneStyleSheet(const String& identifier) const
144 {
145     const auto& contentExtension = m_contentExtensions.get(identifier);
146     return contentExtension ? contentExtension->globalDisplayNoneStyleSheet() : nullptr;
147 }
148
149 BlockedStatus ContentExtensionsBackend::processContentExtensionRulesForLoad(ResourceRequest& request, ResourceType resourceType, DocumentLoader& initiatingDocumentLoader)
150 {
151     Document* currentDocument = nullptr;
152     URL mainDocumentURL;
153
154     if (Frame* frame = initiatingDocumentLoader.frame()) {
155         currentDocument = frame->document();
156
157         if (initiatingDocumentLoader.isLoadingMainResource()
158             && frame->isMainFrame()
159             && resourceType == ResourceType::Document)
160             mainDocumentURL = request.url();
161         else if (Document* mainDocument = frame->mainFrame().document())
162             mainDocumentURL = mainDocument->url();
163     }
164
165     ResourceLoadInfo resourceLoadInfo = { request.url(), mainDocumentURL, resourceType };
166     Vector<ContentExtensions::Action> actions = actionsForResourceLoad(resourceLoadInfo);
167
168     bool willBlockLoad = false;
169     for (const auto& action : actions) {
170         switch (action.type()) {
171         case ContentExtensions::ActionType::BlockLoad:
172             willBlockLoad = true;
173             break;
174         case ContentExtensions::ActionType::BlockCookies:
175             request.setAllowCookies(false);
176             break;
177         case ContentExtensions::ActionType::CSSDisplayNoneSelector:
178             if (resourceType == ResourceType::Document)
179                 initiatingDocumentLoader.addPendingContentExtensionDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID());
180             else if (currentDocument)
181                 currentDocument->extensionStyleSheets().addDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID());
182             break;
183         case ContentExtensions::ActionType::CSSDisplayNoneStyleSheet: {
184             StyleSheetContents* styleSheetContents = globalDisplayNoneStyleSheet(action.stringArgument());
185             if (styleSheetContents) {
186                 if (resourceType == ResourceType::Document)
187                     initiatingDocumentLoader.addPendingContentExtensionSheet(action.stringArgument(), *styleSheetContents);
188                 else if (currentDocument)
189                     currentDocument->extensionStyleSheets().maybeAddContentExtensionSheet(action.stringArgument(), *styleSheetContents);
190             }
191             break;
192         }
193         case ContentExtensions::ActionType::MakeHTTPS: {
194             const URL originalURL = request.url();
195             if (originalURL.protocolIs("http") && (!originalURL.hasPort() || isDefaultPortForProtocol(originalURL.port(), originalURL.protocol()))) {
196                 URL newURL = originalURL;
197                 newURL.setProtocol("https");
198                 if (originalURL.hasPort())
199                     newURL.setPort(defaultPortForProtocol("https"));
200                 request.setURL(newURL);
201
202                 if (resourceType == ResourceType::Document && initiatingDocumentLoader.isLoadingMainResource()) {
203                     // This is to make sure the correct 'new' URL shows in the location bar.
204                     initiatingDocumentLoader.request().setURL(newURL);
205                     initiatingDocumentLoader.frameLoader()->client().dispatchDidChangeProvisionalURL();
206                 }
207                 if (currentDocument)
208                     currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker promoted URL from ", originalURL.string(), " to ", newURL.string()));
209             }
210             break;
211         }
212         case ContentExtensions::ActionType::IgnorePreviousRules:
213         case ContentExtensions::ActionType::InvalidAction:
214             RELEASE_ASSERT_NOT_REACHED();
215         }
216     }
217
218     if (willBlockLoad) {
219         if (currentDocument)
220             currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker prevented frame displaying ", mainDocumentURL.string(), " from loading a resource from ", request.url().string()));
221         return BlockedStatus::Blocked;
222     }
223     return BlockedStatus::NotBlocked;
224 }
225
226 const String& ContentExtensionsBackend::displayNoneCSSRule()
227 {
228     static NeverDestroyed<const String> rule(ASCIILiteral("display:none !important;"));
229     return rule;
230 }
231
232 } // namespace ContentExtensions
233
234 } // namespace WebCore
235
236 #endif // ENABLE(CONTENT_EXTENSIONS)