Fix the Tiger build.
[WebKit-https.git] / WebCore / platform / network / mac / ResourceHandleMac.mm
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 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 "ResourceHandle.h"
28 #import "ResourceHandleInternal.h"
29
30 #import "AuthenticationMac.h"
31 #import "BlockExceptions.h"
32 #import "DocLoader.h"
33 #import "Frame.h"
34 #import "FrameLoader.h"
35 #import "Page.h"
36 #import "ResourceError.h"
37 #import "ResourceResponse.h"
38 #import "SchedulePair.h"
39 #import "SharedBuffer.h"
40 #import "SubresourceLoader.h"
41 #import "AuthenticationChallenge.h"
42 #import "WebCoreSystemInterface.h"
43
44 using namespace WebCore;
45
46 @interface WebCoreResourceHandleAsDelegate : NSObject <NSURLAuthenticationChallengeSender>
47 {
48     ResourceHandle* m_handle;
49 #ifndef BUILDING_ON_TIGER
50     NSURL *m_url;
51 #endif
52 }
53 - (id)initWithHandle:(ResourceHandle*)handle;
54 - (void)detachHandle;
55 @end
56
57 @interface NSURLConnection (NSURLConnectionTigerPrivate)
58 - (NSData *)_bufferedData;
59 @end
60
61 @interface NSURLProtocol (WebFoundationSecret) 
62 + (void)_removePropertyForKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
63 @end
64
65 #ifndef BUILDING_ON_TIGER
66 @interface WebCoreSynchronousLoader : NSObject {
67     NSURL *m_url;
68     NSURLResponse *m_response;
69     NSMutableData *m_data;
70     NSError *m_error;
71     BOOL m_isDone;
72 }
73 + (NSData *)loadRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;
74 @end
75
76 static NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode";
77 #endif
78
79 namespace WebCore {
80
81 #ifdef BUILDING_ON_TIGER
82 static unsigned inNSURLConnectionCallback;
83 #endif
84
85 #ifndef NDEBUG
86 static bool isInitializingConnection;
87 #endif
88     
89 class CallbackGuard {
90 public:
91     CallbackGuard()
92     {
93 #ifdef BUILDING_ON_TIGER
94         ++inNSURLConnectionCallback;
95 #endif
96     }
97     ~CallbackGuard()
98     {
99 #ifdef BUILDING_ON_TIGER
100         ASSERT(inNSURLConnectionCallback > 0);
101         --inNSURLConnectionCallback;
102 #endif
103     }
104 };
105
106 ResourceHandleInternal::~ResourceHandleInternal()
107 {
108 }
109
110 ResourceHandle::~ResourceHandle()
111 {
112     releaseDelegate();
113 }
114
115 bool ResourceHandle::start(Frame* frame)
116 {
117     if (!frame)
118         return false;
119
120     BEGIN_BLOCK_OBJC_EXCEPTIONS;
121
122     // If we are no longer attached to a Page, this must be an attempted load from an
123     // onUnload handler, so let's just block it.
124     Page* page = frame->page();
125     if (!page)
126         return false;
127
128 #ifndef NDEBUG
129     isInitializingConnection = YES;
130 #endif
131     id delegate;
132     
133     if (d->m_mightDownloadFromHandle) {
134         ASSERT(!d->m_proxy);
135         d->m_proxy = wkCreateNSURLConnectionDelegateProxy();
136         [d->m_proxy.get() setDelegate:ResourceHandle::delegate()];
137         [d->m_proxy.get() release];
138         
139         delegate = d->m_proxy.get();
140     } else 
141         delegate = ResourceHandle::delegate();
142     
143
144     NSURLConnection *connection;
145     
146     if (d->m_shouldContentSniff) 
147 #ifdef BUILDING_ON_TIGER
148         connection = [[NSURLConnection alloc] initWithRequest:d->m_request.nsURLRequest() delegate:delegate];
149 #else
150         connection = [[NSURLConnection alloc] initWithRequest:d->m_request.nsURLRequest() delegate:delegate startImmediately:NO];
151 #endif
152     else {
153         NSMutableURLRequest *request = [d->m_request.nsURLRequest() mutableCopy];
154         wkSetNSURLRequestShouldContentSniff(request, NO);
155 #ifdef BUILDING_ON_TIGER
156         connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate];
157 #else
158         connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
159 #endif
160         [request release];
161     }
162
163 #ifndef BUILDING_ON_TIGER
164     bool scheduled = false;
165     if (SchedulePairHashSet* scheduledPairs = page->scheduledRunLoopPairs()) {
166         SchedulePairHashSet::iterator end = scheduledPairs->end();
167         for (SchedulePairHashSet::iterator it = scheduledPairs->begin(); it != end; ++it) {
168             if (NSRunLoop *runLoop = (*it)->nsRunLoop()) {
169                 [connection scheduleInRunLoop:runLoop forMode:(NSString *)(*it)->mode()];
170                 scheduled = true;
171             }
172         }
173     }
174
175     // Start the connection if we did schedule with at least one runloop.
176     // We can't start the connection until we have one runloop scheduled.
177     if (scheduled)
178         [connection start];
179     else
180         d->m_startWhenScheduled = true;
181 #endif
182
183 #ifndef NDEBUG
184     isInitializingConnection = NO;
185 #endif
186     d->m_connection = connection;
187     [connection release];
188     if (d->m_defersLoading)
189         wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), YES);
190
191     if (d->m_connection)
192         return true;
193
194     END_BLOCK_OBJC_EXCEPTIONS;
195
196     return false;
197 }
198
199 void ResourceHandle::cancel()
200 {
201     [d->m_connection.get() cancel];
202 }
203
204 void ResourceHandle::setDefersLoading(bool defers)
205 {
206     d->m_defersLoading = defers;
207     wkSetNSURLConnectionDefersCallbacks(d->m_connection.get(), defers);
208 }
209
210 void ResourceHandle::schedule(SchedulePair* pair)
211 {
212 #ifndef BUILDING_ON_TIGER
213     NSRunLoop *runLoop = pair->nsRunLoop();
214     if (!runLoop)
215         return;
216     [d->m_connection.get() scheduleInRunLoop:runLoop forMode:(NSString *)pair->mode()];
217     if (d->m_startWhenScheduled) {
218         [d->m_connection.get() start];
219         d->m_startWhenScheduled = false;
220     }
221 #endif
222 }
223
224 void ResourceHandle::unschedule(SchedulePair* pair)
225 {
226 #ifndef BUILDING_ON_TIGER
227     if (NSRunLoop *runLoop = pair->nsRunLoop())
228         [d->m_connection.get() unscheduleFromRunLoop:runLoop forMode:(NSString *)pair->mode()];
229 #endif
230 }
231
232 WebCoreResourceHandleAsDelegate *ResourceHandle::delegate()
233 {
234     if (!d->m_delegate) {
235         WebCoreResourceHandleAsDelegate *delegate = [[WebCoreResourceHandleAsDelegate alloc] initWithHandle:this];
236         d->m_delegate = delegate;
237         [delegate release];
238     }
239     return d->m_delegate.get();
240 }
241
242 void ResourceHandle::releaseDelegate()
243 {
244     if (!d->m_delegate)
245         return;
246     if (d->m_proxy)
247         [d->m_proxy.get() setDelegate:nil];
248     [d->m_delegate.get() detachHandle];
249     d->m_delegate = nil;
250 }
251
252 bool ResourceHandle::supportsBufferedData()
253 {
254     static bool supportsBufferedData = [NSURLConnection instancesRespondToSelector:@selector(_bufferedData)];
255     return supportsBufferedData;
256 }
257
258 PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
259 {
260     if (ResourceHandle::supportsBufferedData())
261         return SharedBuffer::wrapNSData([d->m_connection.get() _bufferedData]);
262
263     return 0;
264 }
265
266 id ResourceHandle::releaseProxy()
267 {
268     id proxy = [[d->m_proxy.get() retain] autorelease];
269     d->m_proxy = nil;
270     [proxy setDelegate:nil];
271     return proxy;
272 }
273
274 NSURLConnection *ResourceHandle::connection() const
275 {
276     return d->m_connection.get();
277 }
278
279 bool ResourceHandle::loadsBlocked()
280 {
281 #ifndef BUILDING_ON_TIGER
282     return false;
283 #else
284     // On Tiger, if we're in an NSURLConnection callback, that blocks all other NSURLConnection callbacks.
285     // On Leopard and newer, it blocks only callbacks on that same NSURLConnection object, which is not
286     // a problem in practice.
287     return inNSURLConnectionCallback != 0;
288 #endif
289 }
290
291 bool ResourceHandle::willLoadFromCache(ResourceRequest& request)
292 {
293     request.setCachePolicy(ReturnCacheDataDontLoad);
294     NSURLResponse *nsURLResponse = nil;
295     BEGIN_BLOCK_OBJC_EXCEPTIONS;
296     
297    [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:nil];
298     
299     END_BLOCK_OBJC_EXCEPTIONS;
300     
301     return nsURLResponse;
302 }
303
304 void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame*)
305 {
306     NSError *nsError = nil;
307     
308     NSURLResponse *nsURLResponse = nil;
309     NSData *result = nil;
310
311     ASSERT(!request.isEmpty());
312     
313     BEGIN_BLOCK_OBJC_EXCEPTIONS;
314     
315 #ifndef BUILDING_ON_TIGER
316     result = [WebCoreSynchronousLoader loadRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:&nsError];
317 #else
318     result = [NSURLConnection sendSynchronousRequest:request.nsURLRequest() returningResponse:&nsURLResponse error:&nsError];
319 #endif
320     END_BLOCK_OBJC_EXCEPTIONS;
321
322     if (nsError == nil)
323         response = nsURLResponse;
324     else {
325         response = ResourceResponse(request.url(), String(), 0, String(), String());
326         if ([nsError domain] == NSURLErrorDomain)
327             switch ([nsError code]) {
328                 case NSURLErrorUserCancelledAuthentication:
329                     // FIXME: we should really return the actual HTTP response, but sendSynchronousRequest doesn't provide us with one.
330                     response.setHTTPStatusCode(401);
331                     break;
332                 default:
333                     response.setHTTPStatusCode([nsError code]);
334             }
335         else
336             response.setHTTPStatusCode(404);
337     }
338     
339     data.resize([result length]);
340     memcpy(data.data(), [result bytes], [result length]);
341     
342     error = nsError;
343 }
344
345 void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
346 {
347     ASSERT(!d->m_currentMacChallenge);
348     ASSERT(d->m_currentWebChallenge.isNull());
349     // Since NSURLConnection networking relies on keeping a reference to the original NSURLAuthenticationChallenge,
350     // we make sure that is actually present
351     ASSERT(challenge.nsURLAuthenticationChallenge());
352         
353     d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge();
354     NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge 
355                                                                                        sender:(id<NSURLAuthenticationChallengeSender>)delegate()];
356     d->m_currentWebChallenge = core(webChallenge);
357     [webChallenge release];
358
359     if (client())
360         client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge);
361 }
362
363 void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
364 {
365     ASSERT(d->m_currentMacChallenge);
366     ASSERT(!d->m_currentWebChallenge.isNull());
367     ASSERT(d->m_currentWebChallenge == challenge);
368
369     if (client())
370         client()->didCancelAuthenticationChallenge(this, d->m_currentWebChallenge);
371 }
372
373 void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
374 {
375     ASSERT(!challenge.isNull());
376     if (challenge != d->m_currentWebChallenge)
377         return;
378
379     [[d->m_currentMacChallenge sender] useCredential:mac(credential) forAuthenticationChallenge:d->m_currentMacChallenge];
380
381     clearAuthentication();
382 }
383
384 void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)
385 {
386     ASSERT(!challenge.isNull());
387     if (challenge != d->m_currentWebChallenge)
388         return;
389
390     [[d->m_currentMacChallenge sender] continueWithoutCredentialForAuthenticationChallenge:d->m_currentMacChallenge];
391
392     clearAuthentication();
393 }
394
395 void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge)
396 {
397     if (challenge != d->m_currentWebChallenge)
398         return;
399
400     if (client())
401         client()->receivedCancellation(this, challenge);
402 }
403
404 } // namespace WebCore
405
406 @implementation WebCoreResourceHandleAsDelegate
407
408 - (id)initWithHandle:(ResourceHandle*)handle
409 {
410     self = [self init];
411     if (!self)
412         return nil;
413     m_handle = handle;
414     return self;
415 }
416
417 #ifndef BUILDING_ON_TIGER
418 - (void)dealloc
419 {
420     [m_url release];
421     [super dealloc];
422 }
423 #endif
424
425 - (void)detachHandle
426 {
427     m_handle = 0;
428 }
429
430 - (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
431 {
432     // the willSendRequest call may cancel this load, in which case self could be deallocated
433     RetainPtr<WebCoreResourceHandleAsDelegate> protect(self);
434
435     if (!m_handle || !m_handle->client())
436         return nil;
437     
438     // See <rdar://problem/5380697> .  This is a workaround for a behavior change in CFNetwork where willSendRequest gets called more often.
439     if (!redirectResponse)
440         return newRequest;
441     
442     CallbackGuard guard;
443     ResourceRequest request = newRequest;
444     m_handle->client()->willSendRequest(m_handle, request, redirectResponse);
445 #ifndef BUILDING_ON_TIGER
446     NSURL *copy = [[request.nsURLRequest() URL] copy];
447     [m_url release];
448     m_url = copy;
449 #endif
450     
451     return request.nsURLRequest();
452 }
453
454 - (void)connection:(NSURLConnection *)con didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
455 {
456 #ifndef BUILDING_ON_TIGER
457     if ([challenge previousFailureCount] == 0) {
458         NSString *user = [m_url user];
459         NSString *password = [m_url password];
460
461         if (user && password) {
462             NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:user
463                                                                      password:password
464                                                                   persistence:NSURLCredentialPersistenceForSession];
465             [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
466             [credential release];
467             return;
468         }
469     }
470 #endif
471     
472     if (!m_handle)
473         return;
474     CallbackGuard guard;
475     m_handle->didReceiveAuthenticationChallenge(core(challenge));
476 }
477
478 - (void)connection:(NSURLConnection *)con didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
479 {
480     if (!m_handle)
481         return;
482     CallbackGuard guard;
483     m_handle->didCancelAuthenticationChallenge(core(challenge));
484 }
485
486 - (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
487 {
488     if (!m_handle || !m_handle->client())
489         return;
490     CallbackGuard guard;
491     m_handle->client()->didReceiveResponse(m_handle, r);
492 }
493
494 - (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
495 {
496     if (!m_handle || !m_handle->client())
497         return;
498     // FIXME: If we get more than 2B bytes in a single chunk, this code won't do the right thing.
499     // However, with today's computers and networking speeds, this won't happen in practice.
500     // Could be an issue with a giant local file.
501     CallbackGuard guard;
502     m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], static_cast<int>(lengthReceived));
503 }
504
505 - (void)connection:(NSURLConnection *)con willStopBufferingData:(NSData *)data
506 {
507     if (!m_handle || !m_handle->client())
508         return;
509     // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
510     // However, with today's computers and networking speeds, this won't happen in practice.
511     // Could be an issue with a giant local file.
512     CallbackGuard guard;
513     m_handle->client()->willStopBufferingData(m_handle, (const char*)[data bytes], static_cast<int>([data length]));
514 }
515
516 - (void)connectionDidFinishLoading:(NSURLConnection *)con
517 {
518     if (!m_handle || !m_handle->client())
519         return;
520     CallbackGuard guard;
521     m_handle->client()->didFinishLoading(m_handle);
522 }
523
524 - (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
525 {
526     if (!m_handle || !m_handle->client())
527         return;
528     CallbackGuard guard;
529     m_handle->client()->didFail(m_handle, error);
530 }
531
532 #ifdef BUILDING_ON_TIGER
533 - (void)_callConnectionWillCacheResponseWithInfo:(NSMutableDictionary *)info
534 {
535     NSURLConnection *connection = [info objectForKey:@"connection"];
536     NSCachedURLResponse *cachedResponse = [info objectForKey:@"cachedResponse"];
537     NSCachedURLResponse *result = [self connection:connection willCacheResponse:cachedResponse];
538     if (result)
539         [info setObject:result forKey:@"result"];
540 }
541 #endif
542
543 - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
544 {
545 #ifdef BUILDING_ON_TIGER
546     // On Tiger CFURLConnection can sometimes call the connection:willCacheResponse: delegate method on
547     // a secondary thread instead of the main thread. If this happens perform the work on the main thread.
548     if (!pthread_main_np()) {
549         NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
550         if (connection)
551             [info setObject:connection forKey:@"connection"];
552         if (cachedResponse)
553             [info setObject:cachedResponse forKey:@"cachedResponse"];
554
555         // Include synchronous url connection's mode as an acceptable run loopmode
556         // <rdar://problem/5511842>
557         NSArray *modes = [[NSArray alloc] initWithObjects:(NSString *)kCFRunLoopCommonModes, @"NSSynchronousURLConnection_PrivateMode", nil];        
558         [self performSelectorOnMainThread:@selector(_callConnectionWillCacheResponseWithInfo:) withObject:info waitUntilDone:YES modes:modes];
559         [modes release];
560
561         NSCachedURLResponse *result = [[info valueForKey:@"result"] retain];
562         [info release];
563
564         return [result autorelease];
565     }
566 #endif
567
568 #ifndef NDEBUG
569     if (isInitializingConnection)
570         LOG_ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (4067625)");
571 #endif
572     if (!m_handle || !m_handle->client())
573         return nil;
574
575     CallbackGuard guard;
576     
577     NSCachedURLResponse *newResponse = m_handle->client()->willCacheResponse(m_handle, cachedResponse);
578     if (newResponse != cachedResponse)
579         return newResponse;
580     
581     CacheStoragePolicy policy = static_cast<CacheStoragePolicy>([newResponse storagePolicy]);
582         
583     m_handle->client()->willCacheResponse(m_handle, policy);
584
585     if (static_cast<NSURLCacheStoragePolicy>(policy) != [newResponse storagePolicy])
586         newResponse = [[[NSCachedURLResponse alloc] initWithResponse:[newResponse response]
587                                                                 data:[newResponse data]
588                                                             userInfo:[newResponse userInfo]
589                                                        storagePolicy:static_cast<NSURLCacheStoragePolicy>(policy)] autorelease];
590
591     return newResponse;
592 }
593
594 - (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
595 {
596     if (!m_handle)
597         return;
598     m_handle->receivedCredential(core(challenge), core(credential));
599 }
600
601 - (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
602 {
603     if (!m_handle)
604         return;
605     m_handle->receivedRequestToContinueWithoutCredential(core(challenge));
606 }
607
608 - (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
609 {
610     if (!m_handle)
611         return;
612     m_handle->receivedCancellation(core(challenge));
613 }
614
615 @end
616
617 #ifndef BUILDING_ON_TIGER
618 @implementation WebCoreSynchronousLoader
619
620 - (BOOL)_isDone
621 {
622     return m_isDone;
623 }
624
625 - (void)dealloc
626 {
627     [m_url release];
628     [m_response release];
629     [m_data release];
630     [m_error release];
631     
632     [super dealloc];
633 }
634
635 - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
636 {
637     NSURL *copy = [[newRequest URL] copy];
638     [m_url release];
639     m_url = copy;
640
641     return newRequest;
642 }
643
644 - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
645 {
646     if ([challenge previousFailureCount] == 0) {
647         NSString *user = [m_url user];
648         NSString *password = [m_url password];
649         
650         if (user && password) {
651             NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:user
652                                                                      password:password
653                                                                   persistence:NSURLCredentialPersistenceForSession];
654             [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
655             [credential release];
656             return;
657         }
658     }
659     
660     [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
661 }
662
663 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
664 {
665     NSURLResponse *r = [response copy];
666     
667     [m_response release];
668     m_response = r;
669 }
670
671 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
672 {
673     if (!m_data)
674         m_data = [[NSMutableData alloc] init];
675     
676     [m_data appendData:data];
677 }
678
679 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
680 {
681     m_isDone = YES;
682 }
683
684 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
685 {
686     ASSERT(!m_error);
687     
688     m_error = [error retain];
689     m_isDone = YES;
690 }
691
692 - (NSData *)_data
693 {
694     return [[m_data retain] autorelease];
695 }
696
697 - (NSURLResponse *)_response
698 {
699     return [[m_response retain] autorelease];
700 }
701
702 - (NSError *)_error
703 {
704     return [[m_error retain] autorelease];
705 }
706
707 + (NSData *)loadRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
708 {
709     WebCoreSynchronousLoader *delegate = [[WebCoreSynchronousLoader alloc] init];
710     
711     NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
712     [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:WebCoreSynchronousLoaderRunLoopMode];
713     [connection start];
714     
715     while (![delegate _isDone])
716         [[NSRunLoop currentRunLoop] runMode:WebCoreSynchronousLoaderRunLoopMode beforeDate:[NSDate distantFuture]];
717
718     NSData *data = [delegate _data];
719     *response = [delegate _response];
720     *error = [delegate _error];
721     
722     [connection cancel];
723     
724     [connection release];
725     [delegate release];
726     
727     return data;
728 }
729
730 @end
731 #endif