ResourceHandleCurl.cpp [plain text]
#include "config.h"
#include "ResourceHandle.h"
#if USE(CURL)
#include "CachedResourceLoader.h"
#include "CredentialStorage.h"
#include "FileSystem.h"
#include "Logging.h"
#include "NetworkingContext.h"
#include "NotImplemented.h"
#include "ResourceHandleInternal.h"
#include "ResourceHandleManager.h"
#include "SSLHandle.h"
#if PLATFORM(WIN) && USE(CF)
#include <wtf/PassRefPtr.h>
#include <wtf/RetainPtr.h>
#endif
namespace WebCore {
class WebCoreSynchronousLoader : public ResourceHandleClient {
public:
WebCoreSynchronousLoader();
virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int encodedDataLength);
virtual void didFinishLoading(ResourceHandle*, double );
virtual void didFail(ResourceHandle*, const ResourceError&);
ResourceResponse resourceResponse() const { return m_response; }
ResourceError resourceError() const { return m_error; }
Vector<char> data() const { return m_data; }
private:
ResourceResponse m_response;
ResourceError m_error;
Vector<char> m_data;
};
WebCoreSynchronousLoader::WebCoreSynchronousLoader()
{
}
void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
{
m_response = response;
}
void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, unsigned length, int)
{
m_data.append(data, length);
}
void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*, double)
{
}
void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
{
m_error = error;
}
ResourceHandleInternal::~ResourceHandleInternal()
{
fastFree(m_url);
if (m_customHeaders)
curl_slist_free_all(m_customHeaders);
}
ResourceHandle::~ResourceHandle()
{
cancel();
}
bool ResourceHandle::start()
{
if (d->m_context && !d->m_context->isValid())
return false;
ResourceHandleManager::sharedInstance()->add(this);
return true;
}
void ResourceHandle::cancel()
{
ResourceHandleManager::sharedInstance()->cancel(this);
}
void ResourceHandle::setHostAllowsAnyHTTPSCertificate(const String& host)
{
allowsAnyHTTPSCertificateHosts(host.lower());
}
void ResourceHandle::setClientCertificateInfo(const String& host, const String& certificate, const String& key)
{
if (fileExists(certificate))
addAllowedClientCertificate(host, certificate, key);
else
LOG(Network, "Invalid client certificate file: %s!\n", certificate.latin1().data());
}
#if PLATFORM(WIN) && USE(CF)
static HashMap<String, RetainPtr<CFDataRef> >& clientCerts()
{
static HashMap<String, RetainPtr<CFDataRef> > certs;
return certs;
}
void ResourceHandle::setClientCertificate(const String& host, CFDataRef cert)
{
clientCerts().set(host.lower(), cert);
}
#endif
void ResourceHandle::platformSetDefersLoading(bool defers)
{
if (!d->m_handle)
return;
if (defers) {
CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_ALL);
if (error != CURLE_OK)
return;
} else {
CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_CONT);
if (error != CURLE_OK)
cancel();
}
}
bool ResourceHandle::loadsBlocked()
{
notImplemented();
return false;
}
bool ResourceHandle::shouldUseCredentialStorage()
{
return (!client() || client()->shouldUseCredentialStorage(this)) && firstRequest().url().protocolIsInHTTPFamily();
}
void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
{
WebCoreSynchronousLoader syncLoader;
RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(context, request, &syncLoader, true, false));
ResourceHandleManager* manager = ResourceHandleManager::sharedInstance();
manager->dispatchSynchronousJob(handle.get());
error = syncLoader.resourceError();
data = syncLoader.data();
response = syncLoader.resourceResponse();
}
void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
{
if (!d->m_user.isNull() && !d->m_pass.isNull()) {
Credential credential(d->m_user, d->m_pass, CredentialPersistenceNone);
URL urlToStore;
if (challenge.failureResponse().httpStatusCode() == 401)
urlToStore = challenge.failureResponse().url();
CredentialStorage::set(credential, challenge.protectionSpace(), urlToStore);
String userpass = credential.user() + ":" + credential.password();
curl_easy_setopt(d->m_handle, CURLOPT_USERPWD, userpass.utf8().data());
d->m_user = String();
d->m_pass = String();
return;
}
if (shouldUseCredentialStorage()) {
if (!d->m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
CredentialStorage::remove(challenge.protectionSpace());
}
if (!challenge.previousFailureCount()) {
Credential credential = CredentialStorage::get(challenge.protectionSpace());
if (!credential.isEmpty() && credential != d->m_initialCredential) {
ASSERT(credential.persistence() == CredentialPersistenceNone);
if (challenge.failureResponse().httpStatusCode() == 401) {
CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
}
String userpass = credential.user() + ":" + credential.password();
curl_easy_setopt(d->m_handle, CURLOPT_USERPWD, userpass.utf8().data());
return;
}
}
}
d->m_currentWebChallenge = challenge;
if (client())
client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge);
}
void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
{
if (challenge != d->m_currentWebChallenge)
return;
if (credential.isEmpty()) {
receivedRequestToContinueWithoutCredential(challenge);
return;
}
if (shouldUseCredentialStorage()) {
if (challenge.failureResponse().httpStatusCode() == 401) {
URL urlToStore = challenge.failureResponse().url();
CredentialStorage::set(credential, challenge.protectionSpace(), urlToStore);
}
}
String userpass = credential.user() + ":" + credential.password();
curl_easy_setopt(d->m_handle, CURLOPT_USERPWD, userpass.utf8().data());
clearAuthentication();
}
void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)
{
if (challenge != d->m_currentWebChallenge)
return;
String userpass = "";
curl_easy_setopt(d->m_handle, CURLOPT_USERPWD, userpass.utf8().data());
clearAuthentication();
}
void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge)
{
if (challenge != d->m_currentWebChallenge)
return;
if (client())
client()->receivedCancellation(this, challenge);
}
void ResourceHandle::receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&)
{
ASSERT_NOT_REACHED();
}
void ResourceHandle::receivedChallengeRejection(const AuthenticationChallenge&)
{
ASSERT_NOT_REACHED();
}
}
#endif