Browse Source

💩 Remove Update Check

pull/2/head
Cookie Engineer 1 year ago
parent
commit
5728dd542f
No known key found for this signature in database GPG Key ID: 340F6A4848C5F849
  1. 22
      CMakeLists.txt
  2. 17
      cmake-proxies/CMakeLists.txt
  3. 43
      libraries/lib-network-manager/CMakeLists.txt
  4. 215
      libraries/lib-network-manager/CookiesList.cpp
  5. 78
      libraries/lib-network-manager/CookiesList.h
  6. 158
      libraries/lib-network-manager/HeadersList.cpp
  7. 69
      libraries/lib-network-manager/HeadersList.h
  8. 109
      libraries/lib-network-manager/IResponse.h
  9. 49
      libraries/lib-network-manager/IResponseFactory.h
  10. 79
      libraries/lib-network-manager/NetworkManager.cpp
  11. 49
      libraries/lib-network-manager/NetworkManager.h
  12. 31
      libraries/lib-network-manager/NetworkManagerApi.h
  13. 115
      libraries/lib-network-manager/Request.cpp
  14. 75
      libraries/lib-network-manager/Request.h
  15. 349
      libraries/lib-network-manager/curl/CurlHandleManager.cpp
  16. 127
      libraries/lib-network-manager/curl/CurlHandleManager.h
  17. 382
      libraries/lib-network-manager/curl/CurlResponse.cpp
  18. 98
      libraries/lib-network-manager/curl/CurlResponse.h
  19. 80
      libraries/lib-network-manager/curl/CurlResponseFactory.cpp
  20. 46
      libraries/lib-network-manager/curl/CurlResponseFactory.h
  21. 54
      libraries/lib-network-manager/curl/CurlStringList.cpp
  22. 42
      libraries/lib-network-manager/curl/CurlStringList.h
  23. 3
      linux/build-environment/entrypoint.sh
  24. 2
      scripts/ci/configure.sh
  25. 13
      src/AudacityApp.cpp
  26. 18
      src/CMakeLists.txt
  27. 1
      src/prefs/ApplicationPrefs.cpp
  28. 153
      src/update/UpdateDataParser.cpp
  29. 66
      src/update/UpdateDataParser.h
  30. 153
      src/update/UpdateManager.cpp
  31. 58
      src/update/UpdateManager.h
  32. 136
      src/update/UpdatePopupDialog.cpp
  33. 38
      src/update/UpdatePopupDialog.h
  34. 71
      src/update/VersionId.cpp
  35. 49
      src/update/VersionId.h
  36. 23
      src/update/VersionPatch.h

22
CMakeLists.txt

@ -151,10 +151,6 @@ cmd_option( ${_OPT}obey_system_dependencies
Off
)
cmd_option( ${_OPT}has_networking
"Build networking features into Audacity"
Off)
include( AudacityDependencies )
# Pull all the modules we'll need
@ -170,24 +166,6 @@ include( CMakePushCheckState )
include( GNUInstallDirs )
include( TestBigEndian )
set_from_env(CRASH_REPORT_URL)
cmake_dependent_option(
${_OPT}has_crashreports
"Enables crash reporting for Audacity"
On
"${_OPT}has_networking;DEFINED CRASH_REPORT_URL"
Off
)
cmake_dependent_option(
${_OPT}has_updates_check
"Build updates checking features into Audacity"
On
"${_OPT}has_networking"
Off
)
# Determine 32-bit or 64-bit target
if( CMAKE_C_COMPILER_ID MATCHES "MSVC" AND CMAKE_VS_PLATFORM_NAME MATCHES "Win64|x64" )
set( IS_64BIT ON )

17
cmake-proxies/CMakeLists.txt

@ -120,23 +120,6 @@ add_conan_lib(
ALWAYS_ALLOW_CONAN_FALLBACK
)
if( ${_OPT}has_networking )
add_conan_lib(
CURL
libcurl/7.75.0
REQUIRED
OPTION_NAME curl
PKG_CONFIG "libcurl >= 7.68.0"
INTERFACE_NAME CURL::libcurl
FIND_PACKAGE_OPTIONS
CONAN_OPTIONS
libcurl:with_ssl=${curl_ssl}
libcurl:shared=True
)
endif()
if( NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows")
add_conan_lib(
libuuid

43
libraries/lib-network-manager/CMakeLists.txt

@ -1,43 +0,0 @@
set(TARGET lib-network-manager)
set( TARGET_ROOT ${CMAKE_CURRENT_SOURCE_DIR} )
def_vars()
set( SOURCES
IResponse.h
IResponseFactory.h
HeadersList.h
HeadersList.cpp
CookiesList.h
CookiesList.cpp
Request.h
Request.cpp
NetworkManager.h
NetworkManager.cpp
curl/CurlResponse.h
curl/CurlResponse.cpp
curl/CurlResponseFactory.h
curl/CurlResponseFactory.cpp
curl/CurlStringList.h
curl/CurlStringList.cpp
curl/CurlHandleManager.h
curl/CurlHandleManager.cpp
)
set ( LIBRARIES PRIVATE
CURL::libcurl
ThreadPool::ThreadPool
lib-string-utils
wxwidgets::base
)
set ( DEFINES INTERFACE "HAS_NETWORKING" )
audacity_library( ${TARGET} "${SOURCES}" "${LIBRARIES}" "${DEFINES}" "" )

215
libraries/lib-network-manager/CookiesList.cpp

@ -1,215 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file CookiesList.cpp
@brief Define HTTP cookies list class.
Dmitry Vedenko
**********************************************************************/
/*!********************************************************************
@class Cookie
@brief A struct, representing a Cookie object.
**********************************************************************/
/*!********************************************************************
@class CookiesList
@brief A class, representing a list of HTTP cookies.
**********************************************************************/
#include "CookiesList.h"
#include <sstream>
#include <cstring>
#include <algorithm>
#include "DateTimeConversions.h"
namespace audacity
{
namespace network_manager
{
Cookie Cookie::Parse (const std::string& cookieString)
{
const size_t equalsPosition = cookieString.find ('=');
if (equalsPosition == std::string::npos)
return { cookieString, std::string () };
std::string name = cookieString.substr (0, equalsPosition);
const size_t firstValueIndex = equalsPosition + 1;
const size_t semicolonPosition = cookieString.find (';', firstValueIndex);
Cookie cookie;
cookie.Name = std::move (name);
cookie.Value = semicolonPosition == std::string::npos ?
cookieString.substr (firstValueIndex) :
cookieString.substr (firstValueIndex, semicolonPosition - firstValueIndex);
size_t expiresPosition = cookieString.find("Expires=");
if (expiresPosition != std::string::npos)
{
expiresPosition += std::strlen ("Expires=");
const size_t trailingSemicolon = cookieString.find (';', expiresPosition);
std::string expiresValue =
trailingSemicolon == std::string::npos ?
cookieString.substr (expiresPosition) :
cookieString.substr (expiresPosition, trailingSemicolon - expiresPosition);
// Hack around Yandex violating RFC
std::replace (expiresValue.begin(), expiresValue.end(), '-', ' ');
ParseRFC822Date (expiresValue, &cookie.Expires);
}
return cookie;
}
bool Cookie::isSession () const noexcept
{
return Expires == ExpiresTime {};
}
std::string Cookie::toString (bool fullString) const
{
std::ostringstream stream;
stream << Name << "=" << Value;
if (fullString)
{
if (!isSession())
stream << "; " << "Expires=" << SerializeRFC822Date(Expires);
}
return stream.str ();
}
bool Cookie::isExpired () const noexcept
{
return !isSession() &&
std::chrono::system_clock::now() >= Expires;
}
void CookiesList::setCookie (const Cookie& cookie)
{
setCookie (cookie.Name, cookie.Value);
}
void CookiesList::setCookie (const std::string& cookieName, std::string cookieValue)
{
Cookie* item = getCookie (cookieName);
if (item != nullptr)
item->Value = std::move (cookieValue);
else
mCookies.push_back ({ cookieName, std::move (cookieValue) });
}
void CookiesList::addCookie (Cookie cookie)
{
addCookie (std::move (cookie.Name), std::move (cookie.Value));
}
void CookiesList::addCookie (std::string cookieName, std::string cookieValue)
{
mCookies.push_back ({ std::move (cookieName), std::move (cookieValue) });
}
bool CookiesList::hasCookie (const std::string& cookieName) const noexcept
{
return getCookie (cookieName) != nullptr;
}
std::string CookiesList::getCookieValue (const std::string& cookieName) const
{
const Cookie* item = getCookie (cookieName);
if (item != nullptr)
return item->Value;
return {};
}
const Cookie* CookiesList::getCookie (size_t idx) const noexcept
{
return const_cast<CookiesList*>(this)->getCookie(idx);
}
const Cookie* CookiesList::getCookie (const std::string& name) const noexcept
{
return const_cast<CookiesList*>(this)->getCookie (name);
}
size_t CookiesList::getCookiesCount () const noexcept
{
return mCookies.size ();
}
std::string CookiesList::getCookiesString () const
{
std::string result;
for (const Cookie& cookie : mCookies)
{
if (!result.empty ())
result.push_back (';');
result += cookie.Name + "=" + cookie.Value;
}
return result;
}
CookiesList::CookiesIterator CookiesList::begin () noexcept
{
return mCookies.begin ();
}
CookiesList::CookiesIterator CookiesList::end () noexcept
{
return mCookies.end ();
}
CookiesList::CookiesConstIterator CookiesList::begin () const noexcept
{
return mCookies.begin ();
}
CookiesList::CookiesConstIterator CookiesList::end () const noexcept
{
return mCookies.end ();
}
Cookie* CookiesList::getCookie (size_t idx) noexcept
{
if (idx < mCookies.size ())
return &mCookies[idx];
return nullptr;
}
Cookie* CookiesList::getCookie (const std::string& cookieName) noexcept
{
for (Cookie& cookie : mCookies)
{
if (cookie.Name == cookieName)
return &cookie;
}
return nullptr;
}
}
}

78
libraries/lib-network-manager/CookiesList.h

@ -1,78 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file CookiesList.h
@brief Define HTTP cookies list class.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include "NetworkManagerApi.h"
namespace audacity
{
namespace network_manager
{
using ExpiresTime = std::chrono::system_clock::time_point;
struct NETWORK_MANAGER_API Cookie final
{
std::string Name;
std::string Value;
ExpiresTime Expires {};
static Cookie Parse (const std::string& cookieString);
bool isSession () const noexcept;
bool isExpired () const noexcept;
std::string toString(bool fullString) const;
};
class NETWORK_MANAGER_API CookiesList final
{
using CookiesStorageType = std::vector<Cookie>;
public:
using CookiesIterator = CookiesStorageType::iterator;
using CookiesConstIterator = CookiesStorageType::const_iterator;
void setCookie (const Cookie& cookie);
void setCookie (const std::string& cookieName, std::string cookieValue);
void addCookie (Cookie cookie);
void addCookie (std::string cookieName, std::string cookieValue);
bool hasCookie (const std::string& cookieName) const noexcept;
std::string getCookieValue (const std::string& cookieName) const;
const Cookie* getCookie (size_t idx) const noexcept;
const Cookie* getCookie (const std::string& name) const noexcept;
size_t getCookiesCount () const noexcept;
std::string getCookiesString () const;
CookiesIterator begin () noexcept;
CookiesIterator end () noexcept;
CookiesConstIterator begin () const noexcept;
CookiesConstIterator end () const noexcept;
private:
Cookie* getCookie (size_t idx) noexcept;
Cookie* getCookie (const std::string& cookieName) noexcept;
CookiesStorageType mCookies;
};
}
}

158
libraries/lib-network-manager/HeadersList.cpp

@ -1,158 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file HeadersList.cpp
@brief Define HTTP headers list class.
Dmitry Vedenko
**********************************************************************/
/*!********************************************************************
@class Header
@brief A string pair, representing HTTP header.
**********************************************************************/
/*!********************************************************************
@class HeadersList
@brief A class, representing a list of HTTP headers.
**********************************************************************/
#include "HeadersList.h"
#include <algorithm>
#include <cctype>
namespace audacity
{
namespace network_manager
{
bool Header::hasSameName (const Header& header) const
{
return hasSameName (header.Name);
}
bool Header::hasSameName (const std::string& name) const
{
return std::equal (
name.begin (), name.end (),
Name.begin (), Name.end (),
[](const char leftChar, const char rightChar) {
return std::tolower (leftChar) == std::tolower (rightChar);
});
}
Header Header::Parse (const std::string& header)
{
const size_t colonPosition = header.find (": ");
if (colonPosition == std::string::npos) // This can happen when we receieve the first line of the response
return { header, std::string () };
return {
header.substr (0, colonPosition),
header.substr (colonPosition + 2)
};
}
void HeadersList::setHeader (const Header& header)
{
setHeader (header.Name, header.Value);
}
void HeadersList::setHeader (const std::string& headerName, std::string headerValue)
{
Header* item = getHeader (headerName);
if (item != nullptr)
item->Value = std::move (headerValue);
else
mHeaders.push_back ({ headerName, std::move (headerValue) });
}
void HeadersList::addHeader (Header header)
{
addHeader (std::move (header.Name), std::move (header.Value));
}
void HeadersList::addHeader (std::string headerName, std::string headerValue)
{
mHeaders.push_back ({ std::move (headerName), std::move (headerValue) });
}
bool HeadersList::hasHeader (const std::string& headerName) const noexcept
{
return getHeader (headerName) != nullptr;
}
std::string HeadersList::getHeaderValue (const std::string& headerName) const
{
const Header* header = getHeader (headerName);
if (header != nullptr)
return header->Value;
return {};
}
const Header* HeadersList::getHeader (size_t idx) const noexcept
{
return const_cast<HeadersList*>(this)->getHeader (idx);
}
const Header* HeadersList::getHeader (const std::string& name) const noexcept
{
return const_cast<HeadersList*>(this)->getHeader (name);
}
size_t HeadersList::getHeadersCount () const noexcept
{
return mHeaders.size ();
}
HeadersList::HeadersIterator HeadersList::begin () noexcept
{
return mHeaders.begin ();
}
HeadersList::HeadersIterator HeadersList::end () noexcept
{
return mHeaders.end ();
}
HeadersList::HeadersConstIterator HeadersList::begin () const noexcept
{
return mHeaders.begin ();
}
HeadersList::HeadersConstIterator HeadersList::end () const noexcept
{
return mHeaders.end ();
}
Header* HeadersList::getHeader (size_t idx) noexcept
{
if (idx < mHeaders.size ())
return &mHeaders[idx];
return nullptr;
}
Header* HeadersList::getHeader (const std::string& headerName) noexcept
{
for (Header& header : mHeaders)
{
if (header.hasSameName (headerName))
return &header;
}
return nullptr;
}
}
}

69
libraries/lib-network-manager/HeadersList.h

@ -1,69 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file HeadersList.h
@brief Declare HTTP headers list class.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <string>
#include <vector>
#include "NetworkManagerApi.h"
namespace audacity
{
namespace network_manager
{
struct NETWORK_MANAGER_API Header final
{
std::string Name;
std::string Value;
bool hasSameName (const Header& header) const;
bool hasSameName (const std::string& name) const;
static Header Parse (const std::string& header);
};
class NETWORK_MANAGER_API HeadersList final
{
using HeadersStorageType = std::vector<Header>;
public:
using HeadersIterator = HeadersStorageType::iterator;
using HeadersConstIterator = HeadersStorageType::const_iterator;
void setHeader (const Header& header);
void setHeader (const std::string& headerName, std::string headerValue);
void addHeader (Header header);
void addHeader (std::string headerName, std::string headerValue);
bool hasHeader (const std::string& headerName) const noexcept;
std::string getHeaderValue (const std::string& headerName) const;
const Header* getHeader (size_t idx) const noexcept;
const Header* getHeader (const std::string& name) const noexcept;
size_t getHeadersCount () const noexcept;
HeadersIterator begin () noexcept;
HeadersIterator end () noexcept;
HeadersConstIterator begin () const noexcept;
HeadersConstIterator end () const noexcept;
private:
Header* getHeader (size_t idx) noexcept;
Header* getHeader (const std::string& headerName) noexcept;
HeadersStorageType mHeaders;
};
}
}

109
libraries/lib-network-manager/IResponse.h

@ -1,109 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file IResponse.h
@brief Declare an interface for HTTP response.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <string>
#include <cstdint>
#include <vector>
#include <functional>
#include "NetworkManagerApi.h"
namespace audacity
{
namespace network_manager
{
class Request;
class HeadersList;
class CookiesList;
enum class NetworkError
{
NoError,
BadURL,
ConnectionFailed,
ConnectionRefused,
RemoteHostClosed,
HostNotFound,
Timeout,
OperationCancelled,
SSLHandshakeFailed,
TooManyRedirects,
ProxyConnectionFailed,
ProxyNotFound,
UnknownError,
HTTPError
};
class NETWORK_MANAGER_API IResponse
{
public:
using RequestCallback = std::function<void (IResponse*)>;
virtual ~IResponse () = default;
virtual bool isFinished () const noexcept = 0;
virtual unsigned getHTTPCode () const noexcept = 0;
virtual NetworkError getError () const noexcept = 0;
virtual std::string getErrorString () const = 0;
virtual bool headersReceived () const noexcept = 0;
virtual bool hasHeader (const std::string& headerName) const noexcept = 0;
virtual std::string getHeader (const std::string& headerName) const = 0;
virtual const HeadersList& getHeaders () const noexcept = 0;
virtual const CookiesList& getCookies () const noexcept = 0;
virtual const Request& getRequest () const noexcept = 0;
virtual std::string getURL () const = 0;
virtual void abort () noexcept = 0;
virtual void setOnDataReceivedCallback (RequestCallback callback) = 0;
virtual void setRequestFinishedCallback (RequestCallback callback) = 0;
// The total bytes available to read by readData
virtual uint64_t getBytesAvailable () const noexcept = 0;
// Reads at max maxBytesCount into the buffer, returns the actual count of bytes read
virtual uint64_t readData (void* buffer, uint64_t maxBytesCount) = 0;
template<typename RetVal = std::vector<uint8_t>>
RetVal readAll ()
{
RetVal result;
constexpr uint64_t bufferSize = 4 * 1024;
uint8_t buffer[bufferSize];
while (uint64_t bytesRead = readData (buffer, bufferSize))
{
using PtrType = typename RetVal::pointer;
PtrType begin = reinterpret_cast<PtrType>(buffer);
PtrType end = reinterpret_cast<PtrType>(buffer + bytesRead);
result.insert (result.end (), begin, end);
if (bytesRead < bufferSize)
break;
}
return result;
}
};
}
}

49
libraries/lib-network-manager/IResponseFactory.h

@ -1,49 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file IResponse.h
@brief Declare an interface for HTTP response factory.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <memory>
#include <string>
namespace audacity
{
namespace network_manager
{
class IResponse;
class Request;
using ResponsePtr = std::shared_ptr<IResponse>;
enum class RequestVerb
{
Head,
Get,
Post,
Put,
Delete
};
class IResponseFactory
{
public:
virtual ~IResponseFactory () = default;
virtual void setProxy (const std::string& proxy) = 0;
virtual ResponsePtr performRequest (RequestVerb verb, const Request& request) = 0;
virtual ResponsePtr performRequest (RequestVerb verb, const Request& request, const void* data, size_t size) = 0;
virtual void terminate () = 0;
};
}
}

79
libraries/lib-network-manager/NetworkManager.cpp

@ -1,79 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file NetworkManager.cpp
@brief Define a class for preforming HTTP requests.
Dmitry Vedenko
**********************************************************************/
/*!********************************************************************
@class NetworkManager
@brief Class for preforming HTTP requests.
**********************************************************************/
#include "NetworkManager.h"
#include "IResponseFactory.h"
#include "curl/CurlResponseFactory.h"
namespace audacity
{
namespace network_manager
{
NetworkManager::NetworkManager ()
{
mResponseFactory = std::make_unique<CurlResponseFactory> ();
}
NetworkManager::~NetworkManager ()
{}
NetworkManager& NetworkManager::GetInstance ()
{
static NetworkManager instance;
return instance;
}
void NetworkManager::Terminate ()
{
GetInstance ().mResponseFactory->terminate ();
}
ResponsePtr NetworkManager::doGet (const Request& request)
{
return mResponseFactory->performRequest (RequestVerb::Get, request);
}
ResponsePtr NetworkManager::doHead (const Request& request)
{
return mResponseFactory->performRequest (RequestVerb::Head, request);
}
ResponsePtr NetworkManager::doDelete (const Request& request)
{
return mResponseFactory->performRequest (RequestVerb::Delete, request);
}
ResponsePtr NetworkManager::doPost (const Request& request, const void* data, size_t size)
{
return mResponseFactory->performRequest (RequestVerb::Post, request, data, size);
}
ResponsePtr NetworkManager::doPut (const Request& request, const void* data, size_t size)
{
return mResponseFactory->performRequest (RequestVerb::Put, request, data, size);
}
void NetworkManager::setProxy (const std::string& proxy)
{
mResponseFactory->setProxy (proxy);
}
}
}

49
libraries/lib-network-manager/NetworkManager.h

@ -1,49 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file NetworkManager.h
@brief Declare a class for preforming HTTP requests.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <memory>
#include <string>
#include "NetworkManagerApi.h"
namespace audacity
{
namespace network_manager
{
class Request;
class IResponse;
class IResponseFactory;
using ResponsePtr = std::shared_ptr<IResponse>;
class NETWORK_MANAGER_API NetworkManager final
{
NetworkManager ();
~NetworkManager ();
public:
static NetworkManager& GetInstance();
static void Terminate ();
ResponsePtr doGet (const Request& request);
ResponsePtr doHead (const Request& request);
ResponsePtr doDelete (const Request& request);
ResponsePtr doPost (const Request& request, const void* data, size_t size);
ResponsePtr doPut (const Request& request, const void* data, size_t size);
void setProxy (const std::string& proxy);
private:
std::unique_ptr<IResponseFactory> mResponseFactory;
};
}
}

31
libraries/lib-network-manager/NetworkManagerApi.h

@ -1,31 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file NetworkManagerApi.h
@brief Declare macros for the Network Manager library DLL API
Dmitry Vedenko
**********************************************************************/
#pragma once
/* The dynamic library import and export for Microsoft Windows.
* Supported by Visual Studio and for GCC 4+ */
#if defined _WIN32 || (defined __CYGWIN__ && defined __GNUC__)
# ifndef NETWORK_MANAGER_API
# ifdef BUILDING_LIB_NETWORK_MANAGER
# define NETWORK_MANAGER_API __declspec(dllexport)
# else
# ifdef _DLL
# define NETWORK_MANAGER_API __declspec(dllimport)
# else
# define NETWORK_MANAGER_API
# endif
# endif
# endif
#else
# ifndef NETWORK_MANAGER_API
# define NETWORK_MANAGER_API __attribute__((visibility("default")))
# endif
#endif //_WIN32 || (__CYGWIN__ && __GNUC__)

115
libraries/lib-network-manager/Request.cpp

@ -1,115 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file Request.cpp
@brief Define a class for constructing HTTP requests.
Dmitry Vedenko
**********************************************************************/
/*!********************************************************************
@class Request
@brief Class to construct the HTTP request.
**********************************************************************/
#include "Request.h"
#include <cctype>
#include <algorithm>
namespace audacity
{
namespace network_manager
{
Request::Request(std::string url) noexcept
: mUrl (std::move (url))
{
}
Request& Request::setURL(std::string url) noexcept
{
mUrl = std::move (url);
return *this;
}
const std::string& Request::getURL () const noexcept
{
return mUrl;
}
Request& Request::setHeader (const std::string& name, std::string value)
{
mHeaders.setHeader (name, std::move (value));
return *this;
}
std::string Request::getHeader (const std::string& name) const
{
return mHeaders.getHeaderValue (name);
}
const HeadersList& Request::getHeaders () const noexcept
{
return mHeaders;
}
Request& Request::setCookie (const std::string& name, std::string value)
{
mCookies.setCookie (name, std::move (value));
return *this;
}
std::string Request::getCookie (const std::string& name) const
{
return mCookies.getCookieValue (name);
}
const CookiesList& Request::getCookies () noexcept
{
return mCookies;
}
Request& Request::setMaxRedirects (size_t redirects) noexcept
{
mMaxRedirects = redirects;
return *this;
}
size_t Request::getMaxRedirects () const noexcept
{
return mMaxRedirects;
}
Request& Request::setTimeout (Timeout timeout) noexcept
{
mTimeout = timeout;
return *this;
}
Request::Timeout Request::getTimeout () const noexcept
{
return mTimeout;
}
Request& Request::appendCookies (const CookiesList& list)
{
for (const Cookie& cookie : list)
{
if (!cookie.isExpired())
mCookies.setCookie (cookie);
}
return *this;
}
}
}

75
libraries/lib-network-manager/Request.h

@ -1,75 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file Request.h
@brief Declare a class for constructing HTTP requests.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <string>
#include <chrono>
#include <numeric>
#include "NetworkManagerApi.h"
#include "HeadersList.h"
#include "CookiesList.h"
namespace audacity
{
namespace network_manager
{
class NETWORK_MANAGER_API Request final
{
public:
using Timeout = std::chrono::milliseconds;
static constexpr size_t INFINITE_REDIRECTS = std::numeric_limits<size_t>::max();
Request() = default;
explicit Request(std::string url) noexcept;
Request(const Request&) = default;
Request(Request&&) = default;
Request& operator = (const Request&) = default;
Request& operator = (Request&&) = default;
Request& setURL(std::string url) noexcept;
const std::string& getURL() const noexcept;
Request& setHeader(const std::string& name, std::string value);
std::string getHeader(const std::string& name) const;
const HeadersList& getHeaders () const noexcept;
Request& setCookie(const std::string& name, std::string value);
Request& appendCookies (const CookiesList& list);
std::string getCookie(const std::string& name) const;
const CookiesList& getCookies () noexcept;
Request& setMaxRedirects(size_t redirects) noexcept;
size_t getMaxRedirects() const noexcept;
Request& setTimeout(Timeout timeout) noexcept;
Timeout getTimeout() const noexcept;
private:
std::string mUrl;
HeadersList mHeaders;
CookiesList mCookies;
size_t mMaxRedirects { INFINITE_REDIRECTS };
Timeout mTimeout { std::chrono::seconds (5) };
};
}
}

349
libraries/lib-network-manager/curl/CurlHandleManager.cpp

@ -1,349 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file CurlHandleManager.cpp
@brief Define a class responsible for reuse of CURL hanldes.
Dmitry Vedenko
**********************************************************************/
#include "CurlHandleManager.h"
#include <algorithm>
#include <sstream>
#include <wx/platinfo.h>
namespace audacity
{
namespace network_manager
{
namespace
{
void GetOSString (std::ostringstream& output, const wxPlatformInfo& platformInfo)
{
const wxOperatingSystemId osID = platformInfo.GetOperatingSystemId ();
if (osID & wxOS_WINDOWS)
output << "Windows ";
else if (osID & wxOS_MAC)
output << "MacOS ";
else if (osID & wxOS_UNIX_LINUX)
output << "Linux ";
else if (osID & wxOS_UNIX_FREEBSD)
output << "FreeBSD ";
else if (osID & wxOS_UNIX_OPENBSD)
output << "OpenBSD ";
else
output << "Other ";
output <<
platformInfo.GetOSMajorVersion () <<
"_" <<
platformInfo.GetOSMinorVersion () <<
"_" <<
platformInfo.GetOSMicroVersion() <<
"; ";
#if defined(__amd64__) || defined(__x86_64__) || defined(_M_X64)
output << "x64";
#elif defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(_X86_) || defined(__THW_INTEL)
output << "x86";
#elif defined(__arm64__) || defined(__aarch64__)
output << "arm64";
#elif defined(arm) || defined(__arm__) || defined(ARM) || defined(_ARM_)
output << "arm";
#else
output << "unknown";
#endif
}
}
constexpr std::chrono::milliseconds CurlHandleManager::KEEP_ALIVE_IDLE;
constexpr std::chrono::milliseconds CurlHandleManager::KEEP_ALIVE_PROBE;
CurlHandleManager::Handle::Handle(CurlHandleManager* owner, CURL* handle, RequestVerb verb, std::string url) noexcept
: mHandle (handle),
mOwner (owner),
mVerb (verb),
mUrl (std::move (url)),
mHandleFromCache (handle != nullptr)
{
if (mHandle == nullptr)
mHandle = curl_easy_init ();
setOption (CURLOPT_URL, mUrl);
switch (verb)
{
case RequestVerb::Head:
setOption (CURLOPT_NOBODY, 1);
break;
case RequestVerb::Get:
// This is a default, no additional setup is needed
// We cache handles by the verb, so there is no need to
// reset the handle state
break;
case RequestVerb::Post:
setOption (CURLOPT_POST, 1);
break;
case RequestVerb::Put:
setOption (CURLOPT_UPLOAD, 1);
break;
case RequestVerb::Delete:
setOption (CURLOPT_CUSTOMREQUEST, "DELETE");
break;
}
setOption (CURLOPT_NOSIGNAL, 1L);
setOption (CURLOPT_SSL_VERIFYPEER, 1L);
setOption (CURLOPT_SSL_VERIFYHOST, 2L);
setOption (CURLOPT_ACCEPT_ENCODING, "");
}
CurlHandleManager::Handle::Handle (Handle&& rhs) noexcept
{
*this = std::move (rhs);
}
CurlHandleManager::Handle::~Handle () noexcept
{
if (mReuse)
mOwner->cacheHandle (*this);
else
curl_easy_cleanup (mHandle);
}
CurlHandleManager::Handle& CurlHandleManager::Handle::operator=(Handle&& rhs) noexcept
{
std::swap (mHandle, rhs.mHandle);
std::swap (mOwner, rhs.mOwner);
std::swap (mVerb, rhs.mVerb);
mUrl = std::move (rhs.mUrl);
mHeaders = std::move (rhs.mHeaders);
mReuse = rhs.mReuse;
rhs.mReuse = false;
return *this;
}
CURLcode CurlHandleManager::Handle::setOption (CURLoption option, const std::string& value) noexcept
{
return setOption (option, value.c_str ());
}
CURLcode CurlHandleManager::Handle::appendCookie (const Cookie& cookie) noexcept
{
return setOption(CURLOPT_COOKIE, "Set-Cookie: " + cookie.Name + "=" + cookie.Value);
}
CURLcode CurlHandleManager::Handle::appendCookies (const CookiesList& cookies)noexcept
{
for (const Cookie& cookie : cookies)
{
const CURLcode result = appendCookie (cookie);
if (result != CURLE_OK)
return result;
}
return CURLE_OK;
}
void CurlHandleManager::Handle::appendHeader (const Header& header)
{
if (header.hasSameName ("User-Agent"))
mUserAgentSet = true;
mHeaders.append(header.Name + ": " + header.Value);
}
void CurlHandleManager::Handle::appendHeaders (const HeadersList& headers)
{
for (const Header& header : headers)
appendHeader (header);
}
CurlHandleManager::Handle::Result CurlHandleManager::Handle::perform ()
{
if (!mUserAgentSet)
mHeaders.append ("User-Agent: " + mOwner->getUserAgent ());
CURLcode result = setOption (CURLOPT_HTTPHEADER, mHeaders.getCurlList ());
if (result != CURLE_OK)
return { result, std::string () };
char currentError[CURL_ERROR_SIZE] = {};
setOption(CURLOPT_ERRORBUFFER, currentError);
result = curl_easy_perform (mHandle);
mReuse = mReuse && result == CURLE_OK;
return { result, std::string (currentError) };
}
void CurlHandleManager::Handle::markKeepAlive ()
{
mReuse = true;
}
bool CurlHandleManager::Handle::isHandleFromCache () const noexcept
{
return mHandleFromCache;
}
unsigned CurlHandleManager::Handle::getHTTPCode () const noexcept
{
long code = 0;
if (CURLE_OK != curl_easy_getinfo(mHandle, CURLINFO_RESPONSE_CODE, &code))
return 0;
return code;
}
void CurlHandleManager::Handle::reset () noexcept
{
setOption (CURLOPT_COOKIELIST, nullptr);
setOption (CURLOPT_PROXY, nullptr);
setOption (CURLOPT_SSL_OPTIONS, 0);
mUserAgentSet = false;
}
CurlHandleManager::CurlHandleManager ()
{
std::ostringstream ss;
ss << "Audacity/" <<
AUDACITY_VERSION << "." <<
AUDACITY_RELEASE << "." <<
AUDACITY_REVISION <<
" (";
GetOSString (ss, wxPlatformInfo::Get ());
ss << ")";
mUserAgent = ss.str ();
}
CurlHandleManager::~CurlHandleManager ()
{
std::lock_guard<std::mutex> lock (mHandleCacheLock);
for (auto& cachedHandle : mHandleCache)
curl_easy_cleanup (cachedHandle.Handle);
}
void CurlHandleManager::setProxy (std::string proxy)
{
mProxy = std::move (proxy);
}
CurlHandleManager::Handle CurlHandleManager::getHandle (RequestVerb verb, const std::string& url)
{
Handle handle (this, getCurlHandleFromCache (verb, url), verb, url);
if (!mProxy.empty ())
{
handle.setOption (CURLOPT_PROXY, mProxy);
// If we use proxy, checking the CRL will likely break the SSL proxying
handle.setOption (CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
}
handle.setOption (CURLOPT_TCP_KEEPALIVE, 1L);
handle.setOption (CURLOPT_TCP_KEEPIDLE,
std::chrono::duration_cast<std::chrono::seconds> (KEEP_ALIVE_IDLE).count ()
);
handle.setOption (CURLOPT_TCP_KEEPINTVL,
std::chrono::duration_cast<std::chrono::seconds> (KEEP_ALIVE_PROBE).count ()
);
return handle;
}
std::string CurlHandleManager::getUserAgent () const
{
return mUserAgent;
}
CURL* CurlHandleManager::getCurlHandleFromCache (RequestVerb verb, const std::string& url)
{
std::lock_guard<std::mutex> lock (mHandleCacheLock);
cleanupHandlesCache ();
const std::string schemeAndDomain = GetSchemeAndDomain (url);
auto it = std::find_if (mHandleCache.begin (), mHandleCache.end (), [verb, schemeAndDomain](const CachedHandle& handle) {
return handle.Verb == verb && handle.SchemeAndDomain == schemeAndDomain;
});
if (it == mHandleCache.end ())
return nullptr;
CURL* handle = it->Handle;
mHandleCache.erase (it);
return handle;
}
void CurlHandleManager::cacheHandle (Handle& handle)
{
// Reset the state to the safe defaults
handle.reset ();
std::lock_guard<std::mutex> lock (mHandleCacheLock);
cleanupHandlesCache ();
mHandleCache.push_back ({
handle.mVerb,
GetSchemeAndDomain (handle.mUrl),
handle.mHandle,
RequestClock::now ()
});
}
void CurlHandleManager::cleanupHandlesCache ()
{
const RequestTimePoint timePoint = RequestClock::now ();
mHandleCache.erase (std::remove_if (mHandleCache.begin (), mHandleCache.end (), [timePoint](const CachedHandle& cachedHandle) {
return (timePoint - cachedHandle.RequestTime) >= KEEP_ALIVE_IDLE;
}), mHandleCache.end ());
}
std::string CurlHandleManager::GetSchemeAndDomain (const std::string& url)
{
const size_t schemeEndPosition = url.find ("://");
if (schemeEndPosition == std::string::npos) // Is url even valid?
return url;
const size_t domainStartPosition = schemeEndPosition + 3;
const size_t slashLocation = url.find ('/', domainStartPosition);
if (slashLocation == std::string::npos)
return url;
return url.substr (domainStartPosition, slashLocation - domainStartPosition);
}
}
}

127
libraries/lib-network-manager/curl/CurlHandleManager.h

@ -1,127 +0,0 @@
/*!********************************************************************
Audacity: A Digital Audio Editor
@file CurlHandleManager.h
@brief Declare a class responsible for reuse of CURL hanldes.
Dmitry Vedenko
**********************************************************************/
#pragma once
#include <string>
#include <chrono>
#include <vector>
#include <mutex>
#include <curl/curl.h>
#include "CurlStringList.h"
#include "../IResponseFactory.h"
#include "../CookiesList.h"
#include "../HeadersList.h"
namespace audacity
{
namespace network_manager
{