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/AuthenticationMac.h> 34#import <WebKit/WebPanelAuthenticationHandler.h> 35#import <wtf/Assertions.h> 36 37#import "WebTypesInternal.h" 38 39using namespace WebCore; 40 41@class NSURLConnectionDelegateProxy; 42 43// FIXME: The following are NSURLDownload SPI - it would be nice to not have to override them at 44// some point in the future 45@interface NSURLDownload (WebDownloadCapability) 46- (id)_initWithLoadingConnection:(NSURLConnection *)connection 47 request:(NSURLRequest *)request 48 response:(NSURLResponse *)response 49 delegate:(id)delegate 50 proxy:(NSURLConnectionDelegateProxy *)proxy; 51- (id)_initWithRequest:(NSURLRequest *)request 52 delegate:(id)delegate 53 directory:(NSString *)directory; 54@end 55 56@interface WebDownloadInternal : NSObject 57{ 58@public 59 id realDelegate; 60} 61 62- (void)setRealDelegate:(id)rd; 63 64@end 65 66@implementation WebDownloadInternal 67 68- (void)dealloc 69{ 70 [realDelegate release]; 71 [super dealloc]; 72} 73 74- (void)setRealDelegate:(id)rd 75{ 76 [rd retain]; 77 [realDelegate release]; 78 realDelegate = rd; 79} 80 81- (BOOL)respondsToSelector:(SEL)selector 82{ 83 if (selector == @selector(downloadDidBegin:) || 84 selector == @selector(download:willSendRequest:redirectResponse:) || 85 selector == @selector(download:didReceiveResponse:) || 86 selector == @selector(download:didReceiveDataOfLength:) || 87 selector == @selector(download:shouldDecodeSourceDataOfMIMEType:) || 88 selector == @selector(download:decideDestinationWithSuggestedFilename:) || 89 selector == @selector(download:didCreateDestination:) || 90 selector == @selector(downloadDidFinish:) || 91 selector == @selector(download:didFailWithError:) || 92 selector == @selector(download:shouldBeginChildDownloadOfSource:delegate:) || 93 selector == @selector(download:didBeginChildDownload:)) { 94 return [realDelegate respondsToSelector:selector]; 95 } 96 97 return [super respondsToSelector:selector]; 98} 99 100- (void)downloadDidBegin:(NSURLDownload *)download 101{ 102 [realDelegate downloadDidBegin:download]; 103} 104 105- (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse 106{ 107 return [realDelegate download:download willSendRequest:request redirectResponse:redirectResponse]; 108} 109 110- (void)download:(NSURLDownload *)download didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 111{ 112 // Try previously stored credential first. 113 if (![challenge previousFailureCount]) { 114 NSURLCredential *credential = WebCoreCredentialStorage::get([challenge protectionSpace]); 115 if (credential) { 116 [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; 117 return; 118 } 119 } 120 121 if ([realDelegate respondsToSelector:@selector(download:didReceiveAuthenticationChallenge:)]) { 122 [realDelegate download:download didReceiveAuthenticationChallenge:challenge]; 123 } else { 124 NSWindow *window = nil; 125 if ([realDelegate respondsToSelector:@selector(downloadWindowForAuthenticationSheet:)]) { 126 window = [realDelegate downloadWindowForAuthenticationSheet:(WebDownload *)download]; 127 } 128 129 [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window]; 130 } 131} 132 133- (void)download:(NSURLDownload *)download didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 134{ 135 if ([realDelegate respondsToSelector:@selector(download:didCancelAuthenticationChallenge:)]) { 136 [realDelegate download:download didCancelAuthenticationChallenge:challenge]; 137 } else { 138 [[WebPanelAuthenticationHandler sharedHandler] cancelAuthentication:challenge]; 139 } 140} 141 142- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response 143{ 144 [realDelegate download:download didReceiveResponse:response]; 145} 146 147- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length 148{ 149 [realDelegate download:download didReceiveDataOfLength:length]; 150} 151 152- (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType 153{ 154 return [realDelegate download:download shouldDecodeSourceDataOfMIMEType:encodingType]; 155} 156 157- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename 158{ 159 [realDelegate download:download decideDestinationWithSuggestedFilename:filename]; 160} 161 162- (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path 163{ 164 [realDelegate download:download didCreateDestination:path]; 165} 166 167- (void)downloadDidFinish:(NSURLDownload *)download 168{ 169 [realDelegate downloadDidFinish:download]; 170} 171 172- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error 173{ 174 [realDelegate download:download didFailWithError:error]; 175} 176 177- (NSURLRequest *)download:(NSURLDownload *)download shouldBeginChildDownloadOfSource:(NSURLRequest *)child delegate:(id *)childDelegate 178{ 179 return [realDelegate download:download shouldBeginChildDownloadOfSource:child delegate:childDelegate]; 180} 181 182- (void)download:(NSURLDownload *)parent didBeginChildDownload:(NSURLDownload *)child 183{ 184 [realDelegate download:parent didBeginChildDownload:child]; 185} 186 187@end 188 189@implementation WebDownload 190 191- (void)_setRealDelegate:(id)delegate 192{ 193 if (_webInternal == nil) { 194 _webInternal = [[WebDownloadInternal alloc] init]; 195 [_webInternal setRealDelegate:delegate]; 196 } else { 197 ASSERT(_webInternal == delegate); 198 } 199} 200 201- (id)init 202{ 203 self = [super init]; 204 if (self != nil) { 205 // _webInternal can be set up before init by _setRealDelegate 206 if (_webInternal == nil) { 207 _webInternal = [[WebDownloadInternal alloc] init]; 208 } 209 } 210 return self; 211} 212 213- (void)dealloc 214{ 215 [_webInternal release]; 216 [super dealloc]; 217} 218 219- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate 220{ 221 [self _setRealDelegate:delegate]; 222 return [super initWithRequest:request delegate:_webInternal]; 223} 224 225- (id)_initWithLoadingConnection:(NSURLConnection *)connection 226 request:(NSURLRequest *)request 227 response:(NSURLResponse *)response 228 delegate:(id)delegate 229 proxy:(NSURLConnectionDelegateProxy *)proxy 230{ 231 [self _setRealDelegate:delegate]; 232 return [super _initWithLoadingConnection:connection request:request response:response delegate:_webInternal proxy:proxy]; 233} 234 235- (id)_initWithRequest:(NSURLRequest *)request 236 delegate:(id)delegate 237 directory:(NSString *)directory 238{ 239 [self _setRealDelegate:delegate]; 240 return [super _initWithRequest:request delegate:_webInternal directory:directory]; 241} 242 243- (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data 244{ 245 // NSURLConnection calls this method even if it is not implemented. 246 // This happens because NSURLConnection caches the results of respondsToSelector. 247 // Those results become invalid when the delegate of NSURLConnectionDelegateProxy is changed. 248 // This is a workaround since this problem needs to be fixed in NSURLConnectionDelegateProxy. 249 // <rdar://problem/3913270> NSURLConnection calls unimplemented delegate method in WebDownload 250} 251 252@end 253