2 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "ResourceHandle.h"
29 #include "ResourceHandleClient.h"
30 #include "ResourceHandleInternal.h"
32 #include "AuthenticationCF.h"
33 #include "AuthenticationChallenge.h"
34 #include "CookieStorageWin.h"
36 #include "DocLoader.h"
38 #include "FrameLoader.h"
40 #include "NotImplemented.h"
41 #include "ResourceError.h"
42 #include "ResourceResponse.h"
44 #include <wtf/HashMap.h>
45 #include <wtf/Threading.h>
47 #include <sys/types.h>
49 #include <process.h> // for _beginthread()
51 #include <CFNetwork/CFNetwork.h>
52 #include <WebKitSystemInterface/WebKitSystemInterface.h>
56 static HMODULE
findCFNetworkModule()
58 if (HMODULE
module = GetModuleHandleA("CFNetwork"))
60 return GetModuleHandleA("CFNetwork_debug");
63 static DWORD
cfNetworkVersion()
65 HMODULE cfNetworkModule
= findCFNetworkModule();
66 WCHAR filename
[MAX_PATH
];
67 GetModuleFileName(cfNetworkModule
, filename
, MAX_PATH
);
69 DWORD versionInfoSize
= GetFileVersionInfoSize(filename
, &handle
);
70 Vector
<BYTE
> versionInfo(versionInfoSize
);
71 GetFileVersionInfo(filename
, handle
, versionInfoSize
, versionInfo
.data());
72 VS_FIXEDFILEINFO
* fixedFileInfo
;
73 UINT fixedFileInfoLength
;
74 VerQueryValue(versionInfo
.data(), TEXT("\\"), reinterpret_cast<LPVOID
*>(&fixedFileInfo
), &fixedFileInfoLength
);
75 return fixedFileInfo
->dwProductVersionMS
;
78 static CFIndex
highestSupportedCFURLConnectionClientVersion()
80 const DWORD firstCFNetworkVersionWithConnectionClientV2
= 0x000101a8; // 1.424
81 const DWORD firstCFNetworkVersionWithConnectionClientV3
= 0x000101ad; // 1.429
83 #ifndef _CFURLConnectionClientV2Present
87 DWORD version
= cfNetworkVersion();
88 if (version
< firstCFNetworkVersionWithConnectionClientV2
)
90 #ifndef _CFURLConnectionClientV3Present
94 if (version
< firstCFNetworkVersionWithConnectionClientV3
)
97 #endif // _CFURLConnectionClientV3Present
98 #endif // _CFURLConnectionClientV2Present
101 static CFStringRef WebCoreSynchronousLoaderRunLoopMode
= CFSTR("WebCoreSynchronousLoaderRunLoopMode");
103 class WebCoreSynchronousLoader
{
105 static RetainPtr
<CFDataRef
> load(const ResourceRequest
&, ResourceResponse
&, ResourceError
&);
108 WebCoreSynchronousLoader(ResourceResponse
& response
, ResourceError
& error
)
110 , m_response(response
)
115 static CFURLRequestRef
willSendRequest(CFURLConnectionRef
, CFURLRequestRef
, CFURLResponseRef
, const void* clientInfo
);
116 static void didReceiveResponse(CFURLConnectionRef
, CFURLResponseRef
, const void* clientInfo
);
117 static void didReceiveData(CFURLConnectionRef
, CFDataRef
, CFIndex
, const void* clientInfo
);
118 static void didFinishLoading(CFURLConnectionRef
, const void* clientInfo
);
119 static void didFail(CFURLConnectionRef
, CFErrorRef
, const void* clientInfo
);
120 static void didReceiveChallenge(CFURLConnectionRef
, CFURLAuthChallengeRef
, const void* clientInfo
);
123 RetainPtr
<CFURLRef
> m_url
;
124 ResourceResponse
& m_response
;
125 RetainPtr
<CFMutableDataRef
> m_data
;
126 ResourceError
& m_error
;
129 static HashSet
<String
>& allowsAnyHTTPSCertificateHosts()
131 static HashSet
<String
> hosts
;
136 static HashMap
<String
, RetainPtr
<CFDataRef
> >& clientCerts()
138 static HashMap
<String
, RetainPtr
<CFDataRef
> > certs
;
142 CFURLRequestRef
willSendRequest(CFURLConnectionRef conn
, CFURLRequestRef cfRequest
, CFURLResponseRef cfRedirectResponse
, const void* clientInfo
)
144 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
146 if (!cfRedirectResponse
) {
151 LOG(Network
, "CFNet - willSendRequest(conn=%p, handle=%p) (%s)", conn
, handle
, handle
->request().url().string().utf8().data());
153 ResourceRequest
request(cfRequest
);
154 if (handle
->client())
155 handle
->client()->willSendRequest(handle
, request
, cfRedirectResponse
);
157 cfRequest
= request
.cfURLRequest();
163 void didReceiveResponse(CFURLConnectionRef conn
, CFURLResponseRef cfResponse
, const void* clientInfo
)
165 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
167 LOG(Network
, "CFNet - didReceiveResponse(conn=%p, handle=%p) (%s)", conn
, handle
, handle
->request().url().string().utf8().data());
169 if (handle
->client())
170 handle
->client()->didReceiveResponse(handle
, cfResponse
);
173 void didReceiveData(CFURLConnectionRef conn
, CFDataRef data
, CFIndex originalLength
, const void* clientInfo
)
175 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
176 const UInt8
* bytes
= CFDataGetBytePtr(data
);
177 CFIndex length
= CFDataGetLength(data
);
179 LOG(Network
, "CFNet - didReceiveData(conn=%p, handle=%p, bytes=%d) (%s)", conn
, handle
, length
, handle
->request().url().string().utf8().data());
181 if (handle
->client())
182 handle
->client()->didReceiveData(handle
, (const char*)bytes
, length
, originalLength
);
185 #ifdef _CFURLConnectionClientV2Present
186 static void didSendBodyData(CFURLConnectionRef conn
, CFIndex bytesWritten
, CFIndex totalBytesWritten
, CFIndex totalBytesExpectedToWrite
, const void *clientInfo
)
188 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
189 if (!handle
|| !handle
->client())
191 handle
->client()->didSendData(handle
, totalBytesWritten
, totalBytesExpectedToWrite
);
195 #ifdef _CFURLConnectionClientV3Present
196 static Boolean
shouldUseCredentialStorageCallback(CFURLConnectionRef conn
, const void* clientInfo
)
198 ResourceHandle
* handle
= const_cast<ResourceHandle
*>(static_cast<const ResourceHandle
*>(clientInfo
));
200 LOG(Network
, "CFNet - shouldUseCredentialStorage(conn=%p, handle=%p) (%s)", conn
, handle
, handle
->request().url().string().utf8().data());
205 return handle
->shouldUseCredentialStorage();
209 void didFinishLoading(CFURLConnectionRef conn
, const void* clientInfo
)
211 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
213 LOG(Network
, "CFNet - didFinishLoading(conn=%p, handle=%p) (%s)", conn
, handle
, handle
->request().url().string().utf8().data());
215 if (handle
->client())
216 handle
->client()->didFinishLoading(handle
);
219 void didFail(CFURLConnectionRef conn
, CFErrorRef error
, const void* clientInfo
)
221 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
223 LOG(Network
, "CFNet - didFail(conn=%p, handle=%p, error = %p) (%s)", conn
, handle
, error
, handle
->request().url().string().utf8().data());
225 if (handle
->client())
226 handle
->client()->didFail(handle
, ResourceError(error
));
229 CFCachedURLResponseRef
willCacheResponse(CFURLConnectionRef conn
, CFCachedURLResponseRef cachedResponse
, const void* clientInfo
)
231 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
233 CacheStoragePolicy policy
= static_cast<CacheStoragePolicy
>(CFCachedURLResponseGetStoragePolicy(cachedResponse
));
235 if (handle
->client())
236 handle
->client()->willCacheResponse(handle
, policy
);
238 if (static_cast<CFURLCacheStoragePolicy
>(policy
) != CFCachedURLResponseGetStoragePolicy(cachedResponse
))
239 cachedResponse
= CFCachedURLResponseCreateWithUserInfo(kCFAllocatorDefault
,
240 CFCachedURLResponseGetWrappedResponse(cachedResponse
),
241 CFCachedURLResponseGetReceiverData(cachedResponse
),
242 CFCachedURLResponseGetUserInfo(cachedResponse
),
243 static_cast<CFURLCacheStoragePolicy
>(policy
));
244 CFRetain(cachedResponse
);
246 return cachedResponse
;
249 void didReceiveChallenge(CFURLConnectionRef conn
, CFURLAuthChallengeRef challenge
, const void* clientInfo
)
251 ResourceHandle
* handle
= static_cast<ResourceHandle
*>(const_cast<void*>(clientInfo
));
253 LOG(Network
, "CFNet - didReceiveChallenge(conn=%p, handle=%p (%s)", conn
, handle
, handle
->request().url().string().utf8().data());
255 handle
->didReceiveAuthenticationChallenge(AuthenticationChallenge(challenge
, handle
));
258 void addHeadersFromHashMap(CFMutableURLRequestRef request
, const HTTPHeaderMap
& requestHeaders
)
260 if (!requestHeaders
.size())
263 HTTPHeaderMap::const_iterator end
= requestHeaders
.end();
264 for (HTTPHeaderMap::const_iterator it
= requestHeaders
.begin(); it
!= end
; ++it
) {
265 CFStringRef key
= it
->first
.createCFString();
266 CFStringRef value
= it
->second
.createCFString();
267 CFURLRequestSetHTTPHeaderFieldValue(request
, key
, value
);
273 ResourceHandleInternal::~ResourceHandleInternal()
276 LOG(Network
, "CFNet - Cancelling connection %p (%s)", m_connection
, m_request
.url().string().utf8().data());
277 CFURLConnectionCancel(m_connection
.get());
281 ResourceHandle::~ResourceHandle()
283 LOG(Network
, "CFNet - Destroying job %p (%s)", this, d
->m_request
.url().string().utf8().data());
286 CFArrayRef
arrayFromFormData(const FormData
& d
)
288 size_t size
= d
.elements().size();
289 CFMutableArrayRef a
= CFArrayCreateMutable(0, d
.elements().size(), &kCFTypeArrayCallBacks
);
290 for (size_t i
= 0; i
< size
; ++i
) {
291 const FormDataElement
& e
= d
.elements()[i
];
292 if (e
.m_type
== FormDataElement::data
) {
293 CFDataRef data
= CFDataCreate(0, (const UInt8
*)e
.m_data
.data(), e
.m_data
.size());
294 CFArrayAppendValue(a
, data
);
297 ASSERT(e
.m_type
== FormDataElement::encodedFile
);
298 CFStringRef filename
= e
.m_filename
.createCFString();
299 CFArrayAppendValue(a
, filename
);
306 void emptyPerform(void* unused
)
310 static CFRunLoopRef loaderRL
= 0;
311 void* runLoaderThread(void *unused
)
313 loaderRL
= CFRunLoopGetCurrent();
315 // Must add a source to the run loop to prevent CFRunLoopRun() from exiting
316 CFRunLoopSourceContext ctxt
= {0, (void *)1 /*must be non-NULL*/, 0, 0, 0, 0, 0, 0, 0, emptyPerform
};
317 CFRunLoopSourceRef bogusSource
= CFRunLoopSourceCreate(0, 0, &ctxt
);
318 CFRunLoopAddSource(loaderRL
, bogusSource
,kCFRunLoopDefaultMode
);
325 CFRunLoopRef
ResourceHandle::loaderRunLoop()
328 createThread(runLoaderThread
, 0, "CFNetwork::Loader");
329 while (loaderRL
== 0) {
330 // FIXME: sleep 10? that can't be right...
337 static CFURLRequestRef
makeFinalRequest(const ResourceRequest
& request
, bool shouldContentSniff
)
339 CFMutableURLRequestRef newRequest
= CFURLRequestCreateMutableCopy(kCFAllocatorDefault
, request
.cfURLRequest());
341 if (!shouldContentSniff
)
342 wkSetCFURLRequestShouldContentSniff(newRequest
, false);
344 RetainPtr
<CFMutableDictionaryRef
> sslProps
;
346 if (allowsAnyHTTPSCertificateHosts().contains(request
.url().host().lower())) {
347 sslProps
.adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
348 CFDictionaryAddValue(sslProps
.get(), kCFStreamSSLAllowsAnyRoot
, kCFBooleanTrue
);
349 CFDictionaryAddValue(sslProps
.get(), kCFStreamSSLAllowsExpiredRoots
, kCFBooleanTrue
);
352 HashMap
<String
, RetainPtr
<CFDataRef
> >::iterator clientCert
= clientCerts().find(request
.url().host().lower());
353 if (clientCert
!= clientCerts().end()) {
355 sslProps
.adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
356 wkSetClientCertificateInSSLProperties(sslProps
.get(), (clientCert
->second
).get());
360 CFURLRequestSetSSLProperties(newRequest
, sslProps
.get());
362 if (CFHTTPCookieStorageRef cookieStorage
= currentCookieStorage()) {
363 CFURLRequestSetHTTPCookieStorage(newRequest
, cookieStorage
);
364 CFURLRequestSetHTTPCookieStorageAcceptPolicy(newRequest
, CFHTTPCookieStorageGetCookieAcceptPolicy(cookieStorage
));
370 bool ResourceHandle::start(Frame
* frame
)
372 // If we are no longer attached to a Page, this must be an attempted load from an
373 // onUnload handler, so let's just block it.
377 RetainPtr
<CFURLRequestRef
> request(AdoptCF
, makeFinalRequest(d
->m_request
, d
->m_shouldContentSniff
));
379 static CFIndex clientVersion
= highestSupportedCFURLConnectionClientVersion();
380 CFURLConnectionClient
* client
;
381 #if defined(_CFURLConnectionClientV3Present)
382 CFURLConnectionClient_V3 client_V3
= {clientVersion
, this, 0, 0, 0, willSendRequest
, didReceiveResponse
, didReceiveData
, NULL
, didFinishLoading
, didFail
, willCacheResponse
, didReceiveChallenge
, didSendBodyData
, shouldUseCredentialStorageCallback
, 0};
383 client
= reinterpret_cast<CFURLConnectionClient
*>(&client_V3
);
384 #elif defined(_CFURLConnectionClientV2Present)
385 CFURLConnectionClient_V2 client_V2
= {clientVersion
, this, 0, 0, 0, willSendRequest
, didReceiveResponse
, didReceiveData
, NULL
, didFinishLoading
, didFail
, willCacheResponse
, didReceiveChallenge
, didSendBodyData
};
386 client
= reinterpret_cast<CFURLConnectionClient
*>(&client_V2
);
388 CFURLConnectionClient client_V1
= {1, this, 0, 0, 0, willSendRequest
, didReceiveResponse
, didReceiveData
, NULL
, didFinishLoading
, didFail
, willCacheResponse
, didReceiveChallenge
};
392 d
->m_connection
.adoptCF(CFURLConnectionCreate(0, request
.get(), client
));
394 CFURLConnectionScheduleWithCurrentMessageQueue(d
->m_connection
.get());
395 CFURLConnectionScheduleDownloadWithRunLoop(d
->m_connection
.get(), loaderRunLoop(), kCFRunLoopDefaultMode
);
396 CFURLConnectionStart(d
->m_connection
.get());
398 LOG(Network
, "CFNet - Starting URL %s (handle=%p, conn=%p)", d
->m_request
.url().string().utf8().data(), this, d
->m_connection
);
403 void ResourceHandle::cancel()
405 if (d
->m_connection
) {
406 CFURLConnectionCancel(d
->m_connection
.get());
411 PassRefPtr
<SharedBuffer
> ResourceHandle::bufferedData()
413 ASSERT_NOT_REACHED();
417 bool ResourceHandle::supportsBufferedData()
422 bool ResourceHandle::shouldUseCredentialStorage()
424 LOG(Network
, "CFNet - shouldUseCredentialStorage()");
426 return client()->shouldUseCredentialStorage(this);
431 void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge
& challenge
)
433 LOG(Network
, "CFNet - didReceiveAuthenticationChallenge()");
434 ASSERT(!d
->m_currentCFChallenge
);
435 ASSERT(d
->m_currentWebChallenge
.isNull());
436 // Since CFURLConnection networking relies on keeping a reference to the original CFURLAuthChallengeRef,
437 // we make sure that is actually present
438 ASSERT(challenge
.cfURLAuthChallengeRef());
440 d
->m_currentCFChallenge
= challenge
.cfURLAuthChallengeRef();
441 d
->m_currentWebChallenge
= AuthenticationChallenge(d
->m_currentCFChallenge
, this);
444 client()->didReceiveAuthenticationChallenge(this, d
->m_currentWebChallenge
);
447 void ResourceHandle::receivedCredential(const AuthenticationChallenge
& challenge
, const Credential
& credential
)
449 LOG(Network
, "CFNet - receivedCredential()");
450 ASSERT(!challenge
.isNull());
451 ASSERT(challenge
.cfURLAuthChallengeRef());
452 if (challenge
!= d
->m_currentWebChallenge
)
455 CFURLCredentialRef cfCredential
= createCF(credential
);
456 CFURLConnectionUseCredential(d
->m_connection
.get(), cfCredential
, challenge
.cfURLAuthChallengeRef());
457 CFRelease(cfCredential
);
459 clearAuthentication();
462 void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge
& challenge
)
464 LOG(Network
, "CFNet - receivedRequestToContinueWithoutCredential()");
465 ASSERT(!challenge
.isNull());
466 ASSERT(challenge
.cfURLAuthChallengeRef());
467 if (challenge
!= d
->m_currentWebChallenge
)
470 CFURLConnectionUseCredential(d
->m_connection
.get(), 0, challenge
.cfURLAuthChallengeRef());
472 clearAuthentication();
475 void ResourceHandle::receivedCancellation(const AuthenticationChallenge
& challenge
)
477 LOG(Network
, "CFNet - receivedCancellation()");
478 if (challenge
!= d
->m_currentWebChallenge
)
482 client()->receivedCancellation(this, challenge
);
485 CFURLConnectionRef
ResourceHandle::connection() const
487 return d
->m_connection
.get();
490 CFURLConnectionRef
ResourceHandle::releaseConnectionForDownload()
492 LOG(Network
, "CFNet - Job %p releasing connection %p for download", this, d
->m_connection
.get());
493 return d
->m_connection
.releaseRef();
496 void ResourceHandle::loadResourceSynchronously(const ResourceRequest
& request
, ResourceError
& error
, ResourceResponse
& response
, Vector
<char>& vector
, Frame
*)
498 ASSERT(!request
.isEmpty());
500 RetainPtr
<CFDataRef
> data
= WebCoreSynchronousLoader::load(request
, response
, error
);
502 if (!error
.isNull()) {
503 // FIXME: Return the actual response for failed authentication.
504 response
= ResourceResponse(request
.url(), String(), 0, String(), String());
505 response
.setHTTPStatusCode(404);
509 ASSERT(vector
.isEmpty());
510 vector
.append(CFDataGetBytePtr(data
.get()), CFDataGetLength(data
.get()));
514 void ResourceHandle::setHostAllowsAnyHTTPSCertificate(const String
& host
)
516 allowsAnyHTTPSCertificateHosts().add(host
.lower());
519 void ResourceHandle::setClientCertificate(const String
& host
, CFDataRef cert
)
521 clientCerts().set(host
.lower(), cert
);
524 void ResourceHandle::setDefersLoading(bool defers
)
526 if (!d
->m_connection
)
530 CFURLConnectionHalt(d
->m_connection
.get());
532 CFURLConnectionResume(d
->m_connection
.get());
535 bool ResourceHandle::loadsBlocked()
540 bool ResourceHandle::willLoadFromCache(ResourceRequest
&)
542 // Not having this function means that we'll ask the user about re-posting a form
543 // even when we go back to a page that's still in the cache.
548 CFURLRequestRef
WebCoreSynchronousLoader::willSendRequest(CFURLConnectionRef
, CFURLRequestRef cfRequest
, CFURLResponseRef cfRedirectResponse
, const void* clientInfo
)
550 WebCoreSynchronousLoader
* loader
= static_cast<WebCoreSynchronousLoader
*>(const_cast<void*>(clientInfo
));
552 // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
553 if (loader
->m_url
&& !protocolHostAndPortAreEqual(loader
->m_url
.get(), CFURLRequestGetURL(cfRequest
))) {
554 RetainPtr
<CFErrorRef
> cfError(AdoptCF
, CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainCFNetwork
, kCFURLErrorBadServerResponse
, 0));
555 loader
->m_error
= cfError
.get();
556 loader
->m_isDone
= true;
560 loader
->m_url
= CFURLRequestGetURL(cfRequest
);
566 void WebCoreSynchronousLoader::didReceiveResponse(CFURLConnectionRef
, CFURLResponseRef cfResponse
, const void* clientInfo
)
568 WebCoreSynchronousLoader
* loader
= static_cast<WebCoreSynchronousLoader
*>(const_cast<void*>(clientInfo
));
570 loader
->m_response
= cfResponse
;
573 void WebCoreSynchronousLoader::didReceiveData(CFURLConnectionRef
, CFDataRef data
, CFIndex originalLength
, const void* clientInfo
)
575 WebCoreSynchronousLoader
* loader
= static_cast<WebCoreSynchronousLoader
*>(const_cast<void*>(clientInfo
));
578 loader
->m_data
.adoptCF(CFDataCreateMutable(kCFAllocatorDefault
, originalLength
));
580 const UInt8
* bytes
= CFDataGetBytePtr(data
);
581 CFIndex length
= CFDataGetLength(data
);
583 CFDataAppendBytes(loader
->m_data
.get(), bytes
, length
);
586 void WebCoreSynchronousLoader::didFinishLoading(CFURLConnectionRef
, const void* clientInfo
)
588 WebCoreSynchronousLoader
* loader
= static_cast<WebCoreSynchronousLoader
*>(const_cast<void*>(clientInfo
));
590 loader
->m_isDone
= true;
593 void WebCoreSynchronousLoader::didFail(CFURLConnectionRef
, CFErrorRef error
, const void* clientInfo
)
595 WebCoreSynchronousLoader
* loader
= static_cast<WebCoreSynchronousLoader
*>(const_cast<void*>(clientInfo
));
597 loader
->m_error
= error
;
598 loader
->m_isDone
= true;
601 void WebCoreSynchronousLoader::didReceiveChallenge(CFURLConnectionRef conn
, CFURLAuthChallengeRef challenge
, const void* clientInfo
)
603 WebCoreSynchronousLoader
* loader
= static_cast<WebCoreSynchronousLoader
*>(const_cast<void*>(clientInfo
));
605 // FIXME: Mac uses credentials from URL here, should we do the same?
606 CFURLConnectionUseCredential(conn
, 0, challenge
);
609 RetainPtr
<CFDataRef
> WebCoreSynchronousLoader::load(const ResourceRequest
& request
, ResourceResponse
& response
, ResourceError
& error
)
611 ASSERT(response
.isNull());
612 ASSERT(error
.isNull());
614 WebCoreSynchronousLoader
loader(response
, error
);
616 RetainPtr
<CFURLRequestRef
> cfRequest(AdoptCF
, makeFinalRequest(request
, true));
618 CFURLConnectionClient_V3 client
= { 3, &loader
, 0, 0, 0, willSendRequest
, didReceiveResponse
, didReceiveData
, 0, didFinishLoading
, didFail
, 0, didReceiveChallenge
, 0, 0, 0 };
620 RetainPtr
<CFURLConnectionRef
> connection(AdoptCF
, CFURLConnectionCreate(kCFAllocatorDefault
, cfRequest
.get(), reinterpret_cast<CFURLConnectionClient
*>(&client
)));
622 CFURLConnectionScheduleWithRunLoop(connection
.get(), CFRunLoopGetCurrent(), WebCoreSynchronousLoaderRunLoopMode
);
623 CFURLConnectionScheduleDownloadWithRunLoop(connection
.get(), CFRunLoopGetCurrent(), WebCoreSynchronousLoaderRunLoopMode
);
624 CFURLConnectionStart(connection
.get());
626 while (!loader
.m_isDone
)
627 CFRunLoopRunInMode(WebCoreSynchronousLoaderRunLoopMode
, UINT_MAX
, true);
629 CFURLConnectionCancel(connection
.get());
631 return loader
.m_data
;
634 } // namespace WebCore