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