Reviewed by Darin.
[WebKit-https.git] / WebCore / platform / network / mac / ResourceHandleMac.mm
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "ResourceHandle.h"
28 #import "ResourceHandleInternal.h"
29
30 #import "BlockExceptions.h"
31 #import "DocLoader.h"
32 #import "FrameLoader.h"
33 #import "FrameMac.h"
34 #import "ResourceError.h"
35 #import "ResourceResponse.h"
36 #import "SubresourceLoader.h"
37 #import "WebCoreSystemInterface.h"
38
39 using namespace WebCore;
40
41 @interface WebCoreResourceHandleAsDelegate : NSObject <NSURLAuthenticationChallengeSender>
42 {
43     ResourceHandle* m_handle;
44 }
45 - (id)initWithHandle:(ResourceHandle*)handle;
46 - (void)detachHandle;
47 @end
48
49 @interface NSURLConnection (NSURLConnectionTigerPrivate)
50 - (NSData *)_bufferedData;
51 @end
52
53 @interface NSURLProtocol (WebFoundationSecret) 
54 + (void)_removePropertyForKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
55 @end
56
57 namespace WebCore {
58    
59 static unsigned inNSURLConnectionCallback;
60 static bool NSURLConnectionSupportsBufferedData;
61     
62 #ifndef NDEBUG
63 static bool isInitializingConnection;
64 #endif
65     
66 ResourceHandleInternal::~ResourceHandleInternal()
67 {
68 }
69
70 ResourceHandle::~ResourceHandle()
71 {
72     releaseDelegate();
73 }
74
75 bool ResourceHandle::start(Frame* frame)
76 {
77     if (!frame)
78         return false;
79
80     BEGIN_BLOCK_OBJC_EXCEPTIONS;
81
82     // If we are no longer attached to a Page, this must be an attempted load from an
83     // onUnload handler, so let's just block it.
84     if (!frame->page())
85         return false;
86   
87 #ifndef NDEBUG
88     isInitializingConnection = YES;
89 #endif
90     id delegate;
91     
92     if (d->m_mightDownloadFromHandle) {
93         ASSERT(!d->m_proxy);
94         d->m_proxy = wkCreateNSURLConnectionDelegateProxy();
95         [d->m_proxy.get() setDelegate:ResourceHandle::delegate()];
96         [d->m_proxy.get() release];
97         
98         delegate = d->m_proxy.get();
99     } else 
100         delegate = ResourceHandle::delegate();
101     
102     NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:d->m_request.nsURLRequest() delegate:delegate];
103 #ifndef NDEBUG
104     isInitializingConnection = NO;
105 #endif
106     d->m_connection = connection;
107     [connection release];
108     if (d->m_defersLoading)
109         wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), YES);
110     
111     if (d->m_connection)
112         return true;
113
114     END_BLOCK_OBJC_EXCEPTIONS;
115
116     return false;
117 }
118
119 void ResourceHandle::cancel()
120 {
121     [d->m_connection.get() cancel];
122 }
123
124 void ResourceHandle::setDefersLoading(bool defers)
125 {
126     d->m_defersLoading = defers;
127     wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers);
128 }
129
130 WebCoreResourceHandleAsDelegate *ResourceHandle::delegate()
131 {
132     if (!d->m_delegate) {
133         WebCoreResourceHandleAsDelegate *delegate = [[WebCoreResourceHandleAsDelegate alloc] initWithHandle:this];
134         d->m_delegate = delegate;
135         [delegate release];
136     }
137     return d->m_delegate.get();
138 }
139
140 void ResourceHandle::releaseDelegate()
141 {
142     if (!d->m_delegate)
143         return;
144     [d->m_delegate.get() detachHandle];
145     d->m_delegate = nil;
146 }
147
148 bool ResourceHandle::supportsBufferedData()
149 {
150     static bool initialized = false;
151     if (!initialized) {
152         NSURLConnectionSupportsBufferedData = [NSURLConnection instancesRespondToSelector:@selector(_bufferedData)];
153         initialized = true;
154     }
155
156     return NSURLConnectionSupportsBufferedData;
157 }
158
159 NSData* ResourceHandle::bufferedData()
160 {
161     if (ResourceHandle::supportsBufferedData())
162         return [d->m_connection.get() _bufferedData];
163
164     return nil;
165 }
166
167 id ResourceHandle::releaseProxy()
168 {
169     id proxy = [[d->m_proxy.get() retain] autorelease];
170     d->m_proxy = nil;
171     [proxy setDelegate:nil];
172     return proxy;
173 }
174
175 NSURLConnection *ResourceHandle::connection() const
176 {
177     return d->m_connection.get();
178 }
179
180 bool ResourceHandle::loadsBlocked()
181 {
182     return inNSURLConnectionCallback != 0;
183 }
184
185 } // namespace WebCore
186
187 @implementation WebCoreResourceHandleAsDelegate
188
189 - (id)initWithHandle:(ResourceHandle*)handle
190 {
191     self = [self init];
192     if (!self)
193         return nil;
194     m_handle = handle;
195     return self;
196 }
197
198 - (void)detachHandle
199 {
200     m_handle = 0;
201 }
202
203 - (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
204 {
205     if (!m_handle)
206         return nil;
207     ++inNSURLConnectionCallback;
208     ResourceRequest request = newRequest;
209     m_handle->client()->willSendRequest(m_handle, request, redirectResponse);
210     --inNSURLConnectionCallback;
211     return request.nsURLRequest();
212 }
213
214 - (void)connection:(NSURLConnection *)con didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
215 {
216     if (!m_handle)
217         return;
218     ++inNSURLConnectionCallback;
219     m_handle->client()->didReceiveAuthenticationChallenge(m_handle, challenge);
220     --inNSURLConnectionCallback;
221 }
222
223 - (void)connection:(NSURLConnection *)con didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
224 {
225     if (!m_handle)
226         return;
227     ++inNSURLConnectionCallback;
228     m_handle->client()->didCancelAuthenticationChallenge(m_handle, challenge);
229     --inNSURLConnectionCallback;
230 }
231
232 - (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
233 {
234     if (!m_handle)
235         return;
236     ++inNSURLConnectionCallback;
237     m_handle->client()->didReceiveResponse(m_handle, r);
238     --inNSURLConnectionCallback;
239 }
240
241 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
242 {
243     if (!m_handle)
244         return;
245     ++inNSURLConnectionCallback;
246     m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], lengthReceived);
247     --inNSURLConnectionCallback;
248 }
249
250 - (void)connection:(NSURLConnection *)con willStopBufferingData:(NSData *)data
251 {
252     if (!m_handle)
253         return;
254     ++inNSURLConnectionCallback;
255     m_handle->client()->willStopBufferingData(m_handle, data);
256     --inNSURLConnectionCallback;
257 }
258
259 - (void)connectionDidFinishLoading:(NSURLConnection *)con
260 {
261     if (!m_handle)
262         return;
263     ++inNSURLConnectionCallback;
264     m_handle->client()->didFinishLoading(m_handle);
265     --inNSURLConnectionCallback;
266 }
267
268 - (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
269 {
270     if (!m_handle)
271         return;
272     ++inNSURLConnectionCallback;
273     m_handle->client()->didFail(m_handle, error);
274     --inNSURLConnectionCallback;
275 }
276
277 - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
278 {
279 #ifndef NDEBUG
280     if (isInitializingConnection)
281         LOG_ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (40676250)");
282 #endif
283     if (!m_handle)
284         return nil;
285     ++inNSURLConnectionCallback;
286     NSCachedURLResponse *result = m_handle->client()->willCacheResponse(m_handle, cachedResponse);
287     --inNSURLConnectionCallback;
288     return result;
289 }
290
291 - (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
292 {
293     if (!m_handle)
294         return;
295     m_handle->client()->receivedCredential(m_handle, challenge, credential);
296 }
297
298 - (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
299 {
300     if (!m_handle)
301         return;
302     m_handle->client()->receivedRequestToContinueWithoutCredential(m_handle, challenge);
303 }
304
305 - (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
306 {
307     if (!m_handle)
308         return;
309     m_handle->client()->receivedCancellation(m_handle, challenge);
310 }
311
312 @end