Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 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 COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #import "config.h"
     27 #import "ResourceHandleInternal.h"
     28 
     29 #if !USE(CFNETWORK)
     30 
     31 #import "AuthenticationChallenge.h"
     32 #import "AuthenticationMac.h"
     33 #import "Base64.h"
     34 #import "BlobRegistry.h"
     35 #import "BlockExceptions.h"
     36 #import "CookieStorage.h"
     37 #import "CredentialStorage.h"
     38 #import "CachedResourceLoader.h"
     39 #import "EmptyProtocolDefinitions.h"
     40 #import "FormDataStreamMac.h"
     41 #import "Frame.h"
     42 #import "FrameLoader.h"
     43 #import "Logging.h"
     44 #import "MIMETypeRegistry.h"
     45 #import "Page.h"
     46 #import "ResourceError.h"
     47 #import "ResourceResponse.h"
     48 #import "SchedulePair.h"
     49 #import "Settings.h"
     50 #import "SharedBuffer.h"
     51 #import "SubresourceLoader.h"
     52 #import "WebCoreSystemInterface.h"
     53 #import "WebCoreURLResponse.h"
     54 #import <wtf/text/CString.h>
     55 #import <wtf/UnusedParam.h>
     56 
     57 #ifdef BUILDING_ON_TIGER
     58 typedef int NSInteger;
     59 #endif
     60 
     61 using namespace WebCore;
     62 
     63 @interface WebCoreResourceHandleAsDelegate : NSObject <NSURLConnectionDelegate> {
     64     ResourceHandle* m_handle;
     65 }
     66 - (id)initWithHandle:(ResourceHandle*)handle;
     67 - (void)detachHandle;
     68 @end
     69 
     70 // WebCoreNSURLConnectionDelegateProxy exists so that we can cast m_proxy to it in order
     71 // to disambiguate the argument type in the -setDelegate: call.  This avoids a spurious
     72 // warning that the compiler would otherwise emit.
     73 @interface WebCoreNSURLConnectionDelegateProxy : NSObject <NSURLConnectionDelegate>
     74 - (void)setDelegate:(id<NSURLConnectionDelegate>)delegate;
     75 @end
     76 
     77 @interface NSURLConnection (NSURLConnectionTigerPrivate)
     78 - (NSData *)_bufferedData;
     79 @end
     80 
     81 @interface NSURLConnection (Details)
     82 -(id)_initWithRequest:(NSURLRequest *)request delegate:(id)delegate usesCache:(BOOL)usesCacheFlag maxContentLength:(long long)maxContentLength startImmediately:(BOOL)startImmediately connectionProperties:(NSDictionary *)connectionProperties;
     83 @end
     84 
     85 @interface NSURLRequest (Details)
     86 - (id)_propertyForKey:(NSString *)key;
     87 @end
     88 
     89 #ifndef BUILDING_ON_TIGER
     90 
     91 class WebCoreSynchronousLoaderClient : public ResourceHandleClient {
     92 public:
     93     static PassOwnPtr<WebCoreSynchronousLoaderClient> create()
     94     {
     95         return adoptPtr(new WebCoreSynchronousLoaderClient);
     96     }
     97 
     98     virtual ~WebCoreSynchronousLoaderClient();
     99 
    100     void setAllowStoredCredentials(bool allow) { m_allowStoredCredentials = allow; }
    101     NSURLResponse *response() { return m_response; }
    102     NSMutableData *data() { return m_data; }
    103     NSError *error() { return m_error; }
    104     bool isDone() { return m_isDone; }
    105 
    106 private:
    107     WebCoreSynchronousLoaderClient()
    108         : m_allowStoredCredentials(false)
    109         , m_response(0)
    110         , m_data(0)
    111         , m_error(0)
    112         , m_isDone(false)
    113     {
    114     }
    115 
    116     virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/);
    117     virtual bool shouldUseCredentialStorage(ResourceHandle*);
    118     virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&);
    119     virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
    120     virtual void didReceiveData(ResourceHandle*, const char*, int, int /*encodedDataLength*/);
    121     virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
    122     virtual void didFail(ResourceHandle*, const ResourceError&);
    123 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
    124     virtual bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&);
    125 #endif
    126 
    127     bool m_allowStoredCredentials;
    128     NSURLResponse *m_response;
    129     NSMutableData *m_data;
    130     NSError *m_error;
    131     bool m_isDone;
    132 };
    133 
    134 static NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode";
    135 
    136 #endif
    137 
    138 namespace WebCore {
    139 
    140 #ifdef BUILDING_ON_TIGER
    141 static unsigned inNSURLConnectionCallback;
    142 #endif
    143 
    144 #ifndef NDEBUG
    145 static bool isInitializingConnection;
    146 #endif
    147 
    148 class CallbackGuard {
    149 public:
    150     CallbackGuard()
    151     {
    152 #ifdef BUILDING_ON_TIGER
    153         ++inNSURLConnectionCallback;
    154 #endif
    155     }
    156     ~CallbackGuard()
    157     {
    158 #ifdef BUILDING_ON_TIGER
    159         ASSERT(inNSURLConnectionCallback > 0);
    160         --inNSURLConnectionCallback;
    161 #endif
    162     }
    163 };
    164 
    165 #ifndef BUILDING_ON_TIGER
    166 static String encodeBasicAuthorization(const String& user, const String& password)
    167 {
    168     return base64Encode((user + ":" + password).utf8());
    169 }
    170 #endif
    171 
    172 ResourceHandleInternal::~ResourceHandleInternal()
    173 {
    174 }
    175 
    176 ResourceHandle::~ResourceHandle()
    177 {
    178     releaseDelegate();
    179     d->m_currentWebChallenge.setAuthenticationClient(0);
    180 
    181     LOG(Network, "Handle %p destroyed", this);
    182 }
    183 
    184 static const double MaxFoundationVersionWithoutdidSendBodyDataDelegate = 677.21;
    185 bool ResourceHandle::didSendBodyDataDelegateExists()
    186 {
    187     return NSFoundationVersionNumber > MaxFoundationVersionWithoutdidSendBodyDataDelegate;
    188 }
    189 
    190 static bool shouldRelaxThirdPartyCookiePolicy(const KURL& url)
    191 {
    192     // If a URL already has cookies, then we'll relax the 3rd party cookie policy and accept new cookies.
    193 
    194     NSHTTPCookieStorage *sharedStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    195 
    196     NSHTTPCookieAcceptPolicy cookieAcceptPolicy;
    197 #if USE(CFURLSTORAGESESSIONS)
    198     CFHTTPCookieStorageRef cfPrivateBrowsingStorage = privateBrowsingCookieStorage().get();
    199     if (cfPrivateBrowsingStorage)
    200         cookieAcceptPolicy =  wkGetHTTPCookieAcceptPolicy(cfPrivateBrowsingStorage);
    201     else
    202 #endif
    203         cookieAcceptPolicy = [sharedStorage cookieAcceptPolicy];
    204 
    205     if (cookieAcceptPolicy != NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain)
    206         return false;
    207 
    208     NSArray *cookies;
    209 #if USE(CFURLSTORAGESESSIONS)
    210     if (cfPrivateBrowsingStorage)
    211         cookies = wkHTTPCookiesForURL(cfPrivateBrowsingStorage, url);
    212     else
    213 #endif
    214         cookies = [sharedStorage cookiesForURL:url];
    215 
    216     return [cookies count];
    217 }
    218 
    219 void ResourceHandle::createNSURLConnection(id delegate, bool shouldUseCredentialStorage, bool shouldContentSniff)
    220 {
    221     // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made.
    222     if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty())
    223 #ifndef BUILDING_ON_TIGER
    224      && !firstRequest().url().protocolInHTTPFamily() // On Tiger, always pass credentials in URL, so that they get stored even if the request gets cancelled right away.
    225 #endif
    226     ) {
    227         KURL urlWithCredentials(firstRequest().url());
    228         urlWithCredentials.setUser(d->m_user);
    229         urlWithCredentials.setPass(d->m_pass);
    230         firstRequest().setURL(urlWithCredentials);
    231     }
    232 
    233     if (shouldRelaxThirdPartyCookiePolicy(firstRequest().url()))
    234         firstRequest().setFirstPartyForCookies(firstRequest().url());
    235 
    236 #if !defined(BUILDING_ON_TIGER)
    237     if (shouldUseCredentialStorage && firstRequest().url().protocolInHTTPFamily()) {
    238         if (d->m_user.isEmpty() && d->m_pass.isEmpty()) {
    239             // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication,
    240             // try and reuse the credential preemptively, as allowed by RFC 2617.
    241             d->m_initialCredential = CredentialStorage::get(firstRequest().url());
    242         } else {
    243             // If there is already a protection space known for the URL, update stored credentials before sending a request.
    244             // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately
    245             // (so that an authentication dialog doesn't pop up).
    246             CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), firstRequest().url());
    247         }
    248     }
    249 
    250     if (!d->m_initialCredential.isEmpty()) {
    251         // FIXME: Support Digest authentication, and Proxy-Authorization.
    252         String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password());
    253         firstRequest().addHTTPHeaderField("Authorization", authHeader);
    254     }
    255 
    256     NSURLRequest *nsRequest = firstRequest().nsURLRequest();
    257     if (!shouldContentSniff) {
    258         NSMutableURLRequest *mutableRequest = [[nsRequest copy] autorelease];
    259         wkSetNSURLRequestShouldContentSniff(mutableRequest, NO);
    260         nsRequest = mutableRequest;
    261     }
    262 
    263 #if !defined(BUILDING_ON_LEOPARD)
    264     ASSERT([NSURLConnection instancesRespondToSelector:@selector(_initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:)]);
    265     static bool supportsSettingConnectionProperties = true;
    266 #else
    267     static bool supportsSettingConnectionProperties = [NSURLConnection instancesRespondToSelector:@selector(_initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:)];
    268 #endif
    269 
    270 #if USE(CFURLSTORAGESESSIONS)
    271     if (CFURLStorageSessionRef storageSession = privateBrowsingStorageSession())
    272         nsRequest = [wkCopyRequestWithStorageSession(storageSession, nsRequest) autorelease];
    273 #endif
    274 
    275     if (supportsSettingConnectionProperties) {
    276         NSDictionary *sessionID = shouldUseCredentialStorage ? [NSDictionary dictionary] : [NSDictionary dictionaryWithObject:@"WebKitPrivateSession" forKey:@"_kCFURLConnectionSessionID"];
    277         NSDictionary *propertyDictionary = [NSDictionary dictionaryWithObject:sessionID forKey:@"kCFURLConnectionSocketStreamProperties"];
    278         d->m_connection.adoptNS([[NSURLConnection alloc] _initWithRequest:nsRequest delegate:delegate usesCache:YES maxContentLength:0 startImmediately:NO connectionProperties:propertyDictionary]);
    279         return;
    280     }
    281 
    282     d->m_connection.adoptNS([[NSURLConnection alloc] initWithRequest:nsRequest delegate:delegate startImmediately:NO]);
    283     return;
    284 
    285 #else
    286     // Building on Tiger. Don't use WebCore credential storage, don't try to disable content sniffing.
    287     UNUSED_PARAM(shouldUseCredentialStorage);
    288     UNUSED_PARAM(shouldContentSniff);
    289     d->m_connection.adoptNS([[NSURLConnection alloc] initWithRequest:firstRequest().nsURLRequest() delegate:delegate]);
    290 #endif
    291 }
    292 
    293 bool ResourceHandle::start(NetworkingContext* context)
    294 {
    295     if (!context)
    296         return false;
    297 
    298     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    299 
    300     // If NetworkingContext is invalid then we are no longer attached to a Page,
    301     // this must be an attempted load from an unload event handler, so let's just block it.
    302     if (!context->isValid())
    303         return false;
    304 
    305 #ifndef NDEBUG
    306     isInitializingConnection = YES;
    307 #endif
    308 
    309     ASSERT(!d->m_proxy);
    310     d->m_proxy.adoptNS(wkCreateNSURLConnectionDelegateProxy());
    311     [static_cast<WebCoreNSURLConnectionDelegateProxy*>(d->m_proxy.get()) setDelegate:ResourceHandle::delegate()];
    312 
    313     bool shouldUseCredentialStorage = !client() || client()->shouldUseCredentialStorage(this);
    314 
    315     if (!ResourceHandle::didSendBodyDataDelegateExists())
    316         associateStreamWithResourceHandle([firstRequest().nsURLRequest() HTTPBodyStream], this);
    317 
    318 #ifdef BUILDING_ON_TIGER
    319     // A conditional request sent by WebCore (e.g. to update appcache) can be for a resource that is not cacheable by NSURLConnection,
    320     // which can get confused and fail to load it in this case.
    321     if (firstRequest().isConditional())
    322         firstRequest().setCachePolicy(ReloadIgnoringCacheData);
    323 #endif
    324 
    325     d->m_needsSiteSpecificQuirks = context->needsSiteSpecificQuirks();
    326 
    327     createNSURLConnection(
    328         d->m_proxy.get(),
    329         shouldUseCredentialStorage,
    330         d->m_shouldContentSniff || context->localFileContentSniffingEnabled());
    331 
    332 #ifndef BUILDING_ON_TIGER
    333     bool scheduled = false;
    334     if (SchedulePairHashSet* scheduledPairs = context->scheduledRunLoopPairs()) {
    335         SchedulePairHashSet::iterator end = scheduledPairs->end();
    336         for (SchedulePairHashSet::iterator it = scheduledPairs->begin(); it != end; ++it) {
    337             if (NSRunLoop *runLoop = (*it)->nsRunLoop()) {
    338                 [connection() scheduleInRunLoop:runLoop forMode:(NSString *)(*it)->mode()];
    339                 scheduled = true;
    340             }
    341         }
    342     }
    343 
    344     // Start the connection if we did schedule with at least one runloop.
    345     // We can't start the connection until we have one runloop scheduled.
    346     if (scheduled)
    347         [connection() start];
    348     else
    349         d->m_startWhenScheduled = true;
    350 #endif
    351 
    352 #ifndef NDEBUG
    353     isInitializingConnection = NO;
    354 #endif
    355 
    356     LOG(Network, "Handle %p starting connection %p for %@", this, connection(), firstRequest().nsURLRequest());
    357 
    358     if (d->m_connection) {
    359         if (d->m_defersLoading)
    360             wkSetNSURLConnectionDefersCallbacks(connection(), YES);
    361 
    362         return true;
    363     }
    364 
    365     END_BLOCK_OBJC_EXCEPTIONS;
    366 
    367     return false;
    368 }
    369 
    370 void ResourceHandle::cancel()
    371 {
    372     LOG(Network, "Handle %p cancel connection %p", this, d->m_connection.get());
    373 
    374     // Leaks were seen on HTTP tests without this; can be removed once <rdar://problem/6886937> is fixed.
    375     if (d->m_currentMacChallenge)
    376         [[d->m_currentMacChallenge sender] cancelAuthenticationChallenge:d->m_currentMacChallenge];
    377 
    378     if (!ResourceHandle::didSendBodyDataDelegateExists())
    379         disassociateStreamWithResourceHandle([firstRequest().nsURLRequest() HTTPBodyStream]);
    380     [d->m_connection.get() cancel];
    381 }
    382 
    383 void ResourceHandle::platformSetDefersLoading(bool defers)
    384 {
    385     if (d->m_connection)
    386         wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers);
    387 }
    388 
    389 void ResourceHandle::schedule(SchedulePair* pair)
    390 {
    391 #ifndef BUILDING_ON_TIGER
    392     NSRunLoop *runLoop = pair->nsRunLoop();
    393     if (!runLoop)
    394         return;
    395     [d->m_connection.get() scheduleInRunLoop:runLoop forMode:(NSString *)pair->mode()];
    396     if (d->m_startWhenScheduled) {
    397         [d->m_connection.get() start];
    398         d->m_startWhenScheduled = false;
    399     }
    400 #else
    401     UNUSED_PARAM(pair);
    402 #endif
    403 }
    404 
    405 void ResourceHandle::unschedule(SchedulePair* pair)
    406 {
    407 #ifndef BUILDING_ON_TIGER
    408     if (NSRunLoop *runLoop = pair->nsRunLoop())
    409         [d->m_connection.get() unscheduleFromRunLoop:runLoop forMode:(NSString *)pair->mode()];
    410 #else
    411     UNUSED_PARAM(pair);
    412 #endif
    413 }
    414 
    415 WebCoreResourceHandleAsDelegate *ResourceHandle::delegate()
    416 {
    417     if (!d->m_delegate) {
    418         WebCoreResourceHandleAsDelegate *delegate = [[WebCoreResourceHandleAsDelegate alloc] initWithHandle:this];
    419         d->m_delegate = delegate;
    420         [delegate release];
    421     }
    422     return d->m_delegate.get();
    423 }
    424 
    425 void ResourceHandle::releaseDelegate()
    426 {
    427     if (!d->m_delegate)
    428         return;
    429     if (d->m_proxy)
    430         [d->m_proxy.get() setDelegate:nil];
    431     [d->m_delegate.get() detachHandle];
    432     d->m_delegate = nil;
    433 }
    434 
    435 bool ResourceHandle::supportsBufferedData()
    436 {
    437     static bool supportsBufferedData = [NSURLConnection instancesRespondToSelector:@selector(_bufferedData)];
    438     return supportsBufferedData;
    439 }
    440 
    441 PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
    442 {
    443     if (ResourceHandle::supportsBufferedData())
    444         return SharedBuffer::wrapNSData([d->m_connection.get() _bufferedData]);
    445 
    446     return 0;
    447 }
    448 
    449 id ResourceHandle::releaseProxy()
    450 {
    451     id proxy = [[d->m_proxy.get() retain] autorelease];
    452     d->m_proxy = nil;
    453     [proxy setDelegate:nil];
    454     return proxy;
    455 }
    456 
    457 NSURLConnection *ResourceHandle::connection() const
    458 {
    459     return d->m_connection.get();
    460 }
    461 
    462 bool ResourceHandle::loadsBlocked()
    463 {
    464 #ifndef BUILDING_ON_TIGER
    465     return false;
    466 #else
    467     // On Tiger, if we're in an NSURLConnection callback, that blocks all other NSURLConnection callbacks.
    468     // On Leopard and newer, it blocks only callbacks on that same NSURLConnection object, which is not
    469     // a problem in practice.
    470     return inNSURLConnectionCallback != 0;
    471 #endif
    472 }
    473 
    474 bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame*)
    475 {
    476 #ifndef BUILDING_ON_TIGER
    477     request.setCachePolicy(ReturnCacheDataDontLoad);
    478     NSURLResponse *nsURLResponse = nil;
    479     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    480 
    481    [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:nil];
    482 
    483     END_BLOCK_OBJC_EXCEPTIONS;
    484 
    485     return nsURLResponse;
    486 #else
    487     // <rdar://problem/6803217> - Re-enable after <rdar://problem/6786454> is resolved.
    488     UNUSED_PARAM(request);
    489     return false;
    490 #endif
    491 }
    492 
    493 void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
    494 {
    495     LOG(Network, "ResourceHandle::loadResourceSynchronously:%@ allowStoredCredentials:%u", request.nsURLRequest(), storedCredentials);
    496 
    497 #if ENABLE(BLOB)
    498     if (request.url().protocolIs("blob"))
    499         if (blobRegistry().loadResourceSynchronously(request, error, response, data))
    500             return;
    501 #endif
    502 
    503     NSError *nsError = nil;
    504     NSURLResponse *nsURLResponse = nil;
    505     NSData *result = nil;
    506 
    507     ASSERT(!request.isEmpty());
    508 
    509 #ifndef BUILDING_ON_TIGER
    510     OwnPtr<WebCoreSynchronousLoaderClient> client = WebCoreSynchronousLoaderClient::create();
    511     client->setAllowStoredCredentials(storedCredentials == AllowStoredCredentials);
    512 
    513     RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, client.get(), false /*defersLoading*/, true /*shouldContentSniff*/));
    514 
    515     if (context && handle->d->m_scheduledFailureType != NoFailure) {
    516         error = context->blockedError(request);
    517         return;
    518     }
    519 
    520     handle->createNSURLConnection(
    521         handle->delegate(), // A synchronous request cannot turn into a download, so there is no need to proxy the delegate.
    522         storedCredentials == AllowStoredCredentials,
    523         handle->shouldContentSniff() || (context && context->localFileContentSniffingEnabled()));
    524 
    525     [handle->connection() scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:WebCoreSynchronousLoaderRunLoopMode];
    526     [handle->connection() start];
    527 
    528     while (!client->isDone())
    529         [[NSRunLoop currentRunLoop] runMode:WebCoreSynchronousLoaderRunLoopMode beforeDate:[NSDate distantFuture]];
    530 
    531     result = client->data();
    532     nsURLResponse = client->response();
    533     nsError = client->error();
    534 
    535     [handle->connection() cancel];
    536 
    537 #else
    538     UNUSED_PARAM(storedCredentials);
    539     UNUSED_PARAM(context);
    540     NSURLRequest *firstRequest = request.nsURLRequest();
    541 
    542     if (shouldRelaxThirdPartyCookiePolicy([firstRequest URL])) {
    543         NSMutableURLRequest *mutableRequest = [[firstRequest mutableCopy] autorelease];
    544         [mutableRequest setMainDocumentURL:[mutableRequest URL]];
    545         firstRequest = mutableRequest;
    546     }
    547 
    548     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    549     result = [NSURLConnection sendSynchronousRequest:firstRequest returningResponse:&nsURLResponse error:&nsError];
    550     END_BLOCK_OBJC_EXCEPTIONS;
    551 #endif
    552 
    553     if (!nsError)
    554         response = nsURLResponse;
    555     else {
    556         response = ResourceResponse(request.url(), String(), 0, String(), String());
    557         if ([nsError domain] == NSURLErrorDomain)
    558             switch ([nsError code]) {
    559                 case NSURLErrorUserCancelledAuthentication:
    560                     // FIXME: we should really return the actual HTTP response, but sendSynchronousRequest doesn't provide us with one.
    561                     response.setHTTPStatusCode(401);
    562                     break;
    563                 default:
    564                     response.setHTTPStatusCode([nsError code]);
    565             }
    566         else
    567             response.setHTTPStatusCode(404);
    568     }
    569 
    570     data.resize([result length]);
    571     memcpy(data.data(), [result bytes], [result length]);
    572 
    573     error = nsError;
    574 }
    575 
    576 void ResourceHandle::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
    577 {
    578     const KURL& url = request.url();
    579     d->m_user = url.user();
    580     d->m_pass = url.pass();
    581     d->m_lastHTTPMethod = request.httpMethod();
    582     request.removeCredentials();
    583     if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url()))
    584         request.clearHTTPAuthorization();
    585 
    586 #if USE(CFURLSTORAGESESSIONS)
    587     if (CFURLStorageSessionRef storageSession = privateBrowsingStorageSession())
    588         request.setStorageSession(storageSession);
    589 #endif
    590 
    591     client()->willSendRequest(this, request, redirectResponse);
    592 }
    593 
    594 bool ResourceHandle::shouldUseCredentialStorage()
    595 {
    596     if (client())
    597         return client()->shouldUseCredentialStorage(this);
    598 
    599     return false;
    600 }
    601 
    602 void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
    603 {
    604     ASSERT(!d->m_currentMacChallenge);
    605     ASSERT(d->m_currentWebChallenge.isNull());
    606     // Since NSURLConnection networking relies on keeping a reference to the original NSURLAuthenticationChallenge,
    607     // we make sure that is actually present
    608     ASSERT(challenge.nsURLAuthenticationChallenge());
    609 
    610     if (!d->m_user.isNull() && !d->m_pass.isNull()) {
    611         NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:d->m_user
    612                                                                    password:d->m_pass
    613                                                                 persistence:NSURLCredentialPersistenceForSession];
    614         d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
    615         d->m_currentWebChallenge = challenge;
    616         receivedCredential(challenge, core(credential));
    617         [credential release];
    618         // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
    619         d->m_user = String();
    620         d->m_pass = String();
    621         return;
    622     }
    623 
    624 #ifndef BUILDING_ON_TIGER
    625     if (!client() || client()->shouldUseCredentialStorage(this)) {
    626         if (!d->m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
    627             // The stored credential wasn't accepted, stop using it.
    628             // There is a race condition here, since a different credential might have already been stored by another ResourceHandle,
    629             // but the observable effect should be very minor, if any.
    630             CredentialStorage::remove(challenge.protectionSpace());
    631         }
    632 
    633         if (!challenge.previousFailureCount()) {
    634             Credential credential = CredentialStorage::get(challenge.protectionSpace());
    635             if (!credential.isEmpty() && credential != d->m_initialCredential) {
    636                 ASSERT(credential.persistence() == CredentialPersistenceNone);
    637                 if (challenge.failureResponse().httpStatusCode() == 401) {
    638                     // Store the credential back, possibly adding it as a default for this directory.
    639                     CredentialStorage::set(credential, challenge.protectionSpace(), firstRequest().url());
    640                 }
    641                 [challenge.sender() useCredential:mac(credential) forAuthenticationChallenge:mac(challenge)];
    642                 return;
    643             }
    644         }
    645     }
    646 #endif
    647 
    648     d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
    649     d->m_currentWebChallenge = core(d->m_currentMacChallenge);
    650     d->m_currentWebChallenge.setAuthenticationClient(this);
    651 
    652     if (client())
    653         client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge);
    654 }
    655 
    656 void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
    657 {
    658     ASSERT(d->m_currentMacChallenge);
    659     ASSERT(d->m_currentMacChallenge == challenge.nsURLAuthenticationChallenge());
    660     ASSERT(!d->m_currentWebChallenge.isNull());
    661 
    662     if (client())
    663         client()->didCancelAuthenticationChallenge(this, challenge);
    664 }
    665 
    666 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
    667 bool ResourceHandle::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
    668 {
    669     if (client())
    670         return client()->canAuthenticateAgainstProtectionSpace(this, protectionSpace);
    671 
    672     return false;
    673 }
    674 #endif
    675 
    676 void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
    677 {
    678     ASSERT(!challenge.isNull());
    679     if (challenge != d->m_currentWebChallenge)
    680         return;
    681 
    682     // FIXME: Support empty credentials. Currently, an empty credential cannot be stored in WebCore credential storage, as that's empty value for its map.
    683     if (credential.isEmpty()) {
    684         receivedRequestToContinueWithoutCredential(challenge);
    685         return;
    686     }
    687 
    688 #ifdef BUILDING_ON_TIGER
    689     if (credential.persistence() == CredentialPersistenceNone) {
    690         // NSURLCredentialPersistenceNone doesn't work on Tiger, so we have to use session persistence.
    691         Credential webCredential(credential.user(), credential.password(), CredentialPersistenceForSession);
    692         [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge];
    693     } else
    694 #else
    695     if (credential.persistence() == CredentialPersistenceForSession && (!d->m_needsSiteSpecificQuirks || ![[[mac(challenge) protectionSpace] host] isEqualToString:@"gallery.me.com"])) {
    696         // Manage per-session credentials internally, because once NSURLCredentialPersistenceForSession is used, there is no way
    697         // to ignore it for a particular request (short of removing it altogether).
    698         // <rdar://problem/6867598> gallery.me.com is temporarily whitelisted, so that QuickTime plug-in could see the credentials.
    699         Credential webCredential(credential, CredentialPersistenceNone);
    700         KURL urlToStore;
    701         if (challenge.failureResponse().httpStatusCode() == 401)
    702             urlToStore = firstRequest().url();
    703         CredentialStorage::set(webCredential, core([d->m_currentMacChallenge protectionSpace]), urlToStore);
    704         [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge];
    705     } else
    706 #endif
    707         [[d->m_currentMacChallenge sender] useCredential:mac(credential) forAuthenticationChallenge:d->m_currentMacChallenge];
    708 
    709     clearAuthentication();
    710 }
    711 
    712 void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)
    713 {
    714     ASSERT(!challenge.isNull());
    715     if (challenge != d->m_currentWebChallenge)
    716         return;
    717 
    718     [[d->m_currentMacChallenge sender] continueWithoutCredentialForAuthenticationChallenge:d->m_currentMacChallenge];
    719 
    720     clearAuthentication();
    721 }
    722 
    723 void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge)
    724 {
    725     if (challenge != d->m_currentWebChallenge)
    726         return;
    727 
    728     if (client())
    729         client()->receivedCancellation(this, challenge);
    730 }
    731 
    732 #if USE(CFURLSTORAGESESSIONS)
    733 
    734 RetainPtr<CFURLStorageSessionRef> ResourceHandle::createPrivateBrowsingStorageSession(CFStringRef identifier)
    735 {
    736     return RetainPtr<CFURLStorageSessionRef>(AdoptCF, wkCreatePrivateStorageSession(identifier));
    737 }
    738 
    739 String ResourceHandle::privateBrowsingStorageSessionIdentifierDefaultBase()
    740 {
    741     return String([[NSBundle mainBundle] bundleIdentifier]);
    742 }
    743 
    744 #endif
    745 
    746 } // namespace WebCore
    747 
    748 @implementation WebCoreResourceHandleAsDelegate
    749 
    750 - (id)initWithHandle:(ResourceHandle*)handle
    751 {
    752     self = [self init];
    753     if (!self)
    754         return nil;
    755     m_handle = handle;
    756     return self;
    757 }
    758 
    759 - (void)detachHandle
    760 {
    761     m_handle = 0;
    762 }
    763 
    764 - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
    765 {
    766     UNUSED_PARAM(connection);
    767 
    768     // the willSendRequest call may cancel this load, in which case self could be deallocated
    769     RetainPtr<WebCoreResourceHandleAsDelegate> protect(self);
    770 
    771     if (!m_handle || !m_handle->client())
    772         return nil;
    773 
    774     // See <rdar://problem/5380697> .  This is a workaround for a behavior change in CFNetwork where willSendRequest gets called more often.
    775     if (!redirectResponse)
    776         return newRequest;
    777 
    778 #if !LOG_DISABLED
    779     if ([redirectResponse isKindOfClass:[NSHTTPURLResponse class]])
    780         LOG(Network, "Handle %p delegate connection:%p willSendRequest:%@ redirectResponse:%d, Location:<%@>", m_handle, connection, [newRequest description], static_cast<int>([(id)redirectResponse statusCode]), [[(id)redirectResponse allHeaderFields] objectForKey:@"Location"]);
    781     else
    782         LOG(Network, "Handle %p delegate connection:%p willSendRequest:%@ redirectResponse:non-HTTP", m_handle, connection, [newRequest description]);
    783 #endif
    784 
    785     if ([redirectResponse isKindOfClass:[NSHTTPURLResponse class]] && [(NSHTTPURLResponse *)redirectResponse statusCode] == 307) {
    786         String lastHTTPMethod = m_handle->lastHTTPMethod();
    787         if (!equalIgnoringCase(lastHTTPMethod, String([newRequest HTTPMethod]))) {
    788             NSMutableURLRequest *mutableRequest = [newRequest mutableCopy];
    789             [mutableRequest setHTTPMethod:lastHTTPMethod];
    790 
    791             FormData* body = m_handle->firstRequest().httpBody();
    792             if (!equalIgnoringCase(lastHTTPMethod, "GET") && body && !body->isEmpty())
    793                 WebCore::setHTTPBody(mutableRequest, body);
    794 
    795             String originalContentType = m_handle->firstRequest().httpContentType();
    796             if (!originalContentType.isEmpty())
    797                 [mutableRequest setValue:originalContentType forHTTPHeaderField:@"Content-Type"];
    798 
    799             newRequest = [mutableRequest autorelease];
    800         }
    801     }
    802 
    803     CallbackGuard guard;
    804     ResourceRequest request = newRequest;
    805 
    806     // Should not set Referer after a redirect from a secure resource to non-secure one.
    807     if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https"))
    808         request.clearHTTPReferrer();
    809 
    810     m_handle->willSendRequest(request, redirectResponse);
    811 
    812     if (!ResourceHandle::didSendBodyDataDelegateExists()) {
    813         // The client may change the request's body stream, in which case we have to re-associate
    814         // the handle with the new stream so upload progress callbacks continue to work correctly.
    815         NSInputStream* oldBodyStream = [newRequest HTTPBodyStream];
    816         NSInputStream* newBodyStream = [request.nsURLRequest() HTTPBodyStream];
    817         if (oldBodyStream != newBodyStream) {
    818             disassociateStreamWithResourceHandle(oldBodyStream);
    819             associateStreamWithResourceHandle(newBodyStream, m_handle);
    820         }
    821     }
    822 
    823     return request.nsURLRequest();
    824 }
    825 
    826 - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
    827 {
    828     UNUSED_PARAM(connection);
    829 
    830     LOG(Network, "Handle %p delegate connectionShouldUseCredentialStorage:%p", m_handle, connection);
    831 
    832     if (!m_handle)
    833         return NO;
    834 
    835     CallbackGuard guard;
    836     return m_handle->shouldUseCredentialStorage();
    837 }
    838 
    839 - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    840 {
    841     UNUSED_PARAM(connection);
    842 
    843     LOG(Network, "Handle %p delegate connection:%p didReceiveAuthenticationChallenge:%p", m_handle, connection, challenge);
    844 
    845     if (!m_handle)
    846         return;
    847     CallbackGuard guard;
    848     m_handle->didReceiveAuthenticationChallenge(core(challenge));
    849 }
    850 
    851 - (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    852 {
    853     UNUSED_PARAM(connection);
    854 
    855     LOG(Network, "Handle %p delegate connection:%p didCancelAuthenticationChallenge:%p", m_handle, connection, challenge);
    856 
    857     if (!m_handle)
    858         return;
    859     CallbackGuard guard;
    860     m_handle->didCancelAuthenticationChallenge(core(challenge));
    861 }
    862 
    863 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
    864 - (BOOL)connection:(NSURLConnection *)unusedConnection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
    865 {
    866     UNUSED_PARAM(unusedConnection);
    867 
    868     if (!m_handle)
    869         return NO;
    870 
    871     CallbackGuard guard;
    872     return m_handle->canAuthenticateAgainstProtectionSpace(core(protectionSpace));
    873 }
    874 #endif
    875 
    876 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)r
    877 {
    878     UNUSED_PARAM(connection);
    879 
    880     LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d, reported MIMEType '%s')", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0, [[r MIMEType] UTF8String]);
    881 
    882     if (!m_handle || !m_handle->client())
    883         return;
    884     CallbackGuard guard;
    885 
    886     // Avoid MIME type sniffing if the response comes back as 304 Not Modified.
    887     int statusCode = [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0;
    888     if (statusCode != 304)
    889         adjustMIMETypeIfNecessary([r _CFURLResponse]);
    890 
    891     if ([m_handle->firstRequest().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"])
    892         [r _setMIMEType:@"text/html"];
    893 
    894 #if ENABLE(WML)
    895     const KURL& url = [r URL];
    896     if (url.isLocalFile()) {
    897         // FIXME: Workaround for <rdar://problem/6917571>: The WML file extension ".wml" is not mapped to
    898         // the right MIME type, work around that CFNetwork problem, to unbreak WML support for local files.
    899         const String& path = url.path();
    900 
    901         DEFINE_STATIC_LOCAL(const String, wmlExt, (".wml"));
    902         if (path.endsWith(wmlExt, false)) {
    903             static NSString* defaultMIMETypeString = [(NSString*) defaultMIMEType() retain];
    904             if ([[r MIMEType] isEqualToString:defaultMIMETypeString])
    905                 [r _setMIMEType:@"text/vnd.wap.wml"];
    906         }
    907     }
    908 #endif
    909 
    910     m_handle->client()->didReceiveResponse(m_handle, r);
    911 }
    912 
    913 #if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK)
    914 - (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray
    915 {
    916     UNUSED_PARAM(connection);
    917     LOG(Network, "Handle %p delegate connection:%p didReceiveDataArray:%p arraySize:%d", m_handle, connection, dataArray, [dataArray count]);
    918 
    919     if (!dataArray)
    920         return;
    921 
    922     if (!m_handle || !m_handle->client())
    923         return;
    924 
    925     if (m_handle->client()->supportsDataArray())
    926         m_handle->client()->didReceiveDataArray(m_handle, reinterpret_cast<CFArrayRef>(dataArray));
    927     else {
    928         for (NSData *data in dataArray)
    929             m_handle->client()->didReceiveData(m_handle, static_cast<const char*>([data bytes]), [data length], static_cast<int>([data length]));
    930     }
    931     return;
    932 }
    933 #endif
    934 
    935 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
    936 {
    937     UNUSED_PARAM(connection);
    938     UNUSED_PARAM(lengthReceived);
    939 
    940     LOG(Network, "Handle %p delegate connection:%p didReceiveData:%p lengthReceived:%lld", m_handle, connection, data, lengthReceived);
    941 
    942     if (!m_handle || !m_handle->client())
    943         return;
    944     // FIXME: If we get more than 2B bytes in a single chunk, this code won't do the right thing.
    945     // However, with today's computers and networking speeds, this won't happen in practice.
    946     // Could be an issue with a giant local file.
    947     CallbackGuard guard;
    948     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793
    949     // -1 means we do not provide any data about transfer size to inspector so it would use
    950     // Content-Length headers or content size to show transfer size.
    951     m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], -1);
    952 }
    953 
    954 - (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data
    955 {
    956     UNUSED_PARAM(connection);
    957 
    958     LOG(Network, "Handle %p delegate connection:%p willStopBufferingData:%p", m_handle, connection, data);
    959 
    960     if (!m_handle || !m_handle->client())
    961         return;
    962     // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
    963     // However, with today's computers and networking speeds, this won't happen in practice.
    964     // Could be an issue with a giant local file.
    965     CallbackGuard guard;
    966     m_handle->client()->willStopBufferingData(m_handle, (const char*)[data bytes], static_cast<int>([data length]));
    967 }
    968 
    969 - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
    970 {
    971     UNUSED_PARAM(connection);
    972     UNUSED_PARAM(bytesWritten);
    973 
    974     LOG(Network, "Handle %p delegate connection:%p didSendBodyData:%d totalBytesWritten:%d totalBytesExpectedToWrite:%d", m_handle, connection, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
    975 
    976     if (!m_handle || !m_handle->client())
    977         return;
    978     CallbackGuard guard;
    979     m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite);
    980 }
    981 
    982 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    983 {
    984     UNUSED_PARAM(connection);
    985 
    986     LOG(Network, "Handle %p delegate connectionDidFinishLoading:%p", m_handle, connection);
    987 
    988     if (!m_handle || !m_handle->client())
    989         return;
    990     CallbackGuard guard;
    991 
    992     if (!ResourceHandle::didSendBodyDataDelegateExists())
    993         disassociateStreamWithResourceHandle([m_handle->firstRequest().nsURLRequest() HTTPBodyStream]);
    994 
    995     m_handle->client()->didFinishLoading(m_handle, 0);
    996 }
    997 
    998 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    999 {
   1000     UNUSED_PARAM(connection);
   1001 
   1002     LOG(Network, "Handle %p delegate connection:%p didFailWithError:%@", m_handle, connection, error);
   1003 
   1004     if (!m_handle || !m_handle->client())
   1005         return;
   1006     CallbackGuard guard;
   1007 
   1008     if (!ResourceHandle::didSendBodyDataDelegateExists())
   1009         disassociateStreamWithResourceHandle([m_handle->firstRequest().nsURLRequest() HTTPBodyStream]);
   1010 
   1011     m_handle->client()->didFail(m_handle, error);
   1012 }
   1013 
   1014 #ifdef BUILDING_ON_TIGER
   1015 - (void)_callConnectionWillCacheResponseWithInfo:(NSMutableDictionary *)info
   1016 {
   1017     NSURLConnection *connection = [info objectForKey:@"connection"];
   1018     NSCachedURLResponse *cachedResponse = [info objectForKey:@"cachedResponse"];
   1019     NSCachedURLResponse *result = [self connection:connection willCacheResponse:cachedResponse];
   1020     if (result)
   1021         [info setObject:result forKey:@"result"];
   1022 }
   1023 #endif
   1024 
   1025 - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
   1026 {
   1027     LOG(Network, "Handle %p delegate connection:%p willCacheResponse:%p", m_handle, connection, cachedResponse);
   1028 
   1029 #ifdef BUILDING_ON_TIGER
   1030     // On Tiger CFURLConnection can sometimes call the connection:willCacheResponse: delegate method on
   1031     // a secondary thread instead of the main thread. If this happens perform the work on the main thread.
   1032     if (!pthread_main_np()) {
   1033         NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
   1034         if (connection)
   1035             [info setObject:connection forKey:@"connection"];
   1036         if (cachedResponse)
   1037             [info setObject:cachedResponse forKey:@"cachedResponse"];
   1038 
   1039         // Include synchronous url connection's mode as an acceptable run loopmode
   1040         // <rdar://problem/5511842>
   1041         NSArray *modes = [[NSArray alloc] initWithObjects:(NSString *)kCFRunLoopCommonModes, @"NSSynchronousURLConnection_PrivateMode", nil];
   1042         [self performSelectorOnMainThread:@selector(_callConnectionWillCacheResponseWithInfo:) withObject:info waitUntilDone:YES modes:modes];
   1043         [modes release];
   1044 
   1045         NSCachedURLResponse *result = [[info valueForKey:@"result"] retain];
   1046         [info release];
   1047 
   1048         return [result autorelease];
   1049     }
   1050 #else
   1051     UNUSED_PARAM(connection);
   1052 #endif
   1053 
   1054 #ifndef NDEBUG
   1055     if (isInitializingConnection)
   1056         LOG_ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (4067625)");
   1057 #endif
   1058 
   1059     if (!m_handle || !m_handle->client())
   1060         return nil;
   1061 
   1062     CallbackGuard guard;
   1063 
   1064     NSCachedURLResponse *newResponse = m_handle->client()->willCacheResponse(m_handle, cachedResponse);
   1065     if (newResponse != cachedResponse)
   1066         return newResponse;
   1067 
   1068     CacheStoragePolicy policy = static_cast<CacheStoragePolicy>([newResponse storagePolicy]);
   1069 
   1070     m_handle->client()->willCacheResponse(m_handle, policy);
   1071 
   1072     if (static_cast<NSURLCacheStoragePolicy>(policy) != [newResponse storagePolicy])
   1073         newResponse = [[[NSCachedURLResponse alloc] initWithResponse:[newResponse response]
   1074                                                                 data:[newResponse data]
   1075                                                             userInfo:[newResponse userInfo]
   1076                                                        storagePolicy:static_cast<NSURLCacheStoragePolicy>(policy)] autorelease];
   1077 
   1078     return newResponse;
   1079 }
   1080 
   1081 @end
   1082 
   1083 #ifndef BUILDING_ON_TIGER
   1084 
   1085 WebCoreSynchronousLoaderClient::~WebCoreSynchronousLoaderClient()
   1086 {
   1087     [m_response release];
   1088     [m_data release];
   1089     [m_error release];
   1090 }
   1091 
   1092 void WebCoreSynchronousLoaderClient::willSendRequest(ResourceHandle* handle, ResourceRequest& request, const ResourceResponse& /*redirectResponse*/)
   1093 {
   1094     // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
   1095     if (!protocolHostAndPortAreEqual(handle->firstRequest().url(), request.url())) {
   1096         ASSERT(!m_error);
   1097         m_error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil];
   1098         m_isDone = true;
   1099         request = 0;
   1100         return;
   1101     }
   1102 }
   1103 
   1104 bool WebCoreSynchronousLoaderClient::shouldUseCredentialStorage(ResourceHandle*)
   1105 {
   1106     // FIXME: We should ask FrameLoaderClient whether using credential storage is globally forbidden.
   1107     return m_allowStoredCredentials;
   1108 }
   1109 
   1110 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
   1111 bool WebCoreSynchronousLoaderClient::canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&)
   1112 {
   1113     // FIXME: We should ask FrameLoaderClient.
   1114     return true;
   1115 }
   1116 #endif
   1117 
   1118 void WebCoreSynchronousLoaderClient::didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge)
   1119 {
   1120     // FIXME: The user should be asked for credentials, as in async case.
   1121     [challenge.sender() continueWithoutCredentialForAuthenticationChallenge:challenge.nsURLAuthenticationChallenge()];
   1122 }
   1123 
   1124 void WebCoreSynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
   1125 {
   1126     [m_response release];
   1127     m_response = [response.nsURLResponse() copy];
   1128 }
   1129 
   1130 void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*encodedDataLength*/)
   1131 {
   1132     if (!m_data)
   1133         m_data = [[NSMutableData alloc] init];
   1134     [m_data appendBytes:data length:length];
   1135 }
   1136 
   1137 void WebCoreSynchronousLoaderClient::didFinishLoading(ResourceHandle*, double)
   1138 {
   1139     m_isDone = true;
   1140 }
   1141 
   1142 void WebCoreSynchronousLoaderClient::didFail(ResourceHandle*, const ResourceError& error)
   1143 {
   1144     ASSERT(!m_error);
   1145 
   1146     m_error = [error copy];
   1147     m_isDone = true;
   1148 }
   1149 
   1150 #endif // BUILDING_ON_TIGER
   1151 
   1152 #endif // !USE(CFNETWORK)
   1153