Make adjustMIMETypeIfNecessary use CFNetwork directly
[WebKit-https.git] / Source / WebCore / platform / network / mac / ResourceHandleMac.mm
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 /*lengthReceived*/);
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 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
914 {
915     UNUSED_PARAM(connection);
916
917     LOG(Network, "Handle %p delegate connection:%p didReceiveData:%p lengthReceived:%lld", m_handle, connection, data, lengthReceived);
918
919     if (!m_handle || !m_handle->client())
920         return;
921     // FIXME: If we get more than 2B bytes in a single chunk, this code won't do the right thing.
922     // However, with today's computers and networking speeds, this won't happen in practice.
923     // Could be an issue with a giant local file.
924     CallbackGuard guard;
925     m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], static_cast<int>(lengthReceived));
926 }
927
928 - (void)connection:(NSURLConnection *)connection willStopBufferingData:(NSData *)data
929 {
930     UNUSED_PARAM(connection);
931
932     LOG(Network, "Handle %p delegate connection:%p willStopBufferingData:%p", m_handle, connection, data);
933
934     if (!m_handle || !m_handle->client())
935         return;
936     // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
937     // However, with today's computers and networking speeds, this won't happen in practice.
938     // Could be an issue with a giant local file.
939     CallbackGuard guard;
940     m_handle->client()->willStopBufferingData(m_handle, (const char*)[data bytes], static_cast<int>([data length]));
941 }
942
943 - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
944 {
945     UNUSED_PARAM(connection);
946     UNUSED_PARAM(bytesWritten);
947
948     LOG(Network, "Handle %p delegate connection:%p didSendBodyData:%d totalBytesWritten:%d totalBytesExpectedToWrite:%d", m_handle, connection, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
949
950     if (!m_handle || !m_handle->client())
951         return;
952     CallbackGuard guard;
953     m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite);
954 }
955
956 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
957 {
958     UNUSED_PARAM(connection);
959
960     LOG(Network, "Handle %p delegate connectionDidFinishLoading:%p", m_handle, connection);
961
962     if (!m_handle || !m_handle->client())
963         return;
964     CallbackGuard guard;
965
966     if (!ResourceHandle::didSendBodyDataDelegateExists())
967         disassociateStreamWithResourceHandle([m_handle->firstRequest().nsURLRequest() HTTPBodyStream]);
968
969     m_handle->client()->didFinishLoading(m_handle, 0);
970 }
971
972 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
973 {
974     UNUSED_PARAM(connection);
975
976     LOG(Network, "Handle %p delegate connection:%p didFailWithError:%@", m_handle, connection, error);
977
978     if (!m_handle || !m_handle->client())
979         return;
980     CallbackGuard guard;
981
982     if (!ResourceHandle::didSendBodyDataDelegateExists())
983         disassociateStreamWithResourceHandle([m_handle->firstRequest().nsURLRequest() HTTPBodyStream]);
984
985     m_handle->client()->didFail(m_handle, error);
986 }
987
988 #ifdef BUILDING_ON_TIGER
989 - (void)_callConnectionWillCacheResponseWithInfo:(NSMutableDictionary *)info
990 {
991     NSURLConnection *connection = [info objectForKey:@"connection"];
992     NSCachedURLResponse *cachedResponse = [info objectForKey:@"cachedResponse"];
993     NSCachedURLResponse *result = [self connection:connection willCacheResponse:cachedResponse];
994     if (result)
995         [info setObject:result forKey:@"result"];
996 }
997 #endif
998
999 - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
1000 {
1001     LOG(Network, "Handle %p delegate connection:%p willCacheResponse:%p", m_handle, connection, cachedResponse);
1002
1003 #ifdef BUILDING_ON_TIGER
1004     // On Tiger CFURLConnection can sometimes call the connection:willCacheResponse: delegate method on
1005     // a secondary thread instead of the main thread. If this happens perform the work on the main thread.
1006     if (!pthread_main_np()) {
1007         NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
1008         if (connection)
1009             [info setObject:connection forKey:@"connection"];
1010         if (cachedResponse)
1011             [info setObject:cachedResponse forKey:@"cachedResponse"];
1012
1013         // Include synchronous url connection's mode as an acceptable run loopmode
1014         // <rdar://problem/5511842>
1015         NSArray *modes = [[NSArray alloc] initWithObjects:(NSString *)kCFRunLoopCommonModes, @"NSSynchronousURLConnection_PrivateMode", nil];        
1016         [self performSelectorOnMainThread:@selector(_callConnectionWillCacheResponseWithInfo:) withObject:info waitUntilDone:YES modes:modes];
1017         [modes release];
1018
1019         NSCachedURLResponse *result = [[info valueForKey:@"result"] retain];
1020         [info release];
1021
1022         return [result autorelease];
1023     }
1024 #else
1025     UNUSED_PARAM(connection);
1026 #endif
1027
1028 #ifndef NDEBUG
1029     if (isInitializingConnection)
1030         LOG_ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (4067625)");
1031 #endif
1032
1033     if (!m_handle || !m_handle->client())
1034         return nil;
1035
1036     CallbackGuard guard;
1037     
1038     NSCachedURLResponse *newResponse = m_handle->client()->willCacheResponse(m_handle, cachedResponse);
1039     if (newResponse != cachedResponse)
1040         return newResponse;
1041     
1042     CacheStoragePolicy policy = static_cast<CacheStoragePolicy>([newResponse storagePolicy]);
1043         
1044     m_handle->client()->willCacheResponse(m_handle, policy);
1045
1046     if (static_cast<NSURLCacheStoragePolicy>(policy) != [newResponse storagePolicy])
1047         newResponse = [[[NSCachedURLResponse alloc] initWithResponse:[newResponse response]
1048                                                                 data:[newResponse data]
1049                                                             userInfo:[newResponse userInfo]
1050                                                        storagePolicy:static_cast<NSURLCacheStoragePolicy>(policy)] autorelease];
1051
1052     return newResponse;
1053 }
1054
1055 @end
1056
1057 #ifndef BUILDING_ON_TIGER
1058
1059 WebCoreSynchronousLoaderClient::~WebCoreSynchronousLoaderClient()
1060 {
1061     [m_response release];
1062     [m_data release];
1063     [m_error release];
1064 }
1065
1066 void WebCoreSynchronousLoaderClient::willSendRequest(ResourceHandle* handle, ResourceRequest& request, const ResourceResponse& /*redirectResponse*/)
1067 {
1068     // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
1069     if (!protocolHostAndPortAreEqual(handle->firstRequest().url(), request.url())) {
1070         ASSERT(!m_error);
1071         m_error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil];
1072         m_isDone = true;
1073         request = 0;
1074         return;
1075     }
1076 }
1077
1078 bool WebCoreSynchronousLoaderClient::shouldUseCredentialStorage(ResourceHandle*)
1079 {
1080     // FIXME: We should ask FrameLoaderClient whether using credential storage is globally forbidden.
1081     return m_allowStoredCredentials;
1082 }
1083
1084 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
1085 bool WebCoreSynchronousLoaderClient::canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace&)
1086 {
1087     // FIXME: We should ask FrameLoaderClient.
1088     return true;
1089 }
1090 #endif
1091
1092 void WebCoreSynchronousLoaderClient::didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge)
1093 {
1094     // FIXME: The user should be asked for credentials, as in async case.
1095     [challenge.sender() continueWithoutCredentialForAuthenticationChallenge:challenge.nsURLAuthenticationChallenge()];
1096 }
1097
1098 void WebCoreSynchronousLoaderClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
1099 {
1100     [m_response release];
1101     m_response = [response.nsURLResponse() copy];
1102 }
1103
1104 void WebCoreSynchronousLoaderClient::didReceiveData(ResourceHandle*, const char* data, int length, int /*lengthReceived*/)
1105 {
1106     if (!m_data)
1107         m_data = [[NSMutableData alloc] init];
1108     [m_data appendBytes:data length:length];
1109 }
1110
1111 void WebCoreSynchronousLoaderClient::didFinishLoading(ResourceHandle*, double)
1112 {
1113     m_isDone = true;
1114 }
1115
1116 void WebCoreSynchronousLoaderClient::didFail(ResourceHandle*, const ResourceError& error)
1117 {
1118     ASSERT(!m_error);
1119
1120     m_error = [error copy];
1121     m_isDone = true;
1122 }
1123
1124 #endif // BUILDING_ON_TIGER
1125
1126 #endif // !USE(CFNETWORK)