Split CDataDownload into subclasses

develop
Nimetu 3 years ago
parent dfe45029ab
commit f26dc534c8

@ -47,6 +47,20 @@ namespace NLGUI
extern std::string CurrentCookie; extern std::string CurrentCookie;
class ICurlDownloadCB
{
public:
ICurlDownloadCB(const std::string &url)
: url(url)
{}
virtual ~ICurlDownloadCB() {};
virtual void finish() = 0;
std::string url;
};
// HTML group // HTML group
/** /**
* Widget to have a resizable scrolltext and its scrollbar * Widget to have a resizable scrolltext and its scrollbar
@ -133,9 +147,8 @@ namespace NLGUI
void endParagraph(); void endParagraph();
// add image download (used by view_bitmap.cpp to load web images) // add image download (used by view_bitmap.cpp to load web images)
void addImageDownload(const std::string &url, CViewBase *img, const CStyleParams &style = CStyleParams(), const TImageType type = NormalImage, const std::string &placeholder = "web_del.tga"); ICurlDownloadCB *addImageDownload(const std::string &url, CViewBase *img, const CStyleParams &style = CStyleParams(), const TImageType type = NormalImage, const std::string &placeholder = "web_del.tga");
// remove image from download list if present void removeImageDownload(ICurlDownloadCB *handle, CViewBase *img);
void removeImageDownload(CViewBase *img);
std::string localImageName(const std::string &url); std::string localImageName(const std::string &url);
// Timeout // Timeout
@ -817,48 +830,89 @@ namespace NLGUI
// decode all HTML entities // decode all HTML entities
static std::string decodeHTMLEntities(const std::string &str); static std::string decodeHTMLEntities(const std::string &str);
struct CDataImageDownload class CDataDownload : public ICurlDownloadCB
{ {
public: public:
CDataImageDownload(CViewBase *img, CStyleParams style, TImageType type): Image(img), Style(style), Type(type) CDataDownload(const std::string &u, const std::string &d)
: ICurlDownloadCB(u), data(NULL), fp(NULL), dest(d), redirects(0), ConnectionTimeout(60)
{}
virtual ~CDataDownload();
public:
CCurlWWWData *data;
std::string dest;
std::string tmpdest;
uint32 redirects;
FILE *fp;
uint32 ConnectionTimeout;
};
class StylesheetDownloadCB : public CDataDownload
{ {
}
public: public:
StylesheetDownloadCB(const std::string &url, const std::string &dest, CGroupHTML *parent)
: CDataDownload(url, dest), Parent(parent)
{}
virtual void finish() NL_OVERRIDE;
private:
CGroupHTML *Parent;
};
class ImageDownloadCB : public CDataDownload
{
public:
struct SImageInfo
{
SImageInfo(CViewBase *img, const CStyleParams &style, TImageType type)
: Image(img), Style(style), Type(type)
{}
CViewBase *Image; CViewBase *Image;
CStyleParams Style; CStyleParams Style;
TImageType Type; TImageType Type;
}; };
struct CDataDownload ImageDownloadCB(const std::string &url, const std::string &dest, CViewBase *img, const CStyleParams &style, TImageType type, CGroupHTML *parent)
{ : CDataDownload(url, dest), Parent(parent)
public:
CDataDownload(const std::string &u, const std::string &d, TDataType t, CViewBase *i, const std::string &s, const std::string &m, const CStyleParams &style = CStyleParams(), const TImageType imagetype = NormalImage)
: data(NULL), fp(NULL), url(u), dest(d), type(t), luaScript(s), md5sum(m), redirects(0), ConnectionTimeout(60)
{ {
if (t == ImgType) imgs.push_back(CDataImageDownload(i, style, imagetype)); addImage(img, style, type);
} }
~CDataDownload();
virtual void finish() NL_OVERRIDE;
void addImage(CViewBase *img, const CStyleParams &style, TImageType type);
void removeImage(CViewBase *img);
private:
std::vector<SImageInfo> Images;
CGroupHTML *Parent;
CStyleParams Style;
TImageType Type;
};
class BnpDownloadCB : public CDataDownload
{
public: public:
CCurlWWWData *data; BnpDownloadCB(const std::string &url, const std::string &dest, const std::string md5sum, const std::string lua, CGroupHTML *parent)
std::string url; : CDataDownload(url, dest), Parent(parent), m_md5sum(md5sum), m_lua(lua)
std::string dest; {}
std::string tmpdest;
std::string luaScript; virtual void finish() NL_OVERRIDE;
std::string md5sum;
TDataType type; private:
uint32 redirects; CGroupHTML *Parent;
FILE *fp; std::string m_md5sum;
std::vector<CDataImageDownload> imgs; std::string m_lua;
uint32 ConnectionTimeout;
}; };
std::list<CDataDownload> Curls; std::list<CDataDownload*> Curls;
CURLM *MultiCurl; CURLM *MultiCurl;
int RunningCurls; int RunningCurls;
bool startCurlDownload(CDataDownload &download); bool startCurlDownload(CDataDownload *download);
void finishCurlDownload(const CDataDownload &download); void finishCurlDownload(CDataDownload *download);
void pumpCurlQueue(); void pumpCurlQueue();
void initImageDownload(); void initImageDownload();
@ -888,7 +942,7 @@ namespace NLGUI
// _CurlWWW download finished // _CurlWWW download finished
void htmlDownloadFinished(bool success, const std::string &error); void htmlDownloadFinished(bool success, const std::string &error);
// images, stylesheets, etc finished downloading // images, stylesheets, etc finished downloading
void dataDownloadFinished(bool success, const std::string &error, CDataDownload &data); void dataDownloadFinished(bool success, const std::string &error, CDataDownload *data);
// HtmlType download finished // HtmlType download finished
void htmlDownloadFinished(const std::string &content, const std::string &type, long code); void htmlDownloadFinished(const std::string &content, const std::string &type, long code);

@ -28,6 +28,7 @@
namespace NLGUI namespace NLGUI
{ {
class ICurlDownloadCB;
/** /**
* class implementing a bitmap view * class implementing a bitmap view
@ -61,7 +62,7 @@ namespace NLGUI
_TxtHeight = -1; _TxtHeight = -1;
// Support for https://.. textures // Support for https://.. textures
_HtmlDownload = false; _HtmlDownload = NULL;
} }
/// Destructor /// Destructor
@ -141,7 +142,9 @@ namespace NLGUI
bool _Flip : 1; bool _Flip : 1;
bool _Tile : 1; bool _Tile : 1;
bool _InheritGCAlpha : 1; bool _InheritGCAlpha : 1;
bool _HtmlDownload : 1;
// pointer to active curl download object
ICurlDownloadCB *_HtmlDownload;
// For single texture // For single texture

@ -266,6 +266,120 @@ namespace NLGUI
data = NULL; data = NULL;
} }
void CGroupHTML::StylesheetDownloadCB::finish()
{
if (CFile::fileExists(tmpdest))
{
if (CFile::fileExists(dest))
{
CFile::deleteFile(dest);
}
CFile::moveFile(dest, tmpdest);
}
Parent->cssDownloadFinished(url, dest);
}
void CGroupHTML::ImageDownloadCB::addImage(CViewBase *img, const CStyleParams &style, TImageType type)
{
Images.push_back(SImageInfo(img, style, type));
}
void CGroupHTML::ImageDownloadCB::removeImage(CViewBase *img)
{
for(std::vector<SImageInfo>::iterator it = Images.begin(); it != Images.end(); ++it)
{
if (it->Image == img)
{
Images.erase(it);
break;
}
}
}
void CGroupHTML::ImageDownloadCB::finish()
{
// tmpdest file does not exist if download skipped (ie cache was used)
if (CFile::fileExists(tmpdest) || CFile::getFileSize(tmpdest) == 0)
{
try {
// verify that image is not corrupted
uint32 w, h;
CBitmap::loadSize(tmpdest, w, h);
if (w != 0 && h != 0)
{
if (CFile::fileExists(dest))
CFile::deleteFile(dest);
}
}
catch(const NLMISC::Exception &e)
{
// exception message has .tmp file name, so keep it for further analysis
nlwarning("Invalid image (%s) from url (%s): %s", tmpdest.c_str(), url.c_str(), e.what());
}
// to reload image on page, the easiest seems to be changing texture
// to temp file temporarily. that forces driver to reload texture from disk
// ITexture::touch() seem not to do this.
// cache was updated, first set texture as temp file
for(std::vector<SImageInfo>::iterator it = Images.begin(); it != Images.end(); ++it)
{
SImageInfo &img = *it;
Parent->setImage(img.Image, tmpdest, img.Type);
Parent->setImageSize(img.Image, img.Style);
}
CFile::moveFile(dest, tmpdest);
}
if (!CFile::fileExists(dest) || CFile::getFileSize(dest) == 0)
{
// placeholder if cached image failed
dest = "web_del.tga";
}
// even if image was cached, incase there was 'http://' image set to CViewBitmap
for(std::vector<SImageInfo>::iterator it = Images.begin(); it != Images.end(); ++it)
{
SImageInfo &img = *it;
Parent->setImage(img.Image, dest, img.Type);
Parent->setImageSize(img.Image, img.Style);
}
}
void CGroupHTML::BnpDownloadCB::finish()
{
bool verified = false;
// no tmpfile if file was already in cache
if (CFile::fileExists(tmpdest))
{
verified = m_md5sum.empty() || (m_md5sum != getMD5(tmpdest).toString());
if (verified)
{
if (CFile::fileExists(dest))
{
CFile::deleteFile(dest);
}
CFile::moveFile(dest, tmpdest);
}
else
{
CFile::deleteFile(tmpdest);
}
}
else if (CFile::fileExists(dest))
{
verified = m_md5sum.empty() || (m_md5sum != getMD5(dest).toString());
}
if (!m_lua.empty())
{
std::string script = "\nlocal __CURRENT_WINDOW__ = \""+Parent->getId()+"\"";
script += toString("\nlocal __DOWNLOAD_STATUS__ = %s\n", verified ? "true" : "false");
script += m_lua;
CLuaManager::getInstance().executeLuaScript(script, true );
}
}
// Check if domain is on TrustedDomain // Check if domain is on TrustedDomain
bool CGroupHTML::isTrustedDomain(const string &domain) bool CGroupHTML::isTrustedDomain(const string &domain)
{ {
@ -479,17 +593,17 @@ namespace NLGUI
{ {
if (RunningCurls < options.curlMaxConnections) if (RunningCurls < options.curlMaxConnections)
{ {
std::list<CDataDownload>::iterator it=Curls.begin(); std::list<CDataDownload*>::iterator it=Curls.begin();
uint c = 0;
while(it != Curls.end() && RunningCurls < options.curlMaxConnections) while(it != Curls.end() && RunningCurls < options.curlMaxConnections)
{ {
if (it->data == NULL) if ((*it)->data == NULL)
{ {
LOG_DL("(%s) starting new download '%s'", _Id.c_str(), it->url.c_str()); LOG_DL("(%s) starting new download '%s'", _Id.c_str(), it->url.c_str());
if (!startCurlDownload(*it)) if (!startCurlDownload(*it))
{ {
LOG_DL("(%s) failed to start '%s)'", _Id.c_str(), it->url.c_str()); LOG_DL("(%s) failed to start '%s)'", _Id.c_str(), it->url.c_str());
finishCurlDownload(*it); finishCurlDownload(*it);
it = Curls.erase(it); it = Curls.erase(it);
continue; continue;
} }
@ -504,11 +618,11 @@ namespace NLGUI
} }
// Add url to MultiCurl queue and return cURL handle // Add url to MultiCurl queue and return cURL handle
bool CGroupHTML::startCurlDownload(CDataDownload &download) bool CGroupHTML::startCurlDownload(CDataDownload *download)
{ {
if (!MultiCurl) if (!MultiCurl)
{ {
nlwarning("Invalid MultiCurl handle, unable to download '%s'", download.url.c_str()); nlwarning("Invalid MultiCurl handle, unable to download '%s'", download->url.c_str());
return false; return false;
} }
@ -516,28 +630,28 @@ namespace NLGUI
time(&currentTime); time(&currentTime);
CHttpCacheObject cache; CHttpCacheObject cache;
if (CFile::fileExists(download.dest)) if (CFile::fileExists(download->dest))
cache = CHttpCache::getInstance()->lookup(download.dest); cache = CHttpCache::getInstance()->lookup(download->dest);
if (cache.Expires > currentTime) if (cache.Expires > currentTime)
{ {
LOG_DL("Cache for (%s) is not expired (%s, expires:%d)", download.url.c_str(), download.dest.c_str(), cache.Expires - currentTime); LOG_DL("Cache for (%s) is not expired (%s, expires:%d)", download->url.c_str(), download->dest.c_str(), cache.Expires - currentTime);
return false; return false;
} }
// use browser Id so that two browsers would not use same temp file // use browser Id so that two browsers would not use same temp file
download.tmpdest = localImageName(_Id + download.dest) + ".tmp"; download->tmpdest = localImageName(_Id + download->dest) + ".tmp";
// erase the tmp file if exists // erase the tmp file if exists
if (CFile::fileExists(download.tmpdest)) if (CFile::fileExists(download->tmpdest))
{ {
CFile::deleteFile(download.tmpdest); CFile::deleteFile(download->tmpdest);
} }
FILE *fp = nlfopen (download.tmpdest, "wb"); FILE *fp = nlfopen (download->tmpdest, "wb");
if (fp == NULL) if (fp == NULL)
{ {
nlwarning("Can't open file '%s' for writing: code=%d '%s'", download.tmpdest.c_str (), errno, strerror(errno)); nlwarning("Can't open file '%s' for writing: code=%d '%s'", download->tmpdest.c_str (), errno, strerror(errno));
return false; return false;
} }
@ -545,28 +659,28 @@ namespace NLGUI
if (!curl) if (!curl)
{ {
fclose(fp); fclose(fp);
CFile::deleteFile(download.tmpdest); CFile::deleteFile(download->tmpdest);
nlwarning("Creating cURL handle failed, unable to download '%s'", download.url.c_str()); nlwarning("Creating cURL handle failed, unable to download '%s'", download->url.c_str());
return false; return false;
} }
LOG_DL("curl easy handle %p created for '%s'", curl, download.url.c_str()); LOG_DL("curl easy handle %p created for '%s'", curl, download->url.c_str());
// https:// // https://
if (toLowerAscii(download.url.substr(0, 8)) == "https://") if (toLowerAscii(download->url.substr(0, 8)) == "https://")
{ {
// if supported, use custom SSL context function to load certificates // if supported, use custom SSL context function to load certificates
NLWEB::CCurlCertificates::useCertificates(curl); NLWEB::CCurlCertificates::useCertificates(curl);
} }
download.data = new CCurlWWWData(curl, download.url); download->data = new CCurlWWWData(curl, download->url);
download.fp = fp; download->fp = fp;
// initial connection timeout, curl default is 300sec // initial connection timeout, curl default is 300sec
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, download.ConnectionTimeout); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, download->ConnectionTimeout);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
curl_easy_setopt(curl, CURLOPT_URL, download.url.c_str()); curl_easy_setopt(curl, CURLOPT_URL, download->url.c_str());
// limit curl to HTTP and HTTPS protocols only // limit curl to HTTP and HTTPS protocols only
curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
@ -580,16 +694,16 @@ namespace NLGUI
headers.push_back("If-Modified-Since: " + cache.LastModified); headers.push_back("If-Modified-Since: " + cache.LastModified);
if (headers.size() > 0) if (headers.size() > 0)
download.data->sendHeaders(headers); download->data->sendHeaders(headers);
// catch headers // catch headers
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, NLGUI::curlHeaderCallback); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, NLGUI::curlHeaderCallback);
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, download.data); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, download->data);
std::string userAgent = options.appName + "/" + options.appVersion; std::string userAgent = options.appName + "/" + options.appVersion;
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str()); curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str());
CUrlParser uri(download.url); CUrlParser uri(download->url);
if (!uri.host.empty()) if (!uri.host.empty())
sendCookies(curl, uri.host, isTrustedDomain(uri.host)); sendCookies(curl, uri.host, isTrustedDomain(uri.host));
@ -599,7 +713,7 @@ namespace NLGUI
CURLMcode ret = curl_multi_add_handle(MultiCurl, curl); CURLMcode ret = curl_multi_add_handle(MultiCurl, curl);
if (ret != CURLM_OK) if (ret != CURLM_OK)
{ {
nlwarning("cURL multi handle %p error %d on '%s'", curl, ret, download.url.c_str()); nlwarning("cURL multi handle %p error %d on '%s'", curl, ret, download->url.c_str());
return false; return false;
} }
@ -607,118 +721,21 @@ namespace NLGUI
return true; return true;
} }
void CGroupHTML::finishCurlDownload(const CDataDownload &download) void CGroupHTML::finishCurlDownload(CDataDownload *download)
{
if (download.type == ImgType)
{
if (CFile::fileExists(download.tmpdest) && CFile::getFileSize(download.tmpdest) > 0)
{
try
{
// verify that image is not corrupted
uint32 w, h;
CBitmap::loadSize(download.tmpdest, w, h);
if (w != 0 && h != 0)
{
if (CFile::fileExists(download.dest))
CFile::deleteFile(download.dest);
// to reload image on page, the easiest seems to be changing texture
// to temp file temporarily. that forces driver to reload texture from disk
// ITexture::touch() seem not to do this.
// cache was updated, first set texture as temp file
for(uint i = 0; i < download.imgs.size(); i++)
{
setImage(download.imgs[i].Image, download.tmpdest, download.imgs[i].Type);
setImageSize(download.imgs[i].Image, download.imgs[i].Style);
}
CFile::moveFile(download.dest, download.tmpdest);
}
}
catch(const NLMISC::Exception &e)
{
// exception message has .tmp file name, so keep it for further analysis
nlwarning("Invalid image (%s) from url (%s): %s", download.tmpdest.c_str(), download.url.c_str(), e.what());
}
}
if (CFile::fileExists(download.dest) && CFile::getFileSize(download.dest) > 0)
{
try
{
// verify that image is not corrupted
uint32 w, h;
CBitmap::loadSize(download.dest, w, h);
if (w != 0 && h != 0)
for(uint i = 0; i < download.imgs.size(); i++)
{
setImage(download.imgs[i].Image, download.dest, download.imgs[i].Type);
setImageSize(download.imgs[i].Image, download.imgs[i].Style);
}
}
catch(const NLMISC::Exception &e)
{
nlwarning("Invalid image (%s) from url (%s): %s", download.dest.c_str(), download.url.c_str(), e.what());
}
}
return;
}
if (download.type == StylesheetType)
{
if (CFile::fileExists(download.tmpdest))
{
if (CFile::fileExists(download.dest))
{
CFile::deleteFile(download.dest);
}
CFile::moveFile(download.dest, download.tmpdest);
}
cssDownloadFinished(download.url, download.dest);
return;
}
if (download.type == BnpType)
{
bool verified = false;
// no tmpfile if file was already in cache
if (CFile::fileExists(download.tmpdest))
{ {
verified = download.md5sum.empty() || (download.md5sum != getMD5(download.tmpdest).toString()); if (download)
if (verified)
{
if (CFile::fileExists(download.dest))
{ {
CFile::deleteFile(download.dest); download->finish();
} delete download;
CFile::moveFile(download.dest, download.tmpdest);
} }
else else
{ {
CFile::deleteFile(download.tmpdest); nlwarning("Unknown CURL download (nullptr)");
}
}
else if (CFile::fileExists(download.dest))
{
verified = download.md5sum.empty() || (download.md5sum != getMD5(download.dest).toString());
}
std::string script = "\nlocal __CURRENT_WINDOW__ = \""+this->_Id+"\"";
script += toString("\nlocal __DOWNLOAD_STATUS__ = %s\n", verified ? "true" : "false");
script += download.luaScript;
CLuaManager::getInstance().executeLuaScript(script, true );
return;
} }
nlwarning("Unknown CURL download type (%d) finished '%s'", download.type, download.url.c_str());
} }
// Add a image download request in the multi_curl // Add a image download request in the multi_curl
void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type, const std::string &placeholder) ICurlDownloadCB *CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type, const std::string &placeholder)
{ {
std::string finalUrl; std::string finalUrl;
img->setModulateGlobalColor(style.GlobalColor); img->setModulateGlobalColor(style.GlobalColor);
@ -728,7 +745,7 @@ namespace NLGUI
{ {
setImage(img, decodeURIComponent(url), type); setImage(img, decodeURIComponent(url), type);
setImageSize(img, style); setImageSize(img, style);
return; return NULL;
} }
// load the image from local files/bnp // load the image from local files/bnp
@ -737,7 +754,7 @@ namespace NLGUI
{ {
setImage(img, image, type); setImage(img, image, type);
setImageSize(img, style); setImageSize(img, style);
return; return NULL;
} }
finalUrl = upgradeInsecureUrl(getAbsoluteUrl(url)); finalUrl = upgradeInsecureUrl(getAbsoluteUrl(url));
@ -759,36 +776,40 @@ namespace NLGUI
} }
// Search if we are not already downloading this url. // Search if we are not already downloading this url.
for(std::list<CDataDownload>::iterator it = Curls.begin(); it != Curls.end(); ++it) for(std::list<CDataDownload*>::iterator it = Curls.begin(); it != Curls.end(); ++it)
{ {
if(it->url == finalUrl) if((*it)->url == finalUrl)
{ {
LOG_DL("already downloading '%s' img %p", finalUrl.c_str(), img); LOG_DL("already downloading '%s' img %p", finalUrl.c_str(), img);
it->imgs.push_back(CDataImageDownload(img, style, type)); ImageDownloadCB *cb = dynamic_cast<ImageDownloadCB*>(*it);
return; if (cb)
{
cb->addImage(img, style, type);
// return pointer to shared ImageDownloadCB
return cb;
}
else
{
nlwarning("Found image download '%s', but casting to ImageDownloadCB failed", finalUrl.c_str());
}
} }
} }
Curls.push_back(CDataDownload(finalUrl, dest, ImgType, img, "", "", style, type)); Curls.push_back(new ImageDownloadCB(finalUrl, dest, img, style, type, this));
pumpCurlQueue(); // as we return pointer to callback, skip starting downloads just now
//pumpCurlQueue();
return Curls.back();
} }
void CGroupHTML::removeImageDownload(CViewBase *img) void CGroupHTML::removeImageDownload(ICurlDownloadCB *handle, CViewBase *img)
{
for(std::list<CDataDownload>::iterator it = Curls.begin(); it != Curls.end(); ++it)
{
// check all active downloads because image does not keep url around
std::vector<CDataImageDownload>::iterator imgIter = it->imgs.begin();
while(imgIter != it->imgs.end())
{ {
if (imgIter->Image == img) ImageDownloadCB *cb = dynamic_cast<ImageDownloadCB*>(handle);
{ if (!cb) {
it->imgs.erase(imgIter); nlwarning("Trying to remove image from downloads, but ICurlDownloadCB pointer did not cast to ImageDownloadCB");
break; return;
}
++imgIter;
}
} }
// image will be removed from handle, but handle is kept and image will be downloaded
cb->removeImage(img);
} }
void CGroupHTML::initImageDownload() void CGroupHTML::initImageDownload()
@ -815,9 +836,9 @@ namespace NLGUI
url = upgradeInsecureUrl(getAbsoluteUrl(url)); url = upgradeInsecureUrl(getAbsoluteUrl(url));
// Search if we are not already downloading this url. // Search if we are not already downloading this url.
for(std::list<CDataDownload>::const_iterator it = Curls.begin(); it != Curls.end(); ++it) for(std::list<CDataDownload*>::const_iterator it = Curls.begin(); it != Curls.end(); ++it)
{ {
if(it->url == url) if((*it)->url == url)
{ {
LOG_DL("already downloading '%s'", url.c_str()); LOG_DL("already downloading '%s'", url.c_str());
return false; return false;
@ -842,7 +863,7 @@ namespace NLGUI
} }
if (action != "delete") if (action != "delete")
{ {
Curls.push_back(CDataDownload(url, dest, BnpType, NULL, script, md5sum)); Curls.push_back(new BnpDownloadCB(url, dest, md5sum, script, this));
pumpCurlQueue(); pumpCurlQueue();
} }
else else
@ -871,7 +892,7 @@ namespace NLGUI
_StylesheetQueue.back().Url = url; _StylesheetQueue.back().Url = url;
// push to the front of the queue // push to the front of the queue
Curls.push_front(CDataDownload(url, localImageName(url), StylesheetType, NULL, "", "")); Curls.push_front(new StylesheetDownloadCB(url, localImageName(url), this));
} }
pumpCurlQueue(); pumpCurlQueue();
} }
@ -915,9 +936,9 @@ namespace NLGUI
} }
else else
{ {
for(std::list<CDataDownload>::iterator it = Curls.begin(); it != Curls.end(); ++it) for(std::list<CDataDownload*>::iterator it = Curls.begin(); it != Curls.end(); ++it)
{ {
if(it->data && it->data->Request == msg->easy_handle) if((*it)->data && (*it)->data->Request == msg->easy_handle)
{ {
std::string error; std::string error;
bool success = msg->data.result == CURLE_OK; bool success = msg->data.result == CURLE_OK;
@ -956,27 +977,30 @@ namespace NLGUI
} }
// remove all queued and already started downloads // remove all queued and already started downloads
for(std::list<CDataDownload>::iterator it = Curls.begin(); it != Curls.end(); ++it) for(std::list<CDataDownload*>::iterator it = Curls.begin(); it != Curls.end(); ++it)
{ {
if (it->data) CDataDownload &dl = *(*it);
if (dl.data)
{ {
LOG_DL("(%s) stop data url '%s'", _Id.c_str(), it->url.c_str()); LOG_DL("(%s) stop data url '%s'", _Id.c_str(), dl.url.c_str());
if (MultiCurl) if (MultiCurl)
{ {
curl_multi_remove_handle(MultiCurl, it->data->Request); curl_multi_remove_handle(MultiCurl, dl.data->Request);
} }
// close and remove temp file // close and remove temp file
if (it->fp) if (dl.fp)
{ {
fclose(it->fp); fclose(dl.fp);
if (CFile::fileExists(it->tmpdest)) if (CFile::fileExists(dl.tmpdest))
{ {
CFile::deleteFile(it->tmpdest); CFile::deleteFile(dl.tmpdest);
} }
} }
} }
// release CDataDownload
delete *it;
} }
Curls.clear(); Curls.clear();
@ -2935,10 +2959,10 @@ namespace NLGUI
LOG_DL("Clear pointers to %d curls", Curls.size()); LOG_DL("Clear pointers to %d curls", Curls.size());
// remove image refs from downloads // remove image refs from downloads
for(std::list<CDataDownload>::iterator it = Curls.begin(); it != Curls.end(); ++it) /*for(std::list<CDataDownload>::iterator it = Curls.begin(); it != Curls.end(); ++it)
{ {
it->imgs.clear(); it->imgs.clear();
} }*/
} }
// *************************************************************************** // ***************************************************************************
@ -3691,96 +3715,98 @@ namespace NLGUI
updateRefreshButton(); updateRefreshButton();
} }
void CGroupHTML::dataDownloadFinished(bool success, const std::string &error, CDataDownload &data) void CGroupHTML::dataDownloadFinished(bool success, const std::string &error, CDataDownload *data)
{ {
fclose(data.fp); fclose(data->fp);
CUrlParser uri(data.url); CUrlParser uri(data->url);
if (!uri.host.empty()) if (!uri.host.empty())
{ {
receiveCookies(data.data->Request, uri.host, isTrustedDomain(uri.host)); receiveCookies(data->data->Request, uri.host, isTrustedDomain(uri.host));
} }
long code = -1; long code = -1;
curl_easy_getinfo(data.data->Request, CURLINFO_RESPONSE_CODE, &code); curl_easy_getinfo(data->data->Request, CURLINFO_RESPONSE_CODE, &code);
LOG_DL("(%s) transfer '%p' completed with http code %d, url (len %d) '%s'", _Id.c_str(), data.data->Request, code, data.url.size(), data.url.c_str()); LOG_DL("(%s) transfer '%p' completed with http code %d, url (len %d) '%s'", _Id.c_str(), data->data->Request, code, data->url.size(), data->url.c_str());
curl_multi_remove_handle(MultiCurl, data.data->Request); curl_multi_remove_handle(MultiCurl, data->data->Request);
// save HSTS header from all requests regardless of HTTP code // save HSTS header from all requests regardless of HTTP code
if (success) if (success)
{ {
if (data.data->hasHSTSHeader()) if (data->data->hasHSTSHeader())
{ {
CStrictTransportSecurity::getInstance()->setFromHeader(uri.host, data.data->getHSTSHeader()); CStrictTransportSecurity::getInstance()->setFromHeader(uri.host, data->data->getHSTSHeader());
} }
// 2XX success, 304 Not Modified // 2XX success, 304 Not Modified
if ((code >= 200 && code <= 204) || code == 304) if ((code >= 200 && code <= 204) || code == 304)
{ {
CHttpCacheObject obj; CHttpCacheObject obj;
obj.Expires = data.data->getExpires(); obj.Expires = data->data->getExpires();
obj.Etag = data.data->getEtag(); obj.Etag = data->data->getEtag();
obj.LastModified = data.data->getLastModified(); obj.LastModified = data->data->getLastModified();
CHttpCache::getInstance()->store(data.dest, obj); CHttpCache::getInstance()->store(data->dest, obj);
if (code == 304 && CFile::fileExists(data.tmpdest)) if (code == 304 && CFile::fileExists(data->tmpdest))
{ {
CFile::deleteFile(data.tmpdest); CFile::deleteFile(data->tmpdest);
} }
} }
else if ((code >= 301 && code <= 303) || code == 307 || code == 308) else if ((code >= 301 && code <= 303) || code == 307 || code == 308)
{ {
if (data.redirects < DEFAULT_RYZOM_REDIRECT_LIMIT) if (data->redirects < DEFAULT_RYZOM_REDIRECT_LIMIT)
{ {
std::string location(data.data->getLocationHeader()); std::string location(data->data->getLocationHeader());
if (!location.empty()) if (!location.empty())
{ {
CUrlParser uri(location); CUrlParser uri(location);
if (!uri.isAbsolute()) if (!uri.isAbsolute())
{ {
uri.inherit(data.url); uri.inherit(data->url);
location = uri.toString(); location = uri.toString();
} }
// clear old request state, and curl easy handle
delete data->data;
data->data = NULL;
data->fp = NULL;
data->url = location;
data->redirects++;
// push same request in the front of the queue // push same request in the front of the queue
// cache filename is based of original url // cache filename is based of original url
Curls.push_front(data); Curls.push_front(data);
// clear old request state
Curls.front().data = NULL;
Curls.front().fp = NULL;
Curls.front().url = location;
Curls.front().redirects++;
LOG_DL("Redirect '%s'", location.c_str()); LOG_DL("Redirect '%s'", location.c_str());
// no finished callback called, so cleanup old temp // no finished callback called, so cleanup old temp
if (CFile::fileExists(data.tmpdest)) if (CFile::fileExists(data->tmpdest))
{ {
CFile::deleteFile(data.tmpdest); CFile::deleteFile(data->tmpdest);
} }
return; return;
} }
nlwarning("Redirected to empty url '%s'", data.url.c_str()); nlwarning("Redirected to empty url '%s'", data->url.c_str());
} }
else else
{ {
nlwarning("Redirect limit reached for '%s'", data.url.c_str()); nlwarning("Redirect limit reached for '%s'", data->url.c_str());
} }
} }
else else
{ {
nlwarning("HTTP request failed with code [%d] for '%s'\n",code, data.url.c_str()); nlwarning("HTTP request failed with code [%d] for '%s'\n",code, data->url.c_str());
// 404, 500, etc // 404, 500, etc
if (CFile::fileExists(data.dest)) if (CFile::fileExists(data->dest))
{ {
CFile::deleteFile(data.dest); CFile::deleteFile(data->dest);
} }
} }
} }
else else
{ {
nlwarning("DATA download failed '%s', error '%s'", data.url.c_str(), error.c_str()); nlwarning("DATA download failed '%s', error '%s'", data->url.c_str(), error.c_str());
} }
finishCurlDownload(data); finishCurlDownload(data);

@ -46,8 +46,8 @@ namespace NLGUI
{ {
CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:webig:content:html")); CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:webig:content:html"));
if (groupHtml) { if (groupHtml) {
_HtmlDownload = false; groupHtml->removeImageDownload(_HtmlDownload, dynamic_cast<CViewBase*>(this));
groupHtml->removeImageDownload(dynamic_cast<CViewBase*>(this)); _HtmlDownload = NULL;
} }
} }
} }
@ -476,13 +476,15 @@ namespace NLGUI
if (!CFile::fileExists(localname)) if (!CFile::fileExists(localname))
localname = "web_del.tga"; localname = "web_del.tga";
_TextureId.setTexture (localname.c_str(), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false); _TextureId.setTexture (localname.c_str(), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false);
_HtmlDownload = true; _HtmlDownload = groupHtml->addImageDownload(TxName, dynamic_cast<CViewBase*>(this));
groupHtml->addImageDownload(TxName, dynamic_cast<CViewBase*>(this));
} }
} }
else else
{
_HtmlDownload = NULL;
_TextureId.setTexture (TxName.c_str (), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false); _TextureId.setTexture (TxName.c_str (), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false);
} }
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
std::string CViewBitmap::getTexture () const std::string CViewBitmap::getTexture () const

Loading…
Cancel
Save