From 774a752bed88e7d1fdc6245cb031acf042f828e8 Mon Sep 17 00:00:00 2001 From: New Pagodi Date: Sun, 7 Feb 2021 00:48:02 -0600 Subject: [PATCH] Track active transfers in wxWebSessionCURL class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At various points in a transfer being managed by the wxWebSessionCURL class we need to perform operations on a wxWebRequestCURL object. However it’s possible for the request object to be deleted while the transfer is in progress. To ensure that the request objects are valid, keep track of the request objects with a hash map. Objects are added to the map when a transfer is started and removed when the transfer is complete or in the request’s destructor. --- include/wx/private/webrequest_curl.h | 8 +++++ src/common/webrequest_curl.cpp | 49 +++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/include/wx/private/webrequest_curl.h b/include/wx/private/webrequest_curl.h index 25b90a80ba..dd1e4bf4ea 100644 --- a/include/wx/private/webrequest_curl.h +++ b/include/wx/private/webrequest_curl.h @@ -17,6 +17,7 @@ #include "wx/thread.h" #include "wx/vector.h" #include "wx/timer.h" +#include "wx/hashmap.h" #include "curl/curl.h" @@ -151,6 +152,8 @@ public: void CancelRequest(wxWebRequestCURL* request); + void RequestHasTerminated(wxWebRequestCURL* request); + static bool CurlRuntimeAtLeastVersion(unsigned int, unsigned int, unsigned int); @@ -165,6 +168,11 @@ private: void ProcessSocketPollerResult(wxThreadEvent&); void CheckForCompletedTransfers(); + WX_DECLARE_HASH_MAP(CURL*, wxWebRequestCURL*, wxPointerHash, \ + wxPointerEqual, TransferSet); + + TransferSet m_activeTransfers; + SocketPoller* m_socketPoller; wxTimer m_timeoutTimer; CURLM* m_handle; diff --git a/src/common/webrequest_curl.cpp b/src/common/webrequest_curl.cpp index 417541b9cf..d608192cc8 100644 --- a/src/common/webrequest_curl.cpp +++ b/src/common/webrequest_curl.cpp @@ -240,8 +240,6 @@ wxWebRequestCURL::wxWebRequestCURL(wxWebSession & session, // Set error buffer to get more detailed CURL status m_errorBuffer[0] = '\0'; curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_errorBuffer); - // Set this request in the private pointer - curl_easy_setopt(m_handle, CURLOPT_PRIVATE, static_cast(this)); // Set URL to handle: note that we must use wxURI to escape characters not // allowed in the URLs correctly (URL API is only available in libcurl // since the relatively recent v7.62.0, so we don't want to rely on it). @@ -266,8 +264,7 @@ wxWebRequestCURL::wxWebRequestCURL(wxWebSession & session, wxWebRequestCURL::~wxWebRequestCURL() { DestroyHeaderList(); - - curl_easy_cleanup(m_handle); + m_sessionImpl.RequestHasTerminated(this); } void wxWebRequestCURL::Start() @@ -1004,6 +1001,7 @@ bool wxWebSessionCURL::StartRequest(wxWebRequestCURL & request) if ( code == CURLM_OK ) { request.SetState(wxWebRequest::State_Active); + m_activeTransfers[curl] = &request; // Report a timeout to curl to initiate this transfer. int runningHandles; @@ -1020,10 +1018,37 @@ bool wxWebSessionCURL::StartRequest(wxWebRequestCURL & request) void wxWebSessionCURL::CancelRequest(wxWebRequestCURL* request) { - curl_multi_remove_handle(m_handle, request->GetHandle()); + CURL* curl = request->GetHandle(); + TransferSet::iterator it = m_activeTransfers.find(curl); + + if ( it != m_activeTransfers.end() ) + { + m_activeTransfers.erase(it); + } + + curl_multi_remove_handle(m_handle, curl); request->SetState(wxWebRequest::State_Cancelled); } +void wxWebSessionCURL::RequestHasTerminated(wxWebRequestCURL* request) +{ + CURL* curl = request->GetHandle(); + TransferSet::iterator it = m_activeTransfers.find(curl); + + if ( it != m_activeTransfers.end() ) + { + // The transfer the CURL handle is performing is still in progress, but + // the web request object it belongs to is being deleted. Since the + // next step will call curl_easy_cleanup and any calls on the CURL + // handle after cleanup are illegal, remove it from the CURLM + // multihandle now. + curl_multi_remove_handle(m_handle, curl); + m_activeTransfers.erase(it); + } + + curl_easy_cleanup(curl); +} + wxVersionInfo wxWebSessionCURL::GetLibraryVersionInfo() { const curl_version_info_data* vi = curl_version_info(CURLVERSION_NOW); @@ -1196,10 +1221,16 @@ void wxWebSessionCURL::CheckForCompletedTransfers() { if ( msg->msg == CURLMSG_DONE ) { - wxWebRequestCURL* request; - curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &request); - curl_multi_remove_handle(m_handle, msg->easy_handle); - request->HandleCompletion(); + CURL* curl = msg->easy_handle; + TransferSet::iterator it = m_activeTransfers.find(curl); + + if ( it != m_activeTransfers.end() ) + { + wxWebRequestCURL* request = it->second; + curl_multi_remove_handle(m_handle, curl); + request->HandleCompletion(); + m_activeTransfers.erase(it); + } } } }