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