2 * Copyright (C) 2005 Apple Computer, 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
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #import <WebKit/WebDownload.h>
31 #import <Foundation/NSURLAuthenticationChallenge.h>
32 #import <Foundation/NSURLDownload.h>
33 #import <WebCore/AuthenticationCF.h>
34 #import <WebCore/AuthenticationMac.h>
35 #import <WebCore/Credential.h>
36 #import <WebCore/CredentialStorage.h>
37 #import <WebCore/ProtectionSpace.h>
38 #import <WebKit/WebPanelAuthenticationHandler.h>
39 #import <wtf/Assertions.h>
41 #import "WebTypesInternal.h"
44 #import <CFNetwork/CFNetwork.h>
45 #import <CFNetwork/CFURLConnection.h>
48 using namespace WebCore;
50 @class NSURLConnectionDelegateProxy;
52 // FIXME: The following are NSURLDownload SPI - it would be nice to not have to override them at
53 // some point in the future
54 @interface NSURLDownload (WebDownloadCapability)
55 - (id)_initWithLoadingConnection:(NSURLConnection *)connection
56 request:(NSURLRequest *)request
57 response:(NSURLResponse *)response
59 proxy:(NSURLConnectionDelegateProxy *)proxy;
60 - (id)_initWithRequest:(NSURLRequest *)request
62 directory:(NSString *)directory;
65 - (id)_initWithLoadingCFURLConnection:(CFURLConnectionRef)connection
66 request:(CFURLRequestRef)request
67 response:(CFURLResponseRef)response
69 proxy:(NSURLConnectionDelegateProxy *)proxy;
74 @interface WebDownloadInternal : NSObject <NSURLDownloadDelegate>
80 - (void)setRealDelegate:(id)rd;
84 @implementation WebDownloadInternal
88 [realDelegate release];
92 - (void)setRealDelegate:(id)rd
95 [realDelegate release];
99 - (BOOL)respondsToSelector:(SEL)selector
101 if (selector == @selector(downloadDidBegin:) ||
102 selector == @selector(download:willSendRequest:redirectResponse:) ||
103 selector == @selector(download:didReceiveResponse:) ||
104 selector == @selector(download:didReceiveDataOfLength:) ||
105 selector == @selector(download:shouldDecodeSourceDataOfMIMEType:) ||
106 selector == @selector(download:decideDestinationWithSuggestedFilename:) ||
107 selector == @selector(download:didCreateDestination:) ||
108 selector == @selector(downloadDidFinish:) ||
109 selector == @selector(download:didFailWithError:) ||
110 selector == @selector(download:shouldBeginChildDownloadOfSource:delegate:) ||
111 selector == @selector(download:didBeginChildDownload:)) {
112 return [realDelegate respondsToSelector:selector];
115 return [super respondsToSelector:selector];
118 - (void)downloadDidBegin:(NSURLDownload *)download
120 [realDelegate downloadDidBegin:download];
123 - (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
125 return [realDelegate download:download willSendRequest:request redirectResponse:redirectResponse];
128 - (void)download:(NSURLDownload *)download didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
130 // Try previously stored credential first.
131 if (![challenge previousFailureCount]) {
132 NSURLCredential *credential = mac(CredentialStorage::get(core([challenge protectionSpace])));
134 [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
139 if ([realDelegate respondsToSelector:@selector(download:didReceiveAuthenticationChallenge:)]) {
140 [realDelegate download:download didReceiveAuthenticationChallenge:challenge];
142 NSWindow *window = nil;
143 if ([realDelegate respondsToSelector:@selector(downloadWindowForAuthenticationSheet:)]) {
144 window = [realDelegate downloadWindowForAuthenticationSheet:(WebDownload *)download];
147 [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window];
151 - (void)download:(NSURLDownload *)download didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
153 if ([realDelegate respondsToSelector:@selector(download:didCancelAuthenticationChallenge:)]) {
154 [realDelegate download:download didCancelAuthenticationChallenge:challenge];
156 [[WebPanelAuthenticationHandler sharedHandler] cancelAuthentication:challenge];
160 - (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response
162 [realDelegate download:download didReceiveResponse:response];
165 - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length
167 [realDelegate download:download didReceiveDataOfLength:length];
170 - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType
172 return [realDelegate download:download shouldDecodeSourceDataOfMIMEType:encodingType];
175 - (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
177 [realDelegate download:download decideDestinationWithSuggestedFilename:filename];
180 - (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path
182 [realDelegate download:download didCreateDestination:path];
185 - (void)downloadDidFinish:(NSURLDownload *)download
187 [realDelegate downloadDidFinish:download];
190 - (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
192 [realDelegate download:download didFailWithError:error];
195 - (NSURLRequest *)download:(NSURLDownload *)download shouldBeginChildDownloadOfSource:(NSURLRequest *)child delegate:(id *)childDelegate
197 return [realDelegate download:download shouldBeginChildDownloadOfSource:child delegate:childDelegate];
200 - (void)download:(NSURLDownload *)parent didBeginChildDownload:(NSURLDownload *)child
202 [realDelegate download:parent didBeginChildDownload:child];
207 @implementation WebDownload
209 - (void)_setRealDelegate:(id)delegate
211 if (_webInternal == nil) {
212 _webInternal = [[WebDownloadInternal alloc] init];
213 [_webInternal setRealDelegate:delegate];
215 ASSERT(_webInternal == delegate);
223 // _webInternal can be set up before init by _setRealDelegate
224 if (_webInternal == nil) {
225 _webInternal = [[WebDownloadInternal alloc] init];
233 [_webInternal release];
237 - (id)initWithRequest:(NSURLRequest *)request delegate:(id<NSURLDownloadDelegate>)delegate
239 [self _setRealDelegate:delegate];
240 return [super initWithRequest:request delegate:_webInternal];
243 - (id)_initWithLoadingConnection:(NSURLConnection *)connection
244 request:(NSURLRequest *)request
245 response:(NSURLResponse *)response
246 delegate:(id)delegate
247 proxy:(NSURLConnectionDelegateProxy *)proxy
249 [self _setRealDelegate:delegate];
250 return [super _initWithLoadingConnection:connection request:request response:response delegate:_webInternal proxy:proxy];
254 - (id)_initWithLoadingCFURLConnection:(CFURLConnectionRef)connection
255 request:(CFURLRequestRef)request
256 response:(CFURLResponseRef)response
257 delegate:(id)delegate
258 proxy:(NSURLConnectionDelegateProxy *)proxy
260 [self _setRealDelegate:delegate];
261 return [super _initWithLoadingCFURLConnection:connection request:request response:response delegate:_webInternal proxy:proxy];
265 - (id)_initWithRequest:(NSURLRequest *)request
266 delegate:(id)delegate
267 directory:(NSString *)directory
269 [self _setRealDelegate:delegate];
270 return [super _initWithRequest:request delegate:_webInternal directory:directory];
273 - (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data
275 // NSURLConnection calls this method even if it is not implemented.
276 // This happens because NSURLConnection caches the results of respondsToSelector.
277 // Those results become invalid when the delegate of NSURLConnectionDelegateProxy is changed.
278 // This is a workaround since this problem needs to be fixed in NSURLConnectionDelegateProxy.
279 // <rdar://problem/3913270> NSURLConnection calls unimplemented delegate method in WebDownload