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 58typedef int NSInteger; 59#endif 60 61using 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 91class WebCoreSynchronousLoaderClient : public ResourceHandleClient { 92public: 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 106private: 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 134static NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode"; 135 136#endif 137 138namespace WebCore { 139 140#ifdef BUILDING_ON_TIGER 141static unsigned inNSURLConnectionCallback; 142#endif 143 144#ifndef NDEBUG 145static bool isInitializingConnection; 146#endif 147 148class CallbackGuard { 149public: 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 166static String encodeBasicAuthorization(const String& user, const String& password) 167{ 168 return base64Encode((user + ":" + password).utf8()); 169} 170#endif 171 172ResourceHandleInternal::~ResourceHandleInternal() 173{ 174} 175 176ResourceHandle::~ResourceHandle() 177{ 178 releaseDelegate(); 179 d->m_currentWebChallenge.setAuthenticationClient(0); 180 181 LOG(Network, "Handle %p destroyed", this); 182} 183 184static const double MaxFoundationVersionWithoutdidSendBodyDataDelegate = 677.21; 185bool ResourceHandle::didSendBodyDataDelegateExists() 186{ 187 return NSFoundationVersionNumber > MaxFoundationVersionWithoutdidSendBodyDataDelegate; 188} 189 190static 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 219void 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 293bool 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 370void 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 383void ResourceHandle::platformSetDefersLoading(bool defers) 384{ 385 if (d->m_connection) 386 wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers); 387} 388 389void 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 405void 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 415WebCoreResourceHandleAsDelegate *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 425void 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 435bool ResourceHandle::supportsBufferedData() 436{ 437 static bool supportsBufferedData = [NSURLConnection instancesRespondToSelector:@selector(_bufferedData)]; 438 return supportsBufferedData; 439} 440 441PassRefPtr<SharedBuffer> ResourceHandle::bufferedData() 442{ 443 if (ResourceHandle::supportsBufferedData()) 444 return SharedBuffer::wrapNSData([d->m_connection.get() _bufferedData]); 445 446 return 0; 447} 448 449id 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 457NSURLConnection *ResourceHandle::connection() const 458{ 459 return d->m_connection.get(); 460} 461 462bool 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 474bool 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 493void 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 576void 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 594bool ResourceHandle::shouldUseCredentialStorage() 595{ 596 if (client()) 597 return client()->shouldUseCredentialStorage(this); 598 599 return false; 600} 601 602void 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 656void 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) 667bool ResourceHandle::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace) 668{ 669 if (client()) 670 return client()->canAuthenticateAgainstProtectionSpace(this, protectionSpace); 671 672 return false; 673} 674#endif 675 676void 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 712void 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 723void 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 734RetainPtr<CFURLStorageSessionRef> ResourceHandle::createPrivateBrowsingStorageSession(CFStringRef identifier) 735{ 736 return RetainPtr<CFURLStorageSessionRef>(AdoptCF, wkCreatePrivateStorageSession(identifier)); 737} 738 739String 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 1085WebCoreSynchronousLoaderClient::~WebCoreSynchronousLoaderClient() 1086{ 1087 [m_response release]; 1088 [m_data release]; 1089 [m_error release]; 1090} 1091 1092void 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 1104bool 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) 1111bool WebCoreSynchronousLoaderClient::canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&) 1112{ 1113 // FIXME: We should ask FrameLoaderClient. 1114 return true; 1115} 1116#endif 1117 1118void 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 1124void WebCoreSynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) 1125{ 1126 [m_response release]; 1127 m_response = [response.nsURLResponse() copy]; 1128} 1129 1130void 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 1137void WebCoreSynchronousLoaderClient::didFinishLoading(ResourceHandle*, double) 1138{ 1139 m_isDone = true; 1140} 1141 1142void 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