WebDownload.mm 10 KB

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