b611371f2a2d0d5ac81d74c482d91abe7ef01c34
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / cocoa / NetworkSessionCocoa.mm
1 /*
2  * Copyright (C) 2015 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 "NetworkSession.h"
28
29 #if USE(NETWORK_SESSION)
30
31 #import <Foundation/NSURLSession.h>
32
33 #import <WebCore/AuthenticationChallenge.h>
34 #import <WebCore/Credential.h>
35 #import <WebCore/ResourceError.h>
36 #import <WebCore/ResourceRequest.h>
37 #import <WebCore/ResourceResponse.h>
38 #import <WebCore/SharedBuffer.h>
39 #import <wtf/MainThread.h>
40 #import <wtf/NeverDestroyed.h>
41
42 static NSURLSessionResponseDisposition toNSURLSessionResponseDisposition(WebKit::ResponseDisposition disposition)
43 {
44     switch (disposition) {
45     case WebKit::ResponseDisposition::Cancel:
46         return NSURLSessionResponseCancel;
47     case WebKit::ResponseDisposition::Allow:
48         return NSURLSessionResponseAllow;
49     case WebKit::ResponseDisposition::BecomeDownload:
50         return NSURLSessionResponseBecomeDownload;
51     }
52 }
53
54 static NSURLSessionAuthChallengeDisposition toNSURLSessionAuthChallengeDisposition(WebKit::AuthenticationChallengeDisposition disposition)
55 {
56     switch (disposition) {
57     case WebKit::AuthenticationChallengeDisposition::UseCredential:
58         return NSURLSessionAuthChallengeUseCredential;
59     case WebKit::AuthenticationChallengeDisposition::PerformDefaultHandling:
60         return NSURLSessionAuthChallengePerformDefaultHandling;
61     case WebKit::AuthenticationChallengeDisposition::Cancel:
62         return NSURLSessionAuthChallengeCancelAuthenticationChallenge;
63     case WebKit::AuthenticationChallengeDisposition::RejectProtectionSpace:
64         return NSURLSessionAuthChallengeRejectProtectionSpace;
65     }
66 }
67
68 @interface NetworkSessionDelegate : NSObject <NSURLSessionDataDelegate> {
69     WebKit::NetworkSession* _session;
70 }
71
72 - (id)initWithNetworkSession:(WebKit::NetworkSession&)session;
73
74 @end
75
76 @implementation NetworkSessionDelegate
77
78 - (id)initWithNetworkSession:(WebKit::NetworkSession&)session
79 {
80     self = [super init];
81     if (!self)
82         return nil;
83
84     _session = &session;
85
86     return self;
87 }
88
89 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
90 {
91     UNUSED_PARAM(session);
92
93     if (auto* networkingTask = _session->dataTaskForIdentifier(task.taskIdentifier)) {
94         if (auto* client = networkingTask->client()) {
95             client->willPerformHTTPRedirection(response, request, ^(const WebCore::ResourceRequest& request)
96                 {
97                     completionHandler(request.nsURLRequest(WebCore::UpdateHTTPBody));
98                 }
99             );
100         }
101     }
102 }
103
104 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
105 {
106     UNUSED_PARAM(session);
107
108     if (auto* networkingTask = _session->dataTaskForIdentifier(task.taskIdentifier)) {
109         if (auto* client = networkingTask->client()) {
110             client->didReceiveChallenge(challenge, ^(WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential)
111                 {
112                     completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), credential.nsCredential());
113                 }
114             );
115         }
116     }
117 }
118
119 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
120 {
121     UNUSED_PARAM(session);
122
123     if (auto* networkingTask = _session->dataTaskForIdentifier(task.taskIdentifier)) {
124         if (auto* client = networkingTask->client())
125             client->didCompleteWithError(error);
126     }
127 }
128
129 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
130 {
131     UNUSED_PARAM(session);
132
133     if (auto* networkingTask = _session->dataTaskForIdentifier(dataTask.taskIdentifier)) {
134         if (auto* client = networkingTask->client()) {
135             ASSERT(isMainThread());
136             WebCore::ResourceResponse resourceResponse(response);
137             client->didReceiveResponse(resourceResponse, ^(WebKit::ResponseDisposition responseDisposition)
138                 {
139                     completionHandler(toNSURLSessionResponseDisposition(responseDisposition));
140                 }
141             );
142         }
143     }
144 }
145
146 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
147 {
148     UNUSED_PARAM(session);
149
150     if (auto* networkingTask = _session->dataTaskForIdentifier(dataTask.taskIdentifier)) {
151         if (auto* client = networkingTask->client())
152             client->didReceiveData(WebCore::SharedBuffer::wrapNSData(data));
153     }
154 }
155
156 @end
157
158 namespace WebKit {
159     
160 Ref<NetworkSession> NetworkSession::create(Type type)
161 {
162     return adoptRef(*new NetworkSession(type));
163 }
164
165 Ref<NetworkSession> NetworkSession::singleton()
166 {
167     static NeverDestroyed<Ref<NetworkSession>> sharedInstance(NetworkSession::create(Type::Normal));
168     return sharedInstance.get().copyRef();
169 }
170     
171 static NSURLSessionConfiguration *configurationForType(NetworkSession::Type type)
172 {
173     switch (type) {
174     case NetworkSession::Type::Normal:
175         return [NSURLSessionConfiguration defaultSessionConfiguration];
176     case NetworkSession::Type::Ephemeral:
177         return [NSURLSessionConfiguration ephemeralSessionConfiguration];
178     }
179 }
180
181 NetworkSession::NetworkSession(Type type)
182 {
183     m_sessionDelegate = adoptNS([[NetworkSessionDelegate alloc] initWithNetworkSession:*this]);
184
185     NSURLSessionConfiguration *configuration = configurationForType(type);
186     m_session = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_sessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
187 }
188
189 RefPtr<NetworkingDataTask> NetworkSession::createDataTaskWithRequest(const WebCore::ResourceRequest& request, NetworkSessionTaskClient& client)
190 {
191     RefPtr<NetworkingDataTask> task = adoptRef(new NetworkingDataTask(*this, client, [m_session dataTaskWithRequest:request.nsURLRequest(WebCore::UpdateHTTPBody)]));
192     return task;
193 }
194
195 NetworkingDataTask* NetworkSession::dataTaskForIdentifier(uint64_t taskIdentifier)
196 {
197     ASSERT(isMainThread());
198     return m_dataTaskMap.get(taskIdentifier);
199 }
200
201 NetworkingDataTask::NetworkingDataTask(NetworkSession& session, NetworkSessionTaskClient& client, RetainPtr<NSURLSessionDataTask> task)
202     : m_session(session)
203     , m_task(task)
204     , m_client(&client)
205 {
206     ASSERT(!m_session.m_dataTaskMap.contains(taskIdentifier()));
207     ASSERT(isMainThread());
208     m_session.m_dataTaskMap.add(taskIdentifier(), this);
209 }
210
211 NetworkingDataTask::~NetworkingDataTask()
212 {
213     ASSERT(m_session.m_dataTaskMap.contains(taskIdentifier()));
214     ASSERT(m_session.m_dataTaskMap.get(taskIdentifier()) == this);
215     ASSERT(isMainThread());
216     m_session.m_dataTaskMap.remove(taskIdentifier());
217 }
218
219 void NetworkingDataTask::suspend()
220 {
221     [m_task suspend];
222 }
223
224 void NetworkingDataTask::resume()
225 {
226     [m_task resume];
227 }
228
229 uint64_t NetworkingDataTask::taskIdentifier()
230 {
231     return [m_task taskIdentifier];
232 }
233
234 }
235
236 #endif