1/*
2 * Copyright (C) 2012 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 "CustomProtocolManagerProxy.h"
28
29#if ENABLE(CUSTOM_PROTOCOLS)
30
31#import "ChildProcessProxy.h"
32#import "Connection.h"
33#import "CustomProtocolManagerMessages.h"
34#import "CustomProtocolManagerProxyMessages.h"
35#import "DataReference.h"
36#import "WebCoreArgumentCoders.h"
37#import <WebCore/ResourceError.h>
38#import <WebCore/ResourceRequest.h>
39#import <WebCore/ResourceResponse.h>
40
41using namespace IPC;
42using namespace WebCore;
43using namespace WebKit;
44
45@interface WKCustomProtocolLoader : NSObject <NSURLConnectionDelegate> {
46@private
47    CustomProtocolManagerProxy* _customProtocolManagerProxy;
48    uint64_t _customProtocolID;
49    RefPtr<Connection> _connection;
50    NSURLCacheStoragePolicy _storagePolicy;
51    NSURLConnection *_urlConnection;
52}
53- (id)initWithCustomProtocolManagerProxy:(CustomProtocolManagerProxy*)customProtocolManagerProxy customProtocolID:(uint64_t)customProtocolID request:(NSURLRequest *)request connection:(Connection *)connection;
54@end
55
56@implementation WKCustomProtocolLoader
57
58- (id)initWithCustomProtocolManagerProxy:(CustomProtocolManagerProxy*)customProtocolManagerProxy customProtocolID:(uint64_t)customProtocolID request:(NSURLRequest *)request connection:(Connection *)connection
59{
60    self = [super init];
61    if (!self)
62        return nil;
63
64    ASSERT(customProtocolManagerProxy);
65    ASSERT(request);
66    ASSERT(connection);
67    _customProtocolManagerProxy = customProtocolManagerProxy;
68    _customProtocolID = customProtocolID;
69    _connection = connection;
70    _storagePolicy = NSURLCacheStorageNotAllowed;
71    _urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
72
73    return self;
74}
75
76- (void)dealloc
77{
78    _connection.clear();
79    [_urlConnection cancel];
80    [_urlConnection release];
81    [super dealloc];
82}
83
84- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
85{
86    ResourceError coreError(error);
87    _connection->send(Messages::CustomProtocolManager::DidFailWithError(_customProtocolID, coreError), 0);
88    _customProtocolManagerProxy->stopLoading(_customProtocolID);
89}
90
91- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
92{
93    ASSERT(_storagePolicy == NSURLCacheStorageNotAllowed);
94    _storagePolicy = [cachedResponse storagePolicy];
95    return cachedResponse;
96}
97
98- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
99{
100    ResourceResponse coreResponse(response);
101    _connection->send(Messages::CustomProtocolManager::DidReceiveResponse(_customProtocolID, coreResponse, _storagePolicy), 0);
102}
103
104- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
105{
106    IPC::DataReference coreData(static_cast<const uint8_t*>([data bytes]), [data length]);
107    _connection->send(Messages::CustomProtocolManager::DidLoadData(_customProtocolID, coreData), 0);
108}
109
110- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
111{
112    return request;
113}
114
115- (void)connectionDidFinishLoading:(NSURLConnection *)connection
116{
117    _connection->send(Messages::CustomProtocolManager::DidFinishLoading(_customProtocolID), 0);
118    _customProtocolManagerProxy->stopLoading(_customProtocolID);
119}
120
121@end
122
123namespace WebKit {
124
125CustomProtocolManagerProxy::CustomProtocolManagerProxy(ChildProcessProxy* childProcessProxy, WebContext& webContext)
126    : m_childProcessProxy(childProcessProxy)
127    , m_webContext(webContext)
128{
129    ASSERT(m_childProcessProxy);
130    m_childProcessProxy->addMessageReceiver(Messages::CustomProtocolManagerProxy::messageReceiverName(), *this);
131}
132
133void CustomProtocolManagerProxy::startLoading(uint64_t customProtocolID, const ResourceRequest& coreRequest)
134{
135    NSURLRequest *request = coreRequest.nsURLRequest(DoNotUpdateHTTPBody);
136    if (!request)
137        return;
138
139    WKCustomProtocolLoader *loader = [[WKCustomProtocolLoader alloc] initWithCustomProtocolManagerProxy:this customProtocolID:customProtocolID request:request connection:m_childProcessProxy->connection()];
140    ASSERT(loader);
141    ASSERT(!m_loaderMap.contains(customProtocolID));
142    m_loaderMap.add(customProtocolID, loader);
143    [loader release];
144}
145
146void CustomProtocolManagerProxy::stopLoading(uint64_t customProtocolID)
147{
148    m_loaderMap.remove(customProtocolID);
149}
150
151} // namespace WebKit
152
153#endif // ENABLE(CUSTOM_PROTOCOLS)
154