2017-02-24 17:59:41 +00:00
|
|
|
#pragma once
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2016-10-12 09:32:24 +00:00
|
|
|
#include <functional>
|
2013-05-31 22:50:08 +00:00
|
|
|
#include <memory>
|
2017-02-27 19:51:36 +00:00
|
|
|
#include <thread>
|
2020-09-29 10:44:47 +00:00
|
|
|
#include <cstdint>
|
2016-10-12 09:32:24 +00:00
|
|
|
|
2021-05-15 05:46:03 +00:00
|
|
|
#include "Common/File/Path.h"
|
2021-05-01 15:36:25 +00:00
|
|
|
#include "Common/Net/NetBuffer.h"
|
2020-10-04 18:48:47 +00:00
|
|
|
#include "Common/Net/Resolve.h"
|
2012-06-03 17:01:08 +00:00
|
|
|
|
|
|
|
namespace net {
|
|
|
|
|
|
|
|
class Connection {
|
2012-10-30 12:20:55 +00:00
|
|
|
public:
|
|
|
|
Connection();
|
|
|
|
virtual ~Connection();
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2012-10-30 12:20:55 +00:00
|
|
|
// Inits the sockaddr_in.
|
2018-05-01 00:06:54 +00:00
|
|
|
bool Resolve(const char *host, int port, DNSType type = DNSType::ANY);
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2017-03-22 07:00:52 +00:00
|
|
|
bool Connect(int maxTries = 2, double timeout = 20.0f, bool *cancelConnect = nullptr);
|
2012-10-30 12:20:55 +00:00
|
|
|
void Disconnect();
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2012-10-30 12:20:55 +00:00
|
|
|
// Only to be used for bring-up and debugging.
|
|
|
|
uintptr_t sock() const { return sock_; }
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2012-10-30 12:20:55 +00: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-05-01 05:59:41 +00:00
|
|
|
int port_ = -1;
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2021-05-01 05:59:41 +00:00
|
|
|
addrinfo *resolved_ = nullptr;
|
2012-10-30 12:20:55 +00:00
|
|
|
|
|
|
|
private:
|
2021-05-01 05:59:41 +00:00
|
|
|
uintptr_t sock_ = -1;
|
2012-06-03 17:01:08 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2012-10-30 12:20:55 +00:00
|
|
|
} // namespace net
|
2012-06-03 17:01:08 +00:00
|
|
|
|
|
|
|
namespace http {
|
|
|
|
|
2019-06-23 20:12:13 +00:00
|
|
|
bool GetHeaderValue(const std::vector<std::string> &responseHeaders, const std::string &header, std::string *value);
|
|
|
|
|
2021-05-01 17:19:27 +00:00
|
|
|
struct RequestProgress {
|
|
|
|
RequestProgress() {}
|
|
|
|
explicit RequestProgress(bool *c) : cancelled(c) {}
|
|
|
|
|
|
|
|
float progress = 0.0f;
|
2021-05-01 17:40:34 +00:00
|
|
|
float kBps = 0.0f;
|
2021-05-01 17:19:27 +00:00
|
|
|
bool *cancelled = nullptr;
|
|
|
|
};
|
|
|
|
|
2021-08-22 15:17:26 +00: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 17:01:08 +00:00
|
|
|
class Client : public net::Connection {
|
2012-10-30 12:20:55 +00:00
|
|
|
public:
|
|
|
|
Client();
|
|
|
|
~Client();
|
2012-06-03 17:01:08 +00:00
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
// Return value is the HTTP return code. 200 means OK. < 0 means some local error.
|
2021-08-22 15:17:26 +00: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 17:01:08 +00:00
|
|
|
|
2012-10-30 12:20:55 +00:00
|
|
|
// Return value is the HTTP return code.
|
2021-08-22 15:17:26 +00: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 17:01:08 +00:00
|
|
|
|
2014-11-25 16:49:05 +00:00
|
|
|
// HEAD, PUT, DELETE aren't implemented yet, but can be done with SendRequest.
|
2014-11-24 00:12:54 +00:00
|
|
|
|
2021-08-22 15:17:26 +00: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 17:19:27 +00:00
|
|
|
int ReadResponseHeaders(net::Buffer *readbuf, std::vector<std::string> &responseHeaders, RequestProgress *progress);
|
2014-11-24 00:12:54 +00:00
|
|
|
// If your response contains a response, you must read it.
|
2021-05-01 17:19:27 +00:00
|
|
|
int ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::string> &responseHeaders, Buffer *output, RequestProgress *progress);
|
2014-11-24 00:12:54 +00:00
|
|
|
|
2018-12-27 18:15:58 +00:00
|
|
|
void SetDataTimeout(double t) {
|
|
|
|
dataTimeout_ = t;
|
|
|
|
}
|
|
|
|
|
2021-05-01 06:12:42 +00:00
|
|
|
void SetUserAgent(const std::string &&value) {
|
|
|
|
userAgent_ = value;
|
|
|
|
}
|
|
|
|
|
2018-12-27 18:15:58 +00:00
|
|
|
protected:
|
2021-05-01 06:12:42 +00:00
|
|
|
std::string userAgent_;
|
2014-11-24 00:12:54 +00:00
|
|
|
const char *httpVersion_;
|
2021-05-01 16:37:36 +00:00
|
|
|
double dataTimeout_ = 900.0;
|
2012-06-03 17:01:08 +00:00
|
|
|
};
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
// Not particularly efficient, but hey - it's a background download, that's pretty cool :P
|
|
|
|
class Download {
|
|
|
|
public:
|
2021-05-15 05:46:03 +00:00
|
|
|
Download(const std::string &url, const Path &outfile);
|
2013-05-31 21:04:42 +00:00
|
|
|
~Download();
|
|
|
|
|
2020-06-28 08:03:03 +00:00
|
|
|
void Start();
|
|
|
|
|
|
|
|
void Join();
|
2013-06-26 17:24:49 +00:00
|
|
|
|
2013-06-01 16:59:03 +00:00
|
|
|
// Returns 1.0 when done. That one value can be compared exactly - or just use Done().
|
2021-05-01 17:19:27 +00:00
|
|
|
float Progress() const { return progress_.progress; }
|
2021-05-01 17:40:34 +00:00
|
|
|
float SpeedKBps() const { return progress_.kBps; }
|
2013-06-01 16:59:03 +00:00
|
|
|
|
2013-11-29 16:33:56 +00:00
|
|
|
bool Done() const { return completed_; }
|
2013-05-31 21:04:42 +00:00
|
|
|
bool Failed() const { return failed_; }
|
|
|
|
|
2013-11-29 16:33:56 +00:00
|
|
|
// NOTE! The value of ResultCode is INVALID until Done() returns true.
|
2013-06-02 21:44:28 +00:00
|
|
|
int ResultCode() const { return resultCode_; }
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
std::string url() const { return url_; }
|
2021-05-15 05:46:03 +00:00
|
|
|
const Path &outfile() const { return outfile_; }
|
2013-05-31 21:04:42 +00:00
|
|
|
|
2021-08-22 15:29:48 +00:00
|
|
|
void SetAccept(const char *mime) {
|
|
|
|
acceptMime_ = mime;
|
|
|
|
}
|
|
|
|
|
2013-06-01 16:59:03 +00:00
|
|
|
// If not downloading to a file, access this to get the result.
|
|
|
|
Buffer &buffer() { return buffer_; }
|
2013-11-26 12:56:37 +00:00
|
|
|
const Buffer &buffer() const { return buffer_; }
|
2013-06-01 16:59:03 +00:00
|
|
|
|
2013-06-25 21:27:45 +00:00
|
|
|
void Cancel() {
|
|
|
|
cancelled_ = true;
|
|
|
|
}
|
|
|
|
|
2015-10-06 17:07:09 +00:00
|
|
|
bool IsCancelled() const {
|
|
|
|
return cancelled_;
|
|
|
|
}
|
|
|
|
|
2013-11-26 12:56:37 +00: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 11:21:02 +00:00
|
|
|
if (callback_) {
|
|
|
|
callback_(*this);
|
|
|
|
}
|
2013-11-26 12:56:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 10:48:31 +00: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; }
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
private:
|
2020-06-28 08:03:03 +00:00
|
|
|
void Do(); // Actually does the download. Runs on thread.
|
2019-06-23 19:04:59 +00:00
|
|
|
int PerformGET(const std::string &url);
|
|
|
|
std::string RedirectLocation(const std::string &baseUrl);
|
2013-06-25 21:27:45 +00:00
|
|
|
void SetFailed(int code);
|
2021-08-22 10:21:44 +00:00
|
|
|
|
2021-05-01 17:19:27 +00:00
|
|
|
RequestProgress progress_;
|
2013-05-31 21:04:42 +00:00
|
|
|
Buffer buffer_;
|
2019-06-23 19:04:59 +00:00
|
|
|
std::vector<std::string> responseHeaders_;
|
2013-05-31 21:04:42 +00:00
|
|
|
std::string url_;
|
2021-05-15 05:46:03 +00:00
|
|
|
Path outfile_;
|
2019-09-28 18:40:10 +00:00
|
|
|
std::thread thread_;
|
2021-08-22 15:29:48 +00:00
|
|
|
const char *acceptMime_ = "*/*";
|
2019-09-28 18:40:10 +00:00
|
|
|
int resultCode_ = 0;
|
|
|
|
bool completed_ = false;
|
|
|
|
bool failed_ = false;
|
|
|
|
bool cancelled_ = false;
|
|
|
|
bool hidden_ = false;
|
2020-06-28 08:03:03 +00:00
|
|
|
bool joined_ = false;
|
2013-11-26 12:56:37 +00:00
|
|
|
std::function<void(Download &)> callback_;
|
2013-05-31 21:04:42 +00:00
|
|
|
};
|
|
|
|
|
2013-06-02 21:44:28 +00:00
|
|
|
using std::shared_ptr;
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
class Downloader {
|
|
|
|
public:
|
2013-06-25 21:27:45 +00:00
|
|
|
~Downloader() {
|
|
|
|
CancelAll();
|
|
|
|
}
|
2013-11-18 15:27:39 +00:00
|
|
|
|
2021-08-22 15:29:48 +00:00
|
|
|
std::shared_ptr<Download> StartDownload(const std::string &url, const Path &outfile, const char *acceptMime = nullptr);
|
2013-05-31 21:04:42 +00:00
|
|
|
|
2013-12-10 10:48:31 +00:00
|
|
|
std::shared_ptr<Download> StartDownloadWithCallback(
|
2013-11-26 12:56:37 +00:00
|
|
|
const std::string &url,
|
2021-05-15 05:46:03 +00:00
|
|
|
const Path &outfile,
|
2021-08-22 15:29:48 +00:00
|
|
|
std::function<void(Download &)> callback,
|
|
|
|
const char *acceptMime = nullptr);
|
2013-11-26 12:56:37 +00:00
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
// Drops finished downloads from the list.
|
|
|
|
void Update();
|
2013-06-25 21:27:45 +00:00
|
|
|
void CancelAll();
|
|
|
|
|
2013-11-29 15:31:19 +00:00
|
|
|
std::vector<float> GetCurrentProgress();
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
private:
|
2013-06-02 12:58:55 +00:00
|
|
|
std::vector<std::shared_ptr<Download>> downloads_;
|
2013-05-31 21:04:42 +00:00
|
|
|
};
|
|
|
|
|
2017-03-22 07:00:52 +00:00
|
|
|
} // http
|