Fixed a libcurl memory leak in the scraper.

This commit is contained in:
Leon Styhre 2020-10-18 11:01:56 +02:00
parent da37e2c11a
commit 923d1df479
5 changed files with 28 additions and 22 deletions

View file

@ -43,7 +43,8 @@ GuiScraperSearch::GuiScraperSearch(
mBusyAnim(window), mBusyAnim(window),
mSearchType(type), mSearchType(type),
mScrapeCount(scrapeCount), mScrapeCount(scrapeCount),
mScrapeRatings(false) mScrapeRatings(false),
mFoundGame(false)
{ {
addChild(&mGrid); addChild(&mGrid);
@ -124,6 +125,11 @@ GuiScraperSearch::GuiScraperSearch(
updateViewStyle(); updateViewStyle();
} }
GuiScraperSearch::~GuiScraperSearch()
{
HttpReq::cleanupCurlMulti();
}
void GuiScraperSearch::onSizeChanged() void GuiScraperSearch::onSizeChanged()
{ {
mGrid.setSize(mSize); mGrid.setSize(mSize);

View file

@ -38,6 +38,7 @@ public:
}; };
GuiScraperSearch(Window* window, SearchType searchType, unsigned int scrapeCount = 1); GuiScraperSearch(Window* window, SearchType searchType, unsigned int scrapeCount = 1);
~GuiScraperSearch();
void search(const ScraperSearchParams& params); void search(const ScraperSearchParams& params);
void openInputScreen(ScraperSearchParams& from); void openInputScreen(ScraperSearchParams& from);

View file

@ -16,8 +16,7 @@
#include <assert.h> #include <assert.h>
CURLM* HttpReq::s_multi_handle = curl_multi_init(); CURLM* HttpReq::s_multi_handle;
std::map<CURL*, HttpReq*> HttpReq::s_requests; std::map<CURL*, HttpReq*> HttpReq::s_requests;
std::string HttpReq::urlEncode(const std::string &s) std::string HttpReq::urlEncode(const std::string &s)
@ -50,6 +49,12 @@ bool HttpReq::isUrl(const std::string& str)
HttpReq::HttpReq(const std::string& url) : mStatus(REQ_IN_PROGRESS), mHandle(nullptr) HttpReq::HttpReq(const std::string& url) : mStatus(REQ_IN_PROGRESS), mHandle(nullptr)
{ {
// The multi-handle is cleaned up via a call from GuiScraperSearch after the scraping
// has been completed for a game, meaning the handle is valid for all cURL requests
// performed for the current game.
if (!s_multi_handle)
s_multi_handle = curl_multi_init();
mHandle = curl_easy_init(); mHandle = curl_easy_init();
// On Windows, use the bundled cURL TLS/SSL certificates (which actually come from the // On Windows, use the bundled cURL TLS/SSL certificates (which actually come from the
@ -200,14 +205,8 @@ std::string HttpReq::getErrorMsg()
// Return value is number of elements successfully read. // Return value is number of elements successfully read.
size_t HttpReq::write_content(void* buff, size_t size, size_t nmemb, void* req_ptr) size_t HttpReq::write_content(void* buff, size_t size, size_t nmemb, void* req_ptr)
{ {
std::stringstream& ss = ((HttpReq*)req_ptr)->mContent; std::stringstream& ss = (static_cast<HttpReq*>(req_ptr))->mContent;
ss.write((char*)buff, size * nmemb); ss.write(static_cast<char*>(buff), size * nmemb);
return nmemb; return nmemb;
} }
// Used as a curl callback.
//int HttpReq::update_progress(void* req_ptr, double dlTotal,
// double dlNow, double ulTotal, double ulNow)
//{
//}

View file

@ -40,31 +40,34 @@ class HttpReq
{ {
public: public:
HttpReq(const std::string& url); HttpReq(const std::string& url);
~HttpReq(); ~HttpReq();
enum Status { enum Status {
REQ_IN_PROGRESS, // Request is in progress. REQ_IN_PROGRESS, // Request is in progress.
REQ_SUCCESS, // Request completed successfully, get it with getContent(). REQ_SUCCESS, // Request completed successfully, get it with getContent().
REQ_IO_ERROR, // Some error happened, get it with getErrorMsg(). REQ_IO_ERROR, // Some error happened, get it with getErrorMsg().
REQ_BAD_STATUS_CODE, // Some invalid HTTP response status code happened (non-200). REQ_BAD_STATUS_CODE, // Some invalid HTTP response status code happened (non-200).
REQ_INVALID_RESPONSE // The HTTP response was invalid. REQ_INVALID_RESPONSE // The HTTP response was invalid.
}; };
Status status(); // Process any received data and return the status afterwards. Status status(); // Process any received data and return the status afterwards.
std::string getErrorMsg(); std::string getErrorMsg();
std::string getContent() const; // mStatus must be REQ_SUCCESS. std::string getContent() const; // mStatus must be REQ_SUCCESS.
static std::string urlEncode(const std::string &s); static std::string urlEncode(const std::string &s);
static bool isUrl(const std::string& s); static bool isUrl(const std::string& s);
static void cleanupCurlMulti()
{
if (s_multi_handle != nullptr) {
curl_multi_cleanup(s_multi_handle);
s_multi_handle = nullptr;
}
};
private: private:
static size_t write_content(void* buff, size_t size, size_t nmemb, void* req_ptr); static size_t write_content(void* buff, size_t size, size_t nmemb, void* req_ptr);
//static int update_progress(void* req_ptr, double dlTotal, double dlNow, void onError(const char* msg);
// double ulTotal, double ulNow);
// God dammit libcurl why can't you have some way to check the status of an // God dammit libcurl why can't you have some way to check the status of an
// individual handle why do I have to handle ALL messages at once. // individual handle why do I have to handle ALL messages at once.
@ -72,10 +75,7 @@ private:
static CURLM* s_multi_handle; static CURLM* s_multi_handle;
void onError(const char* msg);
CURL* mHandle; CURL* mHandle;
Status mStatus; Status mStatus;
std::stringstream mContent; std::stringstream mContent;