/* * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "Download.h" #import #import #import #import #import #import #import #import "DataReference.h" #import "WebPage.h" @interface NSURLDownload (WebNSURLDownloadDetails) +(id)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r delegate:(id)delegate proxy:(id)proxy; - (void)_setOriginatingURL:(NSURL *)originatingURL; @end @interface WKDownloadAsDelegate : NSObject { WebKit::Download* _download; } - (id)initWithDownload:(WebKit::Download*)download; - (void)invalidate; @end using namespace WebCore; namespace WebKit { static KURL originatingURLFromBackForwardList(WebPage *webPage) { if (!webPage) return KURL(); Page* page = webPage->corePage(); if (!page) return KURL(); KURL originalURL; int backCount = page->backForward()->backCount(); for (int backIndex = 0; backIndex <= backCount; backIndex++) { // FIXME: At one point we had code here to check a "was user gesture" flag. // Do we need to restore that logic? HistoryItem* historyItem = page->backForward()->itemAtIndex(-backIndex); if (!historyItem) continue; originalURL = historyItem->originalURL(); if (!originalURL.isNull()) return originalURL; } return KURL(); } static void setOriginalURLForDownload(WebPage *webPage, NSURLDownload *download, const ResourceRequest& initialRequest) { KURL originalURL; // If there was no referrer, don't traverse the back/forward history // since this download was initiated directly. if (!initialRequest.httpReferrer().isNull()) { // find the first item in the history that was originated by the user originalURL = originatingURLFromBackForwardList(webPage); } if (originalURL.isNull()) originalURL = initialRequest.url(); NSURL *originalNSURL = originalURL; NSString *scheme = [originalNSURL scheme]; NSString *host = [originalNSURL host]; if (scheme && host && [scheme length] && [host length]) { NSNumber *port = [originalNSURL port]; if (port && [port intValue] < 0) port = nil; RetainPtr hostOnlyURLString; if (port) hostOnlyURLString.adoptNS([[NSString alloc] initWithFormat:@"%@://%@:%d", scheme, host, [port intValue]]); else hostOnlyURLString.adoptNS([[NSString alloc] initWithFormat:@"%@://%@", scheme, host]); RetainPtr hostOnlyURL = [[NSURL alloc] initWithString:hostOnlyURLString.get()]; ASSERT([download respondsToSelector:@selector(_setOriginatingURL:)]); [download _setOriginatingURL:hostOnlyURL.get()]; } } void Download::start(WebPage* initiatingPage) { ASSERT(!m_nsURLDownload); ASSERT(!m_delegate); m_delegate.adoptNS([[WKDownloadAsDelegate alloc] initWithDownload:this]); m_nsURLDownload.adoptNS([[NSURLDownload alloc] initWithRequest:m_request.nsURLRequest() delegate:m_delegate.get()]); // FIXME: Allow this to be changed by the client. [m_nsURLDownload.get() setDeletesFileUponFailure:NO]; setOriginalURLForDownload(initiatingPage, m_nsURLDownload.get(), m_request); } void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle* handle, const ResourceRequest& initialRequest, const ResourceResponse& response) { ASSERT(!m_nsURLDownload); ASSERT(!m_delegate); id proxy = handle->releaseProxy(); ASSERT(proxy); m_delegate.adoptNS([[WKDownloadAsDelegate alloc] initWithDownload:this]); m_nsURLDownload = [NSURLDownload _downloadWithLoadingConnection:handle->connection() request:m_request.nsURLRequest() response:response.nsURLResponse() delegate:m_delegate.get() proxy:proxy]; // FIXME: Allow this to be changed by the client. [m_nsURLDownload.get() setDeletesFileUponFailure:NO]; setOriginalURLForDownload(initiatingPage, m_nsURLDownload.get(), initialRequest); } void Download::cancel() { [m_nsURLDownload.get() cancel]; RetainPtr resumeData = [m_nsURLDownload.get() resumeData]; didCancel(CoreIPC::DataReference(reinterpret_cast([resumeData.get() bytes]), [resumeData.get() length])); } void Download::platformInvalidate() { ASSERT(m_nsURLDownload); ASSERT(m_delegate); [m_delegate.get() invalidate]; m_delegate = nullptr; m_nsURLDownload = nullptr; } void Download::didDecideDestination(const String& destination, bool allowOverwrite) { } void Download::platformDidFinish() { } void Download::receivedCredential(const AuthenticationChallenge& authenticationChallenge, const Credential& credential) { [authenticationChallenge.sender() useCredential:mac(credential) forAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; } void Download::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& authenticationChallenge) { [authenticationChallenge.sender() continueWithoutCredentialForAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; } void Download::receivedCancellation(const AuthenticationChallenge& authenticationChallenge) { [authenticationChallenge.sender() cancelAuthenticationChallenge:authenticationChallenge.nsURLAuthenticationChallenge()]; } } // namespace WebKit @implementation WKDownloadAsDelegate - (id)initWithDownload:(WebKit::Download*)download { self = [super init]; if (!self) return nil; _download = download; return self; } - (void)invalidate { _download = 0; } - (void)downloadDidBegin:(NSURLDownload *)download { if (_download) _download->didStart(); } - (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { return request; } - (BOOL)download:(NSURLDownload *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { // FIXME: Implement. notImplemented(); return NO; } - (void)download:(NSURLDownload *)download didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if (_download) _download->didReceiveAuthenticationChallenge(core(challenge)); } - (void)download:(NSURLDownload *)download didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { // FIXME: Implement. notImplemented(); } - (BOOL)downloadShouldUseCredentialStorage:(NSURLDownload *)download { return NO; } - (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response { if (_download) _download->didReceiveResponse(response); } - (void)download:(NSURLDownload *)download willResumeWithResponse:(NSURLResponse *)response fromByte:(long long)startingByte { // FIXME: Implement. notImplemented(); } - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length { if (_download) _download->didReceiveData(length); } - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType { if (_download) return _download->shouldDecodeSourceDataOfMIMEType(encodingType); return YES; } - (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename { String destination; bool allowOverwrite; if (_download) destination = _download->decideDestinationWithSuggestedFilename(filename, allowOverwrite); if (!destination.isNull()) [download setDestination:destination allowOverwrite:allowOverwrite]; } - (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path { if (_download) _download->didCreateDestination(path); } - (void)downloadDidFinish:(NSURLDownload *)download { if (_download) _download->didFinish(); } - (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error { if (!_download) return; RetainPtr resumeData = [download resumeData]; CoreIPC::DataReference dataReference(reinterpret_cast([resumeData.get() bytes]), [resumeData.get() length]); _download->didFail(error, dataReference); } @end