initial import
[vuplus_webkit] / Source / WebKit / mac / Misc / WebDownload.mm
1 /*
2  * Copyright (C) 2005 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  *
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. 
16  *
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.
27  */
28
29 #import <WebKit/WebDownload.h>
30
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>
40
41 #import "WebTypesInternal.h"
42
43 #if USE(CFNETWORK)
44 #import <CFNetwork/CFNetwork.h>
45 #import <CFNetwork/CFURLConnection.h>
46 #endif
47
48 using namespace WebCore;
49
50 @class NSURLConnectionDelegateProxy;
51
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
58                         delegate:(id)delegate
59                            proxy:(NSURLConnectionDelegateProxy *)proxy;
60 - (id)_initWithRequest:(NSURLRequest *)request
61               delegate:(id)delegate
62              directory:(NSString *)directory;
63
64 #if USE(CFNETWORK)
65 - (id)_initWithLoadingCFURLConnection:(CFURLConnectionRef)connection
66                               request:(CFURLRequestRef)request
67                              response:(CFURLResponseRef)response
68                              delegate:(id)delegate
69                                 proxy:(NSURLConnectionDelegateProxy *)proxy;
70 #endif
71
72 @end
73
74 @interface WebDownloadInternal : NSObject <NSURLDownloadDelegate>
75 {
76 @public
77     id realDelegate;
78 }
79
80 - (void)setRealDelegate:(id)rd;
81
82 @end
83
84 @implementation WebDownloadInternal
85
86 - (void)dealloc
87 {
88     [realDelegate release];
89     [super dealloc];
90 }
91
92 - (void)setRealDelegate:(id)rd
93 {
94     [rd retain];
95     [realDelegate release];
96     realDelegate = rd;
97 }
98
99 - (BOOL)respondsToSelector:(SEL)selector
100 {
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];
113     }
114
115     return [super respondsToSelector:selector];
116 }
117
118 - (void)downloadDidBegin:(NSURLDownload *)download
119 {
120     [realDelegate downloadDidBegin:download];
121 }
122
123 - (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
124 {
125     return [realDelegate download:download willSendRequest:request redirectResponse:redirectResponse];
126 }
127
128 - (void)download:(NSURLDownload *)download didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
129 {
130     // Try previously stored credential first.
131     if (![challenge previousFailureCount]) {
132         NSURLCredential *credential = mac(CredentialStorage::get(core([challenge protectionSpace])));
133         if (credential) {
134             [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
135             return;
136         }
137     }
138
139     if ([realDelegate respondsToSelector:@selector(download:didReceiveAuthenticationChallenge:)]) {
140         [realDelegate download:download didReceiveAuthenticationChallenge:challenge];
141     } else {
142         NSWindow *window = nil;
143         if ([realDelegate respondsToSelector:@selector(downloadWindowForAuthenticationSheet:)]) {
144             window = [realDelegate downloadWindowForAuthenticationSheet:(WebDownload *)download];
145         }
146
147         [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window];
148     }
149 }
150
151 - (void)download:(NSURLDownload *)download didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
152 {
153     if ([realDelegate respondsToSelector:@selector(download:didCancelAuthenticationChallenge:)]) {
154         [realDelegate download:download didCancelAuthenticationChallenge:challenge];
155     } else {
156         [[WebPanelAuthenticationHandler sharedHandler] cancelAuthentication:challenge];
157     }
158 }
159
160 - (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response
161 {
162     [realDelegate download:download didReceiveResponse:response];
163 }
164
165 - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length
166 {
167     [realDelegate download:download didReceiveDataOfLength:length];
168 }
169
170 - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType
171 {
172     return [realDelegate download:download shouldDecodeSourceDataOfMIMEType:encodingType];
173 }
174
175 - (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
176 {
177     [realDelegate download:download decideDestinationWithSuggestedFilename:filename];
178 }
179
180 - (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path
181 {
182     [realDelegate download:download didCreateDestination:path];
183 }
184
185 - (void)downloadDidFinish:(NSURLDownload *)download
186 {
187     [realDelegate downloadDidFinish:download];
188 }
189
190 - (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
191 {
192     [realDelegate download:download didFailWithError:error];
193 }
194
195 - (NSURLRequest *)download:(NSURLDownload *)download shouldBeginChildDownloadOfSource:(NSURLRequest *)child delegate:(id *)childDelegate
196 {
197     return [realDelegate download:download shouldBeginChildDownloadOfSource:child delegate:childDelegate];
198 }
199
200 - (void)download:(NSURLDownload *)parent didBeginChildDownload:(NSURLDownload *)child
201 {
202     [realDelegate download:parent didBeginChildDownload:child];
203 }
204
205 @end
206
207 @implementation WebDownload
208
209 - (void)_setRealDelegate:(id)delegate
210 {
211     if (_webInternal == nil) {
212         _webInternal = [[WebDownloadInternal alloc] init];
213         [_webInternal setRealDelegate:delegate];
214     } else {
215         ASSERT(_webInternal == delegate);
216     }
217 }
218
219 - (id)init
220 {
221     self = [super init];
222     if (self != nil) {
223         // _webInternal can be set up before init by _setRealDelegate
224         if (_webInternal == nil) {
225             _webInternal = [[WebDownloadInternal alloc] init];
226         }
227     }
228     return self;
229 }
230
231 - (void)dealloc
232 {
233     [_webInternal release];
234     [super dealloc];
235 }
236
237 - (id)initWithRequest:(NSURLRequest *)request delegate:(id<NSURLDownloadDelegate>)delegate
238 {
239     [self _setRealDelegate:delegate];
240     return [super initWithRequest:request delegate:_webInternal];
241 }
242
243 - (id)_initWithLoadingConnection:(NSURLConnection *)connection
244                          request:(NSURLRequest *)request
245                         response:(NSURLResponse *)response
246                         delegate:(id)delegate
247                            proxy:(NSURLConnectionDelegateProxy *)proxy
248 {
249     [self _setRealDelegate:delegate];
250     return [super _initWithLoadingConnection:connection request:request response:response delegate:_webInternal proxy:proxy];
251 }
252
253 #if USE(CFNETWORK)
254 - (id)_initWithLoadingCFURLConnection:(CFURLConnectionRef)connection
255                               request:(CFURLRequestRef)request
256                              response:(CFURLResponseRef)response
257                              delegate:(id)delegate
258                                 proxy:(NSURLConnectionDelegateProxy *)proxy
259 {
260     [self _setRealDelegate:delegate];
261     return [super _initWithLoadingCFURLConnection:connection request:request response:response delegate:_webInternal proxy:proxy];
262 }
263 #endif
264
265 - (id)_initWithRequest:(NSURLRequest *)request
266               delegate:(id)delegate
267              directory:(NSString *)directory
268 {
269     [self _setRealDelegate:delegate];
270     return [super _initWithRequest:request delegate:_webInternal directory:directory];
271 }
272
273 - (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data
274 {
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
280 }
281
282 @end