2017-02-24 18:59:41 +01:00
# pragma once
2012-06-03 19:01:08 +02:00
2016-10-12 11:32:24 +02:00
# include <functional>
2013-06-01 00:50:08 +02:00
# include <memory>
2017-02-27 20:51:36 +01:00
# include <thread>
2020-09-29 12:44:47 +02:00
# include <cstdint>
2016-10-12 11:32:24 +02:00
2021-05-14 22:46:03 -07:00
# include "Common/File/Path.h"
2021-05-01 08:36:25 -07:00
# include "Common/Net/NetBuffer.h"
2020-10-04 20:48:47 +02:00
# include "Common/Net/Resolve.h"
2012-06-03 19:01:08 +02:00
namespace net {
class Connection {
2012-10-30 13:20:55 +01:00
public :
Connection ( ) ;
virtual ~ Connection ( ) ;
2012-06-03 19:01:08 +02:00
2012-10-30 13:20:55 +01:00
// Inits the sockaddr_in.
2018-04-30 17:06:54 -07:00
bool Resolve ( const char * host , int port , DNSType type = DNSType : : ANY ) ;
2012-06-03 19:01:08 +02:00
2017-03-22 00:00:52 -07:00
bool Connect ( int maxTries = 2 , double timeout = 20.0f , bool * cancelConnect = nullptr ) ;
2012-10-30 13:20:55 +01:00
void Disconnect ( ) ;
2012-06-03 19:01:08 +02:00
2012-10-30 13:20:55 +01:00
// Only to be used for bring-up and debugging.
uintptr_t sock ( ) const { return sock_ ; }
2012-06-03 19:01:08 +02:00
2012-10-30 13:20:55 +01:00
protected :
// Store the remote host here, so we can send it along through HTTP/1.1 requests.
// TODO: Move to http::client?
std : : string host_ ;
2021-04-30 22:59:41 -07:00
int port_ = - 1 ;
2012-06-03 19:01:08 +02:00
2021-04-30 22:59:41 -07:00
addrinfo * resolved_ = nullptr ;
2012-10-30 13:20:55 +01:00
private :
2021-04-30 22:59:41 -07:00
uintptr_t sock_ = - 1 ;
2012-06-03 19:01:08 +02:00
} ;
2012-10-30 13:20:55 +01:00
} // namespace net
2012-06-03 19:01:08 +02:00
namespace http {
2019-06-23 13:12:13 -07:00
bool GetHeaderValue ( const std : : vector < std : : string > & responseHeaders , const std : : string & header , std : : string * value ) ;
2021-05-01 10:19:27 -07:00
struct RequestProgress {
RequestProgress ( ) { }
explicit RequestProgress ( bool * c ) : cancelled ( c ) { }
float progress = 0.0f ;
2021-05-01 10:40:34 -07:00
float kBps = 0.0f ;
2021-05-01 10:19:27 -07:00
bool * cancelled = nullptr ;
} ;
2021-08-22 08:17:26 -07:00
struct RequestParams {
RequestParams ( ) { }
explicit RequestParams ( const char * r ) : resource ( r ) { }
RequestParams ( const std : : string & r , const char * a ) : resource ( r ) , acceptMime ( a ) { }
std : : string resource ;
const char * acceptMime = " */* " ;
} ;
2012-06-03 19:01:08 +02:00
class Client : public net : : Connection {
2012-10-30 13:20:55 +01:00
public :
Client ( ) ;
~ Client ( ) ;
2012-06-03 19:01:08 +02:00
2013-05-31 23:04:42 +02:00
// Return value is the HTTP return code. 200 means OK. < 0 means some local error.
2021-08-22 08:17:26 -07:00
int GET ( const RequestParams & req , Buffer * output , RequestProgress * progress ) ;
int GET ( const RequestParams & req , Buffer * output , std : : vector < std : : string > & responseHeaders , RequestProgress * progress ) ;
2012-06-03 19:01:08 +02:00
2012-10-30 13:20:55 +01:00
// Return value is the HTTP return code.
2021-08-22 08:17:26 -07:00
int POST ( const RequestParams & req , const std : : string & data , const std : : string & mime , Buffer * output , RequestProgress * progress ) ;
int POST ( const RequestParams & req , const std : : string & data , Buffer * output , RequestProgress * progress ) ;
2012-06-03 19:01:08 +02:00
2014-11-25 08:49:05 -08:00
// HEAD, PUT, DELETE aren't implemented yet, but can be done with SendRequest.
2014-11-23 16:12:54 -08:00
2021-08-22 08:17:26 -07:00
int SendRequest ( const char * method , const RequestParams & req , const char * otherHeaders , RequestProgress * progress ) ;
int SendRequestWithData ( const char * method , const RequestParams & req , const std : : string & data , const char * otherHeaders , RequestProgress * progress ) ;
2021-05-01 10:19:27 -07:00
int ReadResponseHeaders ( net : : Buffer * readbuf , std : : vector < std : : string > & responseHeaders , RequestProgress * progress ) ;
2014-11-23 16:12:54 -08:00
// If your response contains a response, you must read it.
2021-05-01 10:19:27 -07:00
int ReadResponseEntity ( net : : Buffer * readbuf , const std : : vector < std : : string > & responseHeaders , Buffer * output , RequestProgress * progress ) ;
2014-11-23 16:12:54 -08:00
2018-12-27 10:15:58 -08:00
void SetDataTimeout ( double t ) {
dataTimeout_ = t ;
}
2022-12-27 15:08:57 -08:00
void SetUserAgent ( const std : : string & value ) {
2021-04-30 23:12:42 -07:00
userAgent_ = value ;
}
2018-12-27 10:15:58 -08:00
protected :
2021-04-30 23:12:42 -07:00
std : : string userAgent_ ;
2014-11-23 16:12:54 -08:00
const char * httpVersion_ ;
2021-05-01 09:37:36 -07:00
double dataTimeout_ = 900.0 ;
2012-06-03 19:01:08 +02:00
} ;
2023-06-17 22:29:32 +02:00
enum class RequestMethod {
GET ,
POST ,
} ;
// Really an asynchronous request.
2013-05-31 23:04:42 +02:00
class Download {
public :
2023-06-17 22:31:01 +02:00
Download ( RequestMethod method , const std : : string & url , const std : : string & postData , const std : : string & postMime , const Path & outfile ) ;
2013-05-31 23:04:42 +02:00
~ Download ( ) ;
2020-06-28 10:03:03 +02:00
void Start ( ) ;
void Join ( ) ;
2013-06-26 19:24:49 +02:00
2013-06-01 18:59:03 +02:00
// Returns 1.0 when done. That one value can be compared exactly - or just use Done().
2021-05-01 10:19:27 -07:00
float Progress ( ) const { return progress_ . progress ; }
2021-05-01 10:40:34 -07:00
float SpeedKBps ( ) const { return progress_ . kBps ; }
2013-06-01 18:59:03 +02:00
2013-11-29 17:33:56 +01:00
bool Done ( ) const { return completed_ ; }
2013-05-31 23:04:42 +02:00
bool Failed ( ) const { return failed_ ; }
2013-11-29 17:33:56 +01:00
// NOTE! The value of ResultCode is INVALID until Done() returns true.
2013-06-02 23:44:28 +02:00
int ResultCode ( ) const { return resultCode_ ; }
2013-05-31 23:04:42 +02:00
std : : string url ( ) const { return url_ ; }
2021-05-14 22:46:03 -07:00
const Path & outfile ( ) const { return outfile_ ; }
2013-05-31 23:04:42 +02:00
2021-08-22 08:29:48 -07:00
void SetAccept ( const char * mime ) {
acceptMime_ = mime ;
}
2013-06-01 18:59:03 +02:00
// If not downloading to a file, access this to get the result.
Buffer & buffer ( ) { return buffer_ ; }
2013-11-26 13:56:37 +01:00
const Buffer & buffer ( ) const { return buffer_ ; }
2013-06-01 18:59:03 +02:00
2013-06-25 23:27:45 +02:00
void Cancel ( ) {
cancelled_ = true ;
}
2015-10-06 19:07:09 +02:00
bool IsCancelled ( ) const {
return cancelled_ ;
}
2013-11-26 13:56:37 +01:00
// NOTE: Callbacks are NOT executed until RunCallback is called. This is so that
// the call will end up on the thread that calls g_DownloadManager.Update().
void SetCallback ( std : : function < void ( Download & ) > callback ) {
callback_ = callback ;
}
void RunCallback ( ) {
2013-11-29 12:21:02 +01:00
if ( callback_ ) {
callback_ ( * this ) ;
}
2013-11-26 13:56:37 +01:00
}
2013-12-10 11:48:31 +01:00
// Just metadata. Convenient for download managers, for example, if set,
// Downloader::GetCurrentProgress won't return it in the results.
bool IsHidden ( ) const { return hidden_ ; }
void SetHidden ( bool hidden ) { hidden_ = hidden ; }
2023-07-14 15:24:34 +02:00
void SetUserAgent ( const std : : string & userAgent ) {
userAgent_ = userAgent ;
}
2013-12-10 11:48:31 +01:00
2013-05-31 23:04:42 +02:00
private :
2020-06-28 10:03:03 +02:00
void Do ( ) ; // Actually does the download. Runs on thread.
2023-06-17 22:29:32 +02:00
int Perform ( const std : : string & url ) ;
2019-06-23 12:04:59 -07:00
std : : string RedirectLocation ( const std : : string & baseUrl ) ;
2013-06-25 23:27:45 +02:00
void SetFailed ( int code ) ;
2021-08-22 12:21:44 +02:00
2021-05-01 10:19:27 -07:00
RequestProgress progress_ ;
2023-06-17 22:29:32 +02:00
RequestMethod method_ ;
std : : string postData_ ;
2023-07-14 15:24:34 +02:00
std : : string userAgent_ ;
2013-05-31 23:04:42 +02:00
Buffer buffer_ ;
2019-06-23 12:04:59 -07:00
std : : vector < std : : string > responseHeaders_ ;
2013-05-31 23:04:42 +02:00
std : : string url_ ;
2021-05-14 22:46:03 -07:00
Path outfile_ ;
2019-09-28 11:40:10 -07:00
std : : thread thread_ ;
2021-08-22 08:29:48 -07:00
const char * acceptMime_ = " */* " ;
2023-06-17 22:31:01 +02:00
std : : string postMime_ ;
2019-09-28 11:40:10 -07:00
int resultCode_ = 0 ;
bool completed_ = false ;
bool failed_ = false ;
bool cancelled_ = false ;
bool hidden_ = false ;
2020-06-28 10:03:03 +02:00
bool joined_ = false ;
2013-11-26 13:56:37 +01:00
std : : function < void ( Download & ) > callback_ ;
2013-05-31 23:04:42 +02:00
} ;
2013-06-02 23:44:28 +02:00
using std : : shared_ptr ;
2013-05-31 23:04:42 +02:00
class Downloader {
public :
2013-06-25 23:27:45 +02:00
~ Downloader ( ) {
CancelAll ( ) ;
}
2013-11-18 16:27:39 +01:00
2021-08-22 08:29:48 -07:00
std : : shared_ptr < Download > StartDownload ( const std : : string & url , const Path & outfile , const char * acceptMime = nullptr ) ;
2013-05-31 23:04:42 +02:00
2013-12-10 11:48:31 +01:00
std : : shared_ptr < Download > StartDownloadWithCallback (
2013-11-26 13:56:37 +01:00
const std : : string & url ,
2021-05-14 22:46:03 -07:00
const Path & outfile ,
2021-08-22 08:29:48 -07:00
std : : function < void ( Download & ) > callback ,
const char * acceptMime = nullptr ) ;
2013-11-26 13:56:37 +01:00
2023-06-17 22:29:32 +02:00
std : : shared_ptr < Download > AsyncPostWithCallback (
const std : : string & url ,
const std : : string & postData ,
2023-06-17 23:19:23 +02:00
const std : : string & postMime , // Use postMime = "application/x-www-form-urlencoded" for standard form-style posts, such as used by retroachievements. For encoding form data manually we have MultipartFormDataEncoder.
2023-06-17 22:29:32 +02:00
std : : function < void ( Download & ) > callback ) ;
2013-05-31 23:04:42 +02:00
// Drops finished downloads from the list.
void Update ( ) ;
2013-06-25 23:27:45 +02:00
void CancelAll ( ) ;
2023-06-17 22:29:32 +02:00
void WaitForAll ( ) ;
2023-07-14 15:24:34 +02:00
void SetUserAgent ( const std : : string & userAgent ) {
userAgent_ = userAgent ;
}
2023-06-17 22:29:32 +02:00
2013-11-29 16:31:19 +01:00
std : : vector < float > GetCurrentProgress ( ) ;
2023-06-17 01:52:28 +02:00
size_t GetActiveCount ( ) const {
return downloads_ . size ( ) ;
}
2013-05-31 23:04:42 +02:00
private :
2013-06-02 22:58:55 +10:00
std : : vector < std : : shared_ptr < Download > > downloads_ ;
2023-06-17 22:31:47 +02:00
// These get copied to downloads_ in Update(). It's so that callbacks can add new downloads
// while running.
std : : vector < std : : shared_ptr < Download > > newDownloads_ ;
2023-07-14 15:24:34 +02:00
std : : string userAgent_ ;
2013-05-31 23:04:42 +02:00
} ;
2017-03-22 00:00:52 -07:00
} // http