#ifndef CurlDownload_h
#define CurlDownload_h
#include "FileSystem.h"
#include "ResourceHandle.h"
#include "ResourceResponse.h"
#include <wtf/Lock.h>
#include <wtf/Threading.h>
#if PLATFORM(WIN)
#include <windows.h>
#include <winsock2.h>
#endif
#include <curl/curl.h>
namespace WebCore {
class CurlDownloadManager {
public:
CurlDownloadManager();
~CurlDownloadManager();
bool add(CURL* curlHandle);
bool remove(CURL* curlHandle);
int getActiveDownloadCount() const;
int getPendingDownloadCount() const;
private:
void startThreadIfNeeded();
void stopThread();
void stopThreadIfIdle();
void updateHandleList();
CURLM* getMultiHandle() const { return m_curlMultiHandle; }
bool runThread() const { LockHolder locker(m_mutex); return m_runThread; }
void setRunThread(bool runThread) { LockHolder locker(m_mutex); m_runThread = runThread; }
bool addToCurl(CURL* curlHandle);
bool removeFromCurl(CURL* curlHandle);
static void downloadThread(void* data);
ThreadIdentifier m_threadId;
CURLM* m_curlMultiHandle;
Vector<CURL*> m_pendingHandleList;
Vector<CURL*> m_activeHandleList;
Vector<CURL*> m_removedHandleList;
mutable Lock m_mutex;
bool m_runThread;
};
class CurlDownloadListener {
public:
virtual void didReceiveResponse() { }
virtual void didReceiveDataOfLength(int size) { }
virtual void didFinish() { }
virtual void didFail() { }
};
class CurlDownload : public ThreadSafeRefCounted<CurlDownload> {
public:
CurlDownload();
~CurlDownload();
void init(CurlDownloadListener*, const WebCore::URL&);
void init(CurlDownloadListener*, ResourceHandle*, const ResourceRequest&, const ResourceResponse&);
void setListener(CurlDownloadListener* listener) { m_listener = listener; }
bool start();
bool cancel();
String getTempPath() const;
String getUrl() const;
WebCore::ResourceResponse getResponse() const;
bool deletesFileUponFailure() const { return m_deletesFileUponFailure; }
void setDeletesFileUponFailure(bool deletesFileUponFailure) { m_deletesFileUponFailure = deletesFileUponFailure; }
void setDestination(const String& destination) { m_destination = destination; }
private:
void closeFile();
void moveFileToDestination();
void writeDataToFile(const char* data, int size);
void addHeaders(const ResourceRequest&);
void didReceiveHeader(const String& header);
void didReceiveData(void* data, int size);
void didReceiveResponse();
void didReceiveDataOfLength(int size);
void didFinish();
void didFail();
static size_t writeCallback(void* ptr, size_t, size_t nmemb, void* data);
static size_t headerCallback(char* ptr, size_t, size_t nmemb, void* data);
static void downloadFinishedCallback(CurlDownload*);
static void downloadFailedCallback(CurlDownload*);
static void receivedDataCallback(CurlDownload*, int size);
static void receivedResponseCallback(CurlDownload*);
CURL* m_curlHandle;
struct curl_slist* m_customHeaders;
char* m_url;
String m_tempPath;
String m_destination;
WebCore::PlatformFileHandle m_tempHandle;
WebCore::ResourceResponse m_response;
bool m_deletesFileUponFailure;
mutable Lock m_mutex;
CurlDownloadListener *m_listener;
static CurlDownloadManager m_downloadManager;
friend class CurlDownloadManager;
};
}
#endif