9c329e7bc44c756d9a73a5ff63307bf120007219
[WebKit-https.git] / Source / WebCore / platform / cocoa / ContentFilterUnblockHandlerCocoa.mm
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 #import "config.h"
27 #import "ContentFilterUnblockHandler.h"
28
29 #if ENABLE(CONTENT_FILTERING)
30
31 #import "ContentFilter.h"
32 #import "Logging.h"
33 #import "ResourceRequest.h"
34 #import <wtf/BlockObjCExceptions.h>
35
36 #if !LOG_DISABLED
37 #import <wtf/text/CString.h>
38 #endif
39
40 #if PLATFORM(IOS_FAMILY)
41 #import "WebCoreThreadRun.h"
42
43 #if HAVE(PARENTAL_CONTROLS)
44 #import <pal/spi/cocoa/WebFilterEvaluatorSPI.h>
45 #import <wtf/SoftLinking.h>
46
47 SOFT_LINK_PRIVATE_FRAMEWORK(WebContentAnalysis);
48 SOFT_LINK_CLASS(WebContentAnalysis, WebFilterEvaluator);
49
50 static NSString * const webFilterEvaluatorKey { @"webFilterEvaluator" };
51 #endif
52 #endif
53
54 static NSString * const unblockURLHostKey { @"unblockURLHost" };
55 static NSString * const unreachableURLKey { @"unreachableURL" };
56
57 namespace WebCore {
58
59 ContentFilterUnblockHandler::ContentFilterUnblockHandler(String unblockURLHost, UnblockRequesterFunction unblockRequester)
60     : m_unblockURLHost { WTFMove(unblockURLHost) }
61     , m_unblockRequester { WTFMove(unblockRequester) }
62 {
63     LOG(ContentFiltering, "Creating ContentFilterUnblockHandler with an unblock requester and unblock URL host <%s>.\n", m_unblockURLHost.ascii().data());
64 }
65
66 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
67 ContentFilterUnblockHandler::ContentFilterUnblockHandler(String unblockURLHost, RetainPtr<WebFilterEvaluator> evaluator)
68     : m_unblockURLHost { WTFMove(unblockURLHost) }
69     , m_webFilterEvaluator { WTFMove(evaluator) }
70 {
71     LOG(ContentFiltering, "Creating ContentFilterUnblockHandler with a WebFilterEvaluator and unblock URL host <%s>.\n", m_unblockURLHost.ascii().data());
72 }
73 #endif
74
75 void ContentFilterUnblockHandler::wrapWithDecisionHandler(const DecisionHandlerFunction& decisionHandler)
76 {
77     ContentFilterUnblockHandler wrapped { *this };
78     UnblockRequesterFunction wrappedRequester { [wrapped, decisionHandler](DecisionHandlerFunction wrappedDecisionHandler) {
79         wrapped.requestUnblockAsync([wrappedDecisionHandler, decisionHandler](bool unblocked) {
80             wrappedDecisionHandler(unblocked);
81             decisionHandler(unblocked);
82         });
83     }};
84 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
85     m_webFilterEvaluator = nullptr;
86 #endif
87     std::swap(m_unblockRequester, wrappedRequester);
88 }
89
90 bool ContentFilterUnblockHandler::needsUIProcess() const
91 {
92 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
93     return m_webFilterEvaluator;
94 #else
95     return false;
96 #endif
97 }
98
99 void ContentFilterUnblockHandler::encode(NSCoder *coder) const
100 {
101     ASSERT_ARG(coder, coder.allowsKeyedCoding && coder.requiresSecureCoding);
102     BEGIN_BLOCK_OBJC_EXCEPTIONS;
103     [coder encodeObject:m_unblockURLHost forKey:unblockURLHostKey];
104     [coder encodeObject:(NSURL *)m_unreachableURL forKey:unreachableURLKey];
105 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
106     [coder encodeObject:m_webFilterEvaluator.get() forKey:webFilterEvaluatorKey];
107 #endif
108     END_BLOCK_OBJC_EXCEPTIONS;
109 }
110
111 bool ContentFilterUnblockHandler::decode(NSCoder *coder, ContentFilterUnblockHandler& unblockHandler)
112 {
113     ASSERT_ARG(coder, coder.allowsKeyedCoding && coder.requiresSecureCoding);
114     BEGIN_BLOCK_OBJC_EXCEPTIONS;
115     unblockHandler.m_unblockURLHost = [coder decodeObjectOfClass:[NSString class] forKey:unblockURLHostKey];
116     unblockHandler.m_unreachableURL = [coder decodeObjectOfClass:[NSURL class] forKey:unreachableURLKey];
117 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
118     unblockHandler.m_webFilterEvaluator = [coder decodeObjectOfClass:getWebFilterEvaluatorClass() forKey:webFilterEvaluatorKey];
119 #endif
120     return true;
121     END_BLOCK_OBJC_EXCEPTIONS;
122     return false;
123 }
124
125 bool ContentFilterUnblockHandler::canHandleRequest(const ResourceRequest& request) const
126 {
127     if (!m_unblockRequester) {
128 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
129         if (!m_webFilterEvaluator)
130             return false;
131 #else
132         return false;
133 #endif
134     }
135
136     bool isUnblockRequest = request.url().protocolIs(ContentFilter::urlScheme()) && equalIgnoringASCIICase(request.url().host(), m_unblockURLHost);
137 #if !LOG_DISABLED
138     if (isUnblockRequest)
139         LOG(ContentFiltering, "ContentFilterUnblockHandler will handle <%s> as an unblock request.\n", request.url().string().ascii().data());
140 #endif
141     return isUnblockRequest;
142 }
143
144 static inline void dispatchToMainThread(void (^block)())
145 {
146     dispatch_async(dispatch_get_main_queue(), ^{
147 #if PLATFORM(IOS_FAMILY)
148         WebThreadRun(block);
149 #else
150         block();
151 #endif
152     });
153 }
154
155 void ContentFilterUnblockHandler::requestUnblockAsync(DecisionHandlerFunction decisionHandler) const
156 {
157 #if HAVE(PARENTAL_CONTROLS) && PLATFORM(IOS_FAMILY)
158     if (m_webFilterEvaluator) {
159         [m_webFilterEvaluator unblockWithCompletion:[decisionHandler](BOOL unblocked, NSError *) {
160             dispatchToMainThread([decisionHandler, unblocked] {
161                 LOG(ContentFiltering, "WebFilterEvaluator %s the unblock request.\n", unblocked ? "allowed" : "did not allow");
162                 decisionHandler(unblocked);
163             });
164         }];
165         return;
166     }
167 #endif
168
169     if (m_unblockRequester) {
170         m_unblockRequester([decisionHandler](bool unblocked) {
171             dispatchToMainThread([decisionHandler, unblocked] {
172                 decisionHandler(unblocked);
173             });
174         });
175     }
176 }
177
178 } // namespace WebCore
179
180 #endif // PLATFORM(IOS_FAMILY) && ENABLE(CONTENT_FILTERING)