Home | History | Annotate | Download | only in mac
      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