1/* 2 * Copyright (C) 2010, 2011 Apple 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "Download.h" 28 29#import <WebCore/AuthenticationMac.h> 30#import <WebCore/BackForwardController.h> 31#import <WebCore/HistoryItem.h> 32#import <WebCore/NotImplemented.h> 33#import <WebCore/Page.h> 34#import <WebCore/ResourceHandle.h> 35#import <WebCore/ResourceResponse.h> 36#import "DataReference.h" 37#import "WebPage.h" 38 39@interface NSURLDownload (WebNSURLDownloadDetails) 40+(id)_downloadWithLoadingConnection:(NSURLConnection *)connection 41 request:(NSURLRequest *)request 42 response:(NSURLResponse *)r 43 delegate:(id)delegate 44 proxy:(id)proxy; 45- (void)_setOriginatingURL:(NSURL *)originatingURL; 46@end 47 48@interface WKDownloadAsDelegate : NSObject <NSURLDownloadDelegate> { 49 WebKit::Download* _download; 50} 51- (id)initWithDownload:(WebKit::Download*)download; 52- (void)invalidate; 53@end 54 55using namespace WebCore; 56 57namespace WebKit { 58 59static KURL originatingURLFromBackForwardList(WebPage *webPage) 60{ 61 if (!webPage) 62 return KURL(); 63 64 Page* page = webPage->corePage(); 65 if (!page) 66 return KURL(); 67 68 KURL originalURL; 69 int backCount = page->backForward()->backCount(); 70 for (int backIndex = 0; backIndex <= backCount; backIndex++) { 71 // FIXME: At one point we had code here to check a "was user gesture" flag. 72 // Do we need to restore that logic? 73 HistoryItem* historyItem = page->backForward()->itemAtIndex(-backIndex); 74 if (!historyItem) 75 continue; 76 77 originalURL = historyItem->originalURL(); 78 if (!originalURL.isNull()) 79 return originalURL; 80 } 81 82 return KURL(); 83} 84 85static void setOriginalURLForDownload(WebPage *webPage, NSURLDownload *download, const ResourceRequest& initialRequest) 86{ 87 KURL originalURL; 88 89 // If there was no referrer, don't traverse the back/forward history 90 // since this download was initiated directly. <rdar://problem/5294691> 91 if (!initialRequest.httpReferrer().isNull()) { 92 // find the first item in the history that was originated by the user 93 originalURL = originatingURLFromBackForwardList(webPage); 94 } 95 96 if (originalURL.isNull()) 97 originalURL = initialRequest.url(); 98 99 NSURL *originalNSURL = originalURL; 100 101 NSString *scheme = [originalNSURL scheme]; 102 NSString *host = [originalNSURL host]; 103 if (scheme && host && [scheme length] && [host length]) { 104 NSNumber *port = [originalNSURL port]; 105 if (port && [port intValue] < 0) 106 port = nil; 107 RetainPtr<NSString> hostOnlyURLString; 108 if (port) 109 hostOnlyURLString.adoptNS([[NSString alloc] initWithFormat:@"%@://%@:%d", scheme, host, [port intValue]]); 110 else 111 hostOnlyURLString.adoptNS([[NSString alloc] initWithFormat:@"%@://%@", scheme, host]); 112 113 RetainPtr<NSURL> hostOnlyURL = [[NSURL alloc] initWithString:hostOnlyURLString.get()]; 114 115 ASSERT([download respondsToSelector:@selector(_setOriginatingURL:)]); 116 [download _setOriginatingURL:hostOnlyURL.get()]; 117 } 118} 119 120void Download::start(WebPage* initiatingPage) 121{ 122 ASSERT(!m_nsURLDownload); 123 ASSERT(!m_delegate); 124 125 m_delegate.adoptNS([[WKDownloadAsDelegate alloc] initWithDownload:this]); 126 m_nsURLDownload.adoptNS([[NSURLDownload alloc] initWithRequest:m_request.nsURLRequest() delegate:m_delegate.get()]); 127 128 // FIXME: Allow this to be changed by the client. 129 [m_nsURLDownload.get() setDeletesFileUponFailure:NO]; 130 131 setOriginalURLForDownload(initiatingPage, m_nsURLDownload.get(), m_request); 132} 133 134void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle* handle, const ResourceRequest& initialRequest, const ResourceResponse& response) 135{ 136 ASSERT(!m_nsURLDownload); 137 ASSERT(!m_delegate); 138 139 id proxy = handle->releaseProxy(); 140 ASSERT(proxy); 141 142 m_delegate.adoptNS([[WKDownloadAsDelegate alloc] initWithDownload:this]); 143 m_nsURLDownload = [NSURLDownload _downloadWithLoadingConnection:handle->connection() 144 request:m_request.nsURLRequest() 145 response:response.nsURLResponse() 146 delegate:m_delegate.get() 147 proxy:proxy]; 148 149 // FIXME: Allow this to be changed by the client. 150 [m_nsURLDownload.get() setDeletesFileUponFailure:NO]; 151 152 setOriginalURLForDownload(initiatingPage, m_nsURLDownload.get(), initialRequest); 153} 154 155void Download::cancel() 156{ 157 [m_nsURLDownload.get() cancel]; 158 159 RetainPtr<NSData> resumeData = [m_nsURLDownload.get() resumeData]; 160 didCancel(CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([resumeData.get() bytes]), [resumeData.get() length])); 161} 162 163void Download::platformInvalidate() 164{ 165 ASSERT(m_nsURLDownload); 166 ASSERT(m_delegate); 167 168 [m_delegate.get() invalidate]; 169 m_delegate = nullptr; 170 m_nsURLDownload = nullptr; 171} 172 173void Download::didDecideDestination(const String& destination, bool allowOverwrite) 174{ 175} 176 177void Download::platformDidFinish() 178{ 179} 180 181void Download::receivedCredential(const AuthenticationChallenge& authenticationChallenge, const Credential& credential) 182{ 183 [authenticationChallenge.sender() useCredential:mac(credential) forAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; 184} 185 186void Download::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& authenticationChallenge) 187{ 188 [authenticationChallenge.sender() continueWithoutCredentialForAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; 189} 190 191void Download::receivedCancellation(const AuthenticationChallenge& authenticationChallenge) 192{ 193 [authenticationChallenge.sender() cancelAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; 194} 195 196} // namespace WebKit 197 198@implementation WKDownloadAsDelegate 199 200- (id)initWithDownload:(WebKit::Download*)download 201{ 202 self = [super init]; 203 if (!self) 204 return nil; 205 206 _download = download; 207 return self; 208} 209 210- (void)invalidate 211{ 212 _download = 0; 213} 214 215- (void)downloadDidBegin:(NSURLDownload *)download 216{ 217 if (_download) 218 _download->didStart(); 219} 220 221- (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse 222{ 223 return request; 224} 225 226- (BOOL)download:(NSURLDownload *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace 227{ 228 // FIXME: Implement. 229 notImplemented(); 230 return NO; 231} 232 233- (void)download:(NSURLDownload *)download didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 234{ 235 if (_download) 236 _download->didReceiveAuthenticationChallenge(core(challenge)); 237} 238 239- (void)download:(NSURLDownload *)download didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 240{ 241 // FIXME: Implement. 242 notImplemented(); 243} 244 245- (BOOL)downloadShouldUseCredentialStorage:(NSURLDownload *)download 246{ 247 return NO; 248} 249 250- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response 251{ 252 if (_download) 253 _download->didReceiveResponse(response); 254} 255 256- (void)download:(NSURLDownload *)download willResumeWithResponse:(NSURLResponse *)response fromByte:(long long)startingByte 257{ 258 // FIXME: Implement. 259 notImplemented(); 260} 261 262- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length 263{ 264 if (_download) 265 _download->didReceiveData(length); 266} 267 268- (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType 269{ 270 if (_download) 271 return _download->shouldDecodeSourceDataOfMIMEType(encodingType); 272 273 return YES; 274} 275 276- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename 277{ 278 String destination; 279 bool allowOverwrite; 280 if (_download) 281 destination = _download->decideDestinationWithSuggestedFilename(filename, allowOverwrite); 282 283 if (!destination.isNull()) 284 [download setDestination:destination allowOverwrite:allowOverwrite]; 285} 286 287- (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path 288{ 289 if (_download) 290 _download->didCreateDestination(path); 291} 292 293- (void)downloadDidFinish:(NSURLDownload *)download 294{ 295 if (_download) 296 _download->didFinish(); 297} 298 299- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error 300{ 301 if (!_download) 302 return; 303 304 RetainPtr<NSData> resumeData = [download resumeData]; 305 CoreIPC::DataReference dataReference(reinterpret_cast<const uint8_t*>([resumeData.get() bytes]), [resumeData.get() length]); 306 307 _download->didFail(error, dataReference); 308} 309 310@end 311