From 48cba4f88e7299899d0ed44929aff8d259aec6a7 Mon Sep 17 00:00:00 2001 From: New Pagodi Date: Sun, 7 Feb 2021 20:43:51 -0600 Subject: [PATCH] Set wxWebResponseCURL buffer size as soon as known Currently for wxWebRequestCURL objects using memory storage, a download is processed by appending to a wxMemoryBuffer each time the write callback is called. For a large transfer, this can result in many, many reallocation calls and can block the main application. This commit uses the progress callback for wxWebRequestCURL objects added in a previous commit to set a minimum size for the buffer as soon as it is known. --- include/wx/private/webrequest.h | 4 ++++ include/wx/private/webrequest_curl.h | 3 ++- src/common/webrequest.cpp | 5 +++++ src/common/webrequest_curl.cpp | 17 ++++++++++++++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/wx/private/webrequest.h b/include/wx/private/webrequest.h index 0812304fac..497bbfc170 100644 --- a/include/wx/private/webrequest.h +++ b/include/wx/private/webrequest.h @@ -187,6 +187,10 @@ protected: void ReportDataReceived(size_t sizeReceived); + // This function can optionally be called to preallocate the read buffer, + // if the total amount of data to be downloaded is known in advance. + void PreAllocBuffer(size_t sizeNeeded); + private: // Called by wxWebRequestImpl only. friend class wxWebRequestImpl; diff --git a/include/wx/private/webrequest_curl.h b/include/wx/private/webrequest_curl.h index d0e2f8a5d7..25b90a80ba 100644 --- a/include/wx/private/webrequest_curl.h +++ b/include/wx/private/webrequest_curl.h @@ -114,11 +114,12 @@ public: // Methods called from libcurl callbacks size_t CURLOnWrite(void *buffer, size_t size); size_t CURLOnHeader(const char* buffer, size_t size); - int CURLOnProgress(); + int CURLOnProgress(curl_off_t); private: wxWebRequestHeaderMap m_headers; wxString m_statusText; + wxFileOffset m_knownDownloadSize; CURL* GetHandle() const { return static_cast(m_request).GetHandle(); } diff --git a/src/common/webrequest.cpp b/src/common/webrequest.cpp index 351a4b76ae..70dbf7232b 100644 --- a/src/common/webrequest.cpp +++ b/src/common/webrequest.cpp @@ -688,6 +688,11 @@ void* wxWebResponseImpl::GetDataBuffer(size_t sizeNeeded) return m_readBuffer.GetAppendBuf(sizeNeeded); } +void wxWebResponseImpl::PreAllocBuffer(size_t sizeNeeded) +{ + m_readBuffer.SetBufSize(sizeNeeded); +} + void wxWebResponseImpl::ReportDataReceived(size_t sizeReceived) { m_readBuffer.UngetAppendBuf(sizeReceived); diff --git a/src/common/webrequest_curl.cpp b/src/common/webrequest_curl.cpp index d247e844af..f8d2aac47d 100644 --- a/src/common/webrequest_curl.cpp +++ b/src/common/webrequest_curl.cpp @@ -67,7 +67,7 @@ static size_t wxCURLHeader(char *buffer, size_t size, size_t nitems, void *userd return static_cast(userdata)->CURLOnHeader(buffer, size * nitems); } -int wxCURLXferInfo(void* clientp, curl_off_t WXUNUSED(dltotal), +int wxCURLXferInfo(void* clientp, curl_off_t dltotal, curl_off_t WXUNUSED(dlnow), curl_off_t WXUNUSED(ultotal), curl_off_t WXUNUSED(ulnow)) @@ -75,7 +75,7 @@ int wxCURLXferInfo(void* clientp, curl_off_t WXUNUSED(dltotal), wxCHECK_MSG( clientp, 0, "invalid curl progress callback data" ); wxWebResponseCURL* response = reinterpret_cast(clientp); - return response->CURLOnProgress(); + return response->CURLOnProgress(dltotal); } int wxCURLProgress(void* clientp, double dltotal, double dlnow, double ultotal, @@ -90,6 +90,8 @@ int wxCURLProgress(void* clientp, double dltotal, double dlnow, double ultotal, wxWebResponseCURL::wxWebResponseCURL(wxWebRequestCURL& request) : wxWebResponseImpl(request) { + m_knownDownloadSize = 0; + curl_easy_setopt(GetHandle(), CURLOPT_WRITEDATA, static_cast(this)); curl_easy_setopt(GetHandle(), CURLOPT_HEADERDATA, static_cast(this)); @@ -152,8 +154,17 @@ size_t wxWebResponseCURL::CURLOnHeader(const char * buffer, size_t size) return size; } -int wxWebResponseCURL::CURLOnProgress() +int wxWebResponseCURL::CURLOnProgress(curl_off_t total) { + if ( m_knownDownloadSize != total ) + { + if ( m_request.GetStorage() == wxWebRequest::Storage_Memory ) + { + PreAllocBuffer(static_cast(total)); + } + m_knownDownloadSize = total; + } + return 0; }