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 55 using namespace WebCore; 56 57 namespace WebKit { 58 59 static 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 85 static 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 120 void 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 134 void 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 155 void 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 163 void 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 173 void Download::didDecideDestination(const String& destination, bool allowOverwrite) 174 { 175 } 176 177 void Download::platformDidFinish() 178 { 179 } 180 181 void Download::receivedCredential(const AuthenticationChallenge& authenticationChallenge, const Credential& credential) 182 { 183 [authenticationChallenge.sender() useCredential:mac(credential) forAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; 184 } 185 186 void Download::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& authenticationChallenge) 187 { 188 [authenticationChallenge.sender() continueWithoutCredentialForAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; 189 } 190 191 void 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