2 * Copyright (C) 2012, 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 #import "CustomProtocolManager.h"
29 #import "ChildProcess.h"
30 #import "CustomProtocolManagerMessages.h"
31 #import "CustomProtocolManagerProxyMessages.h"
32 #import "DataReference.h"
33 #import "WebCoreArgumentCoders.h"
34 #import "WebProcessCreationParameters.h"
35 #import <WebCore/URL.h>
36 #import <WebCore/ResourceError.h>
37 #import <WebCore/ResourceRequest.h>
38 #import <WebCore/ResourceResponse.h>
40 #if ENABLE(NETWORK_PROCESS)
41 #import "NetworkProcessCreationParameters.h"
45 #if __has_include(<Foundation/NSURLConnectionPrivate.h>)
46 #import <Foundation/NSURLConnectionPrivate.h>
50 @interface NSURLConnection ()
51 + (CFRunLoopRef)resourceLoaderRunLoop;
54 using namespace WebKit;
58 static CustomProtocolManager* sharedCustomProtocolManager;
60 static uint64_t generateCustomProtocolID()
62 static uint64_t uniqueCustomProtocolID = 0;
63 return ++uniqueCustomProtocolID;
68 @interface WKCustomProtocol : NSURLProtocol {
70 uint64_t _customProtocolID;
72 @property (nonatomic, readonly) uint64_t customProtocolID;
75 @implementation WKCustomProtocol
77 @synthesize customProtocolID = _customProtocolID;
79 + (BOOL)canInitWithRequest:(NSURLRequest *)request
81 return sharedCustomProtocolManager->supportsScheme([[[request URL] scheme] lowercaseString]);
84 + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
89 + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b
94 - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client
96 self = [super initWithRequest:request cachedResponse:cachedResponse client:client];
100 _customProtocolID = generateCustomProtocolID();
101 sharedCustomProtocolManager->addCustomProtocol(self);
107 sharedCustomProtocolManager->childProcess()->send(Messages::CustomProtocolManagerProxy::StartLoading(self.customProtocolID, [self request]), 0);
112 sharedCustomProtocolManager->childProcess()->send(Messages::CustomProtocolManagerProxy::StopLoading(self.customProtocolID), 0);
113 sharedCustomProtocolManager->removeCustomProtocol(self);
120 const char* CustomProtocolManager::supplementName()
122 return "CustomProtocolManager";
125 CustomProtocolManager::CustomProtocolManager(ChildProcess* childProcess)
126 : m_childProcess(childProcess)
127 , m_messageQueue(WorkQueue::create("com.apple.WebKit.CustomProtocolManager"))
129 ASSERT(!sharedCustomProtocolManager);
130 sharedCustomProtocolManager = this;
133 void CustomProtocolManager::initializeConnection(IPC::Connection* connection)
135 connection->addWorkQueueMessageReceiver(Messages::CustomProtocolManager::messageReceiverName(), m_messageQueue.get(), this);
138 void CustomProtocolManager::initialize(const WebProcessCreationParameters& parameters)
140 #if ENABLE(NETWORK_PROCESS)
141 ASSERT(parameters.urlSchemesRegisteredForCustomProtocols.isEmpty() || !parameters.usesNetworkProcess);
142 if (parameters.usesNetworkProcess) {
143 m_childProcess->parentProcessConnection()->removeWorkQueueMessageReceiver(Messages::CustomProtocolManager::messageReceiverName());
144 m_messageQueue = nullptr;
149 [NSURLProtocol registerClass:[WKCustomProtocol class]];
151 for (size_t i = 0; i < parameters.urlSchemesRegisteredForCustomProtocols.size(); ++i)
152 registerScheme(parameters.urlSchemesRegisteredForCustomProtocols[i]);
155 #if ENABLE(NETWORK_PROCESS)
156 void CustomProtocolManager::initialize(const NetworkProcessCreationParameters& parameters)
158 [NSURLProtocol registerClass:[WKCustomProtocol class]];
160 for (size_t i = 0; i < parameters.urlSchemesRegisteredForCustomProtocols.size(); ++i)
161 registerScheme(parameters.urlSchemesRegisteredForCustomProtocols[i]);
165 void CustomProtocolManager::addCustomProtocol(WKCustomProtocol *customProtocol)
167 ASSERT(customProtocol);
168 DeprecatedMutexLocker locker(m_customProtocolMapMutex);
169 m_customProtocolMap.add(customProtocol.customProtocolID, customProtocol);
172 void CustomProtocolManager::removeCustomProtocol(WKCustomProtocol *customProtocol)
174 ASSERT(customProtocol);
175 DeprecatedMutexLocker locker(m_customProtocolMapMutex);
176 m_customProtocolMap.remove(customProtocol.customProtocolID);
179 void CustomProtocolManager::registerScheme(const String& scheme)
181 ASSERT(!scheme.isNull());
182 DeprecatedMutexLocker locker(m_registeredSchemesMutex);
183 m_registeredSchemes.add(scheme);
186 void CustomProtocolManager::unregisterScheme(const String& scheme)
188 ASSERT(!scheme.isNull());
189 DeprecatedMutexLocker locker(m_registeredSchemesMutex);
190 m_registeredSchemes.remove(scheme);
193 bool CustomProtocolManager::supportsScheme(const String& scheme)
198 DeprecatedMutexLocker locker(m_registeredSchemesMutex);
199 return m_registeredSchemes.contains(scheme);
202 static inline void dispatchOnResourceLoaderRunLoop(void (^block)())
204 CFRunLoopPerformBlock([NSURLConnection resourceLoaderRunLoop], kCFRunLoopDefaultMode, block);
205 CFRunLoopWakeUp([NSURLConnection resourceLoaderRunLoop]);
208 void CustomProtocolManager::didFailWithError(uint64_t customProtocolID, const WebCore::ResourceError& error)
210 RetainPtr<WKCustomProtocol> protocol = protocolForID(customProtocolID);
214 RetainPtr<NSError> nsError = error.nsError();
216 dispatchOnResourceLoaderRunLoop(^ {
217 [[protocol client] URLProtocol:protocol.get() didFailWithError:nsError.get()];
220 removeCustomProtocol(protocol.get());
223 void CustomProtocolManager::didLoadData(uint64_t customProtocolID, const IPC::DataReference& data)
225 RetainPtr<WKCustomProtocol> protocol = protocolForID(customProtocolID);
229 RetainPtr<NSData> nsData = adoptNS([[NSData alloc] initWithBytes:data.data() length:data.size()]);
231 dispatchOnResourceLoaderRunLoop(^ {
232 [[protocol client] URLProtocol:protocol.get() didLoadData:nsData.get()];
236 void CustomProtocolManager::didReceiveResponse(uint64_t customProtocolID, const WebCore::ResourceResponse& response, uint32_t cacheStoragePolicy)
238 RetainPtr<WKCustomProtocol> protocol = protocolForID(customProtocolID);
242 RetainPtr<NSURLResponse> nsResponse = response.nsURLResponse();
244 dispatchOnResourceLoaderRunLoop(^ {
245 [[protocol client] URLProtocol:protocol.get() didReceiveResponse:nsResponse.get() cacheStoragePolicy:static_cast<NSURLCacheStoragePolicy>(cacheStoragePolicy)];
249 void CustomProtocolManager::didFinishLoading(uint64_t customProtocolID)
251 RetainPtr<WKCustomProtocol> protocol = protocolForID(customProtocolID);
255 dispatchOnResourceLoaderRunLoop(^ {
256 [[protocol client] URLProtocolDidFinishLoading:protocol.get()];
259 removeCustomProtocol(protocol.get());
262 RetainPtr<WKCustomProtocol> CustomProtocolManager::protocolForID(uint64_t customProtocolID)
264 DeprecatedMutexLocker locker(m_customProtocolMapMutex);
266 CustomProtocolMap::const_iterator it = m_customProtocolMap.find(customProtocolID);
267 if (it == m_customProtocolMap.end())
274 } // namespace WebKit