#include "config.h"
#include "CurlDownload.h"
#if USE(CURL)
#include "HTTPParsers.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SharedBuffer.h"
namespace WebCore {
CurlDownload::~CurlDownload()
{
if (m_curlRequest)
m_curlRequest->setClient(nullptr);
}
void CurlDownload::init(CurlDownloadListener& listener, const URL& url)
{
m_listener = &listener;
m_request.setURL(url);
}
void CurlDownload::init(CurlDownloadListener& listener, ResourceHandle*, const ResourceRequest& request, const ResourceResponse&)
{
m_listener = &listener;
m_request = request.isolatedCopy();
}
void CurlDownload::start()
{
ASSERT(isMainThread());
m_curlRequest = createCurlRequest(m_request);
m_curlRequest->enableDownloadToFile();
m_curlRequest->start();
}
bool CurlDownload::cancel()
{
m_isCancelled = true;
if (!m_curlRequest)
m_curlRequest->cancel();
return true;
}
Ref<CurlRequest> CurlDownload::createCurlRequest(ResourceRequest& request)
{
return CurlRequest::create(request, this);
}
void CurlDownload::curlDidReceiveResponse(const CurlResponse& response)
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
m_response = ResourceResponse(response);
if (m_response.shouldRedirect()) {
willSendRequest();
return;
}
if (m_listener)
m_listener->didReceiveResponse(m_response);
m_curlRequest->completeDidReceiveResponse();
}
void CurlDownload::curlDidReceiveBuffer(Ref<SharedBuffer>&& buffer)
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
if (m_listener)
m_listener->didReceiveDataOfLength(buffer->size());
}
void CurlDownload::curlDidComplete()
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
if (!m_destination.isEmpty()) {
if (m_curlRequest && !m_curlRequest->getDownloadedFilePath().isEmpty())
FileSystem::moveFile(m_curlRequest->getDownloadedFilePath(), m_destination);
}
if (m_listener)
m_listener->didFinish();
}
void CurlDownload::curlDidFailWithError(const ResourceError& resourceError)
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
if (m_deletesFileUponFailure && m_curlRequest && !m_curlRequest->getDownloadedFilePath().isEmpty())
FileSystem::deleteFile(m_curlRequest->getDownloadedFilePath());
if (m_listener)
m_listener->didFail();
}
bool CurlDownload::shouldRedirectAsGET(const ResourceRequest& request, bool crossOrigin)
{
if ((request.httpMethod() == "GET") || (request.httpMethod() == "HEAD"))
return false;
if (!request.url().protocolIsInHTTPFamily())
return true;
if (m_response.isSeeOther())
return true;
if ((m_response.isMovedPermanently() || m_response.isFound()) && (request.httpMethod() == "POST"))
return true;
if (crossOrigin && (request.httpMethod() == "DELETE"))
return true;
return false;
}
void CurlDownload::willSendRequest()
{
ASSERT(isMainThread());
static const int maxRedirects = 20;
if (m_redirectCount++ > maxRedirects) {
if (m_listener)
m_listener->didFail();
return;
}
String location = m_response.httpHeaderField(HTTPHeaderName::Location);
URL newURL = URL(m_request.url(), location);
bool crossOrigin = !protocolHostAndPortAreEqual(m_request.url(), newURL);
ResourceRequest newRequest = m_request;
newRequest.setURL(newURL);
if (shouldRedirectAsGET(newRequest, crossOrigin)) {
newRequest.setHTTPMethod("GET");
newRequest.setHTTPBody(nullptr);
newRequest.clearHTTPContentType();
}
if (crossOrigin) {
newRequest.clearHTTPAuthorization();
newRequest.clearHTTPOrigin();
}
m_curlRequest->cancel();
m_curlRequest->setClient(nullptr);
m_curlRequest = createCurlRequest(newRequest);
m_curlRequest->start();
}
}
#endif