#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->invalidateClient();
}
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)
{
auto curlRequest = CurlRequest::create(request, *this);
return curlRequest;
}
void CurlDownload::curlDidReceiveResponse(CurlRequest& request, 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);
request.completeDidReceiveResponse();
}
void CurlDownload::curlDidReceiveBuffer(CurlRequest& request, Ref<SharedBuffer>&& buffer)
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
if (m_listener)
m_listener->didReceiveDataOfLength(buffer->size());
}
void CurlDownload::curlDidComplete(CurlRequest& request)
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
if (!m_destination.isEmpty()) {
if (!request.getDownloadedFilePath().isEmpty())
FileSystem::moveFile(request.getDownloadedFilePath(), m_destination);
}
if (m_listener)
m_listener->didFinish();
}
void CurlDownload::curlDidFailWithError(CurlRequest& request, const ResourceError& resourceError)
{
ASSERT(isMainThread());
if (m_isCancelled)
return;
if (m_deletesFileUponFailure && !request.getDownloadedFilePath().isEmpty())
FileSystem::deleteFile(request.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_response.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 = createCurlRequest(newRequest);
m_curlRequest->start();
}
}
#endif