parent
18bfa1c785
commit
86a3c8ce56
|
@ -140,17 +140,17 @@ void ClientMediaDownloader::step(Client *client)
|
||||||
// Remote media: check for completion of fetches
|
// Remote media: check for completion of fetches
|
||||||
if (m_httpfetch_active) {
|
if (m_httpfetch_active) {
|
||||||
bool fetched_something = false;
|
bool fetched_something = false;
|
||||||
HTTPFetchResult fetchresult;
|
HTTPFetchResult fetch_result;
|
||||||
|
|
||||||
while (httpfetch_async_get(m_httpfetch_caller, fetchresult)) {
|
while (httpfetch_async_get(m_httpfetch_caller, fetch_result)) {
|
||||||
m_httpfetch_active--;
|
m_httpfetch_active--;
|
||||||
fetched_something = true;
|
fetched_something = true;
|
||||||
|
|
||||||
// Is this a hashset (index.mth) or a media file?
|
// Is this a hashset (index.mth) or a media file?
|
||||||
if (fetchresult.request_id < m_remotes.size())
|
if (fetch_result.request_id < m_remotes.size())
|
||||||
remoteHashSetReceived(fetchresult);
|
remoteHashSetReceived(fetch_result);
|
||||||
else
|
else
|
||||||
remoteMediaReceived(fetchresult, client);
|
remoteMediaReceived(fetch_result, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fetched_something)
|
if (fetched_something)
|
||||||
|
@ -259,17 +259,17 @@ void ClientMediaDownloader::initialStep(Client *client)
|
||||||
actionstream << "Client: Contacting remote server \""
|
actionstream << "Client: Contacting remote server \""
|
||||||
<< remote->baseurl << "\"" << std::endl;
|
<< remote->baseurl << "\"" << std::endl;
|
||||||
|
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetch_request;
|
||||||
fetchrequest.url =
|
fetch_request.url =
|
||||||
remote->baseurl + MTHASHSET_FILE_NAME;
|
remote->baseurl + MTHASHSET_FILE_NAME;
|
||||||
fetchrequest.caller = m_httpfetch_caller;
|
fetch_request.caller = m_httpfetch_caller;
|
||||||
fetchrequest.request_id = m_httpfetch_next_id; // == i
|
fetch_request.request_id = m_httpfetch_next_id; // == i
|
||||||
fetchrequest.timeout = m_httpfetch_timeout;
|
fetch_request.timeout = m_httpfetch_timeout;
|
||||||
fetchrequest.connect_timeout = m_httpfetch_timeout;
|
fetch_request.connect_timeout = m_httpfetch_timeout;
|
||||||
fetchrequest.post_data = required_hash_set;
|
fetch_request.post_data = required_hash_set;
|
||||||
fetchrequest.extra_headers.push_back(
|
fetch_request.extra_headers.push_back(
|
||||||
"Content-Type: application/octet-stream");
|
"Content-Type: application/octet-stream");
|
||||||
httpfetch_async(fetchrequest);
|
httpfetch_async(fetch_request);
|
||||||
|
|
||||||
m_httpfetch_active++;
|
m_httpfetch_active++;
|
||||||
m_httpfetch_next_id++;
|
m_httpfetch_next_id++;
|
||||||
|
@ -279,21 +279,21 @@ void ClientMediaDownloader::initialStep(Client *client)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientMediaDownloader::remoteHashSetReceived(
|
void ClientMediaDownloader::remoteHashSetReceived(
|
||||||
const HTTPFetchResult &fetchresult)
|
const HTTPFetchResult &fetch_result)
|
||||||
{
|
{
|
||||||
u32 remote_id = fetchresult.request_id;
|
u32 remote_id = fetch_result.request_id;
|
||||||
assert(remote_id < m_remotes.size());
|
assert(remote_id < m_remotes.size());
|
||||||
RemoteServerStatus *remote = m_remotes[remote_id];
|
RemoteServerStatus *remote = m_remotes[remote_id];
|
||||||
|
|
||||||
m_outstanding_hash_sets--;
|
m_outstanding_hash_sets--;
|
||||||
|
|
||||||
if (fetchresult.succeeded) {
|
if (fetch_result.succeeded) {
|
||||||
try {
|
try {
|
||||||
// Server sent a list of file hashes that are
|
// Server sent a list of file hashes that are
|
||||||
// available on it, try to parse the list
|
// available on it, try to parse the list
|
||||||
|
|
||||||
std::set<std::string> sha1_set;
|
std::set<std::string> sha1_set;
|
||||||
deSerializeHashSet(fetchresult.data, sha1_set);
|
deSerializeHashSet(fetch_result.data, sha1_set);
|
||||||
|
|
||||||
// Parsing succeeded: For every file that is
|
// Parsing succeeded: For every file that is
|
||||||
// available on this server, add this server
|
// available on this server, add this server
|
||||||
|
@ -320,7 +320,7 @@ void ClientMediaDownloader::remoteHashSetReceived(
|
||||||
// Do NOT check for any particular response code (e.g. 404) here,
|
// Do NOT check for any particular response code (e.g. 404) here,
|
||||||
// because different servers respond differently
|
// because different servers respond differently
|
||||||
|
|
||||||
if (!fetchresult.succeeded && !fetchresult.timeout) {
|
if (!fetch_result.succeeded && !fetch_result.timeout) {
|
||||||
infostream << "Client: Enabling compatibility mode for remote "
|
infostream << "Client: Enabling compatibility mode for remote "
|
||||||
<< "server \"" << remote->baseurl << "\"" << std::endl;
|
<< "server \"" << remote->baseurl << "\"" << std::endl;
|
||||||
remote->request_by_filename = true;
|
remote->request_by_filename = true;
|
||||||
|
@ -338,7 +338,7 @@ void ClientMediaDownloader::remoteHashSetReceived(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientMediaDownloader::remoteMediaReceived(
|
void ClientMediaDownloader::remoteMediaReceived(
|
||||||
const HTTPFetchResult &fetchresult,
|
const HTTPFetchResult &fetch_result,
|
||||||
Client *client)
|
Client *client)
|
||||||
{
|
{
|
||||||
// Some remote server sent us a file.
|
// Some remote server sent us a file.
|
||||||
|
@ -349,7 +349,7 @@ void ClientMediaDownloader::remoteMediaReceived(
|
||||||
std::string name;
|
std::string name;
|
||||||
{
|
{
|
||||||
std::map<unsigned long, std::string>::iterator it =
|
std::map<unsigned long, std::string>::iterator it =
|
||||||
m_remote_file_transfers.find(fetchresult.request_id);
|
m_remote_file_transfers.find(fetch_result.request_id);
|
||||||
assert(it != m_remote_file_transfers.end());
|
assert(it != m_remote_file_transfers.end());
|
||||||
name = it->second;
|
name = it->second;
|
||||||
m_remote_file_transfers.erase(it);
|
m_remote_file_transfers.erase(it);
|
||||||
|
@ -368,9 +368,9 @@ void ClientMediaDownloader::remoteMediaReceived(
|
||||||
|
|
||||||
// If fetch succeeded, try to load media file
|
// If fetch succeeded, try to load media file
|
||||||
|
|
||||||
if (fetchresult.succeeded) {
|
if (fetch_result.succeeded) {
|
||||||
bool success = checkAndLoad(name, filestatus->sha1,
|
bool success = checkAndLoad(name, filestatus->sha1,
|
||||||
fetchresult.data, false, client);
|
fetch_result.data, false, client);
|
||||||
if (success) {
|
if (success) {
|
||||||
filestatus->received = true;
|
filestatus->received = true;
|
||||||
assert(m_uncached_received_count < m_uncached_count);
|
assert(m_uncached_received_count < m_uncached_count);
|
||||||
|
@ -445,14 +445,14 @@ void ClientMediaDownloader::startRemoteMediaTransfers()
|
||||||
<< "\"" << name << "\" "
|
<< "\"" << name << "\" "
|
||||||
<< "\"" << url << "\"" << std::endl;
|
<< "\"" << url << "\"" << std::endl;
|
||||||
|
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetch_request;
|
||||||
fetchrequest.url = url;
|
fetch_request.url = url;
|
||||||
fetchrequest.caller = m_httpfetch_caller;
|
fetch_request.caller = m_httpfetch_caller;
|
||||||
fetchrequest.request_id = m_httpfetch_next_id;
|
fetch_request.request_id = m_httpfetch_next_id;
|
||||||
fetchrequest.timeout = 0; // no data timeout!
|
fetch_request.timeout = 0; // no data timeout!
|
||||||
fetchrequest.connect_timeout =
|
fetch_request.connect_timeout =
|
||||||
m_httpfetch_timeout;
|
m_httpfetch_timeout;
|
||||||
httpfetch_async(fetchrequest);
|
httpfetch_async(fetch_request);
|
||||||
|
|
||||||
m_remote_file_transfers.insert(std::make_pair(
|
m_remote_file_transfers.insert(std::make_pair(
|
||||||
m_httpfetch_next_id,
|
m_httpfetch_next_id,
|
||||||
|
|
|
@ -96,8 +96,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialStep(Client *client);
|
void initialStep(Client *client);
|
||||||
void remoteHashSetReceived(const HTTPFetchResult &fetchresult);
|
void remoteHashSetReceived(const HTTPFetchResult &fetch_result);
|
||||||
void remoteMediaReceived(const HTTPFetchResult &fetchresult,
|
void remoteMediaReceived(const HTTPFetchResult &fetch_result,
|
||||||
Client *client);
|
Client *client);
|
||||||
s32 selectRemoteServer(FileStatus *filestatus);
|
s32 selectRemoteServer(FileStatus *filestatus);
|
||||||
void startRemoteMediaTransfers();
|
void startRemoteMediaTransfers();
|
||||||
|
|
|
@ -31,44 +31,33 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
|
|
||||||
Json::Value fetchJsonValue(const std::string &url,
|
Json::Value fetchJsonValue(const std::string &url,
|
||||||
std::vector<std::string> *extra_headers) {
|
std::vector<std::string> *extra_headers)
|
||||||
|
{
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetch_request;
|
||||||
HTTPFetchResult fetchresult;
|
HTTPFetchResult fetch_result;
|
||||||
fetchrequest.url = url;
|
fetch_request.url = url;
|
||||||
fetchrequest.caller = HTTPFETCH_SYNC;
|
fetch_request.caller = HTTPFETCH_SYNC;
|
||||||
|
|
||||||
if (extra_headers != NULL)
|
if (extra_headers != NULL)
|
||||||
fetchrequest.extra_headers = *extra_headers;
|
fetch_request.extra_headers = *extra_headers;
|
||||||
|
|
||||||
httpfetch_sync(fetchrequest,fetchresult);
|
httpfetch_sync(fetch_request, fetch_result);
|
||||||
|
|
||||||
if (!fetchresult.succeeded) {
|
if (!fetch_result.succeeded) {
|
||||||
return Json::Value();
|
return Json::Value();
|
||||||
}
|
}
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
Json::Reader reader;
|
Json::Reader reader;
|
||||||
std::istringstream stream(fetchresult.data);
|
std::istringstream stream(fetch_result.data);
|
||||||
|
|
||||||
if (!reader.parse( stream, root ) )
|
if (!reader.parse(stream, root)) {
|
||||||
{
|
|
||||||
errorstream << "URL: " << url << std::endl;
|
errorstream << "URL: " << url << std::endl;
|
||||||
errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
|
errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
|
||||||
errorstream << "data: \"" << fetchresult.data << "\"" << std::endl;
|
errorstream << "data: \"" << fetch_result.data << "\"" << std::endl;
|
||||||
return Json::Value();
|
return Json::Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.isArray()) {
|
|
||||||
return root;
|
return root;
|
||||||
}
|
|
||||||
if ((root["list"].isArray())) {
|
|
||||||
return root["list"];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json::Value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ModStoreMod> readModStoreList(Json::Value& modlist) {
|
std::vector<ModStoreMod> readModStoreList(Json::Value& modlist) {
|
||||||
|
|
|
@ -528,27 +528,26 @@ bool GUIEngine::setTexture(texture_layer layer, std::string texturepath,
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
bool GUIEngine::downloadFile(std::string url,std::string target)
|
bool GUIEngine::downloadFile(std::string url, std::string target)
|
||||||
{
|
{
|
||||||
#if USE_CURL
|
#if USE_CURL
|
||||||
std::ofstream targetfile(target.c_str(), std::ios::out | std::ios::binary);
|
std::ofstream target_file(target.c_str(), std::ios::out | std::ios::binary);
|
||||||
|
|
||||||
if (!targetfile.good()) {
|
if (!target_file.good()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetch_request;
|
||||||
HTTPFetchResult fetchresult;
|
HTTPFetchResult fetch_result;
|
||||||
fetchrequest.url = url;
|
fetch_request.url = url;
|
||||||
fetchrequest.caller = HTTPFETCH_SYNC;
|
fetch_request.caller = HTTPFETCH_SYNC;
|
||||||
fetchrequest.timeout = g_settings->getS32("curl_file_download_timeout");
|
fetch_request.timeout = g_settings->getS32("curl_file_download_timeout");
|
||||||
httpfetch_sync(fetchrequest, fetchresult);
|
httpfetch_sync(fetch_request, fetch_result);
|
||||||
|
|
||||||
if (fetchresult.succeeded) {
|
if (!fetch_result.succeeded) {
|
||||||
targetfile << fetchresult.data;
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
target_file << fetch_result.data;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -52,12 +52,12 @@ HTTPFetchRequest::HTTPFetchRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void httpfetch_deliver_result(const HTTPFetchResult &fetchresult)
|
static void httpfetch_deliver_result(const HTTPFetchResult &fetch_result)
|
||||||
{
|
{
|
||||||
unsigned long caller = fetchresult.caller;
|
unsigned long caller = fetch_result.caller;
|
||||||
if (caller != HTTPFETCH_DISCARD) {
|
if (caller != HTTPFETCH_DISCARD) {
|
||||||
JMutexAutoLock lock(g_httpfetch_mutex);
|
JMutexAutoLock lock(g_httpfetch_mutex);
|
||||||
g_httpfetch_results[caller].push_back(fetchresult);
|
g_httpfetch_results[caller].push_back(fetch_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ void httpfetch_caller_free(unsigned long caller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetchresult)
|
bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(g_httpfetch_mutex);
|
JMutexAutoLock lock(g_httpfetch_mutex);
|
||||||
|
|
||||||
|
@ -108,13 +108,13 @@ bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetchresult)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check that result queue is nonempty
|
// Check that result queue is nonempty
|
||||||
std::list<HTTPFetchResult> &callerresults = it->second;
|
std::list<HTTPFetchResult> &caller_results = it->second;
|
||||||
if (callerresults.empty())
|
if (caller_results.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Pop first result
|
// Pop first result
|
||||||
fetchresult = callerresults.front();
|
fetch_result = caller_results.front();
|
||||||
callerresults.pop_front();
|
caller_results.pop_front();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +175,19 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HTTPFetchOngoing
|
class HTTPFetchOngoing
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
HTTPFetchOngoing(HTTPFetchRequest request, CurlHandlePool *pool);
|
||||||
|
~HTTPFetchOngoing();
|
||||||
|
|
||||||
|
CURLcode start(CURLM *multi);
|
||||||
|
const HTTPFetchResult * complete(CURLcode res);
|
||||||
|
|
||||||
|
const HTTPFetchRequest &getRequest() const { return request; };
|
||||||
|
const CURL *getEasyHandle() const { return curl; };
|
||||||
|
|
||||||
|
private:
|
||||||
CurlHandlePool *pool;
|
CurlHandlePool *pool;
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
CURLM *multi;
|
CURLM *multi;
|
||||||
|
@ -184,21 +195,26 @@ struct HTTPFetchOngoing
|
||||||
HTTPFetchResult result;
|
HTTPFetchResult result;
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
char *post_fields;
|
char *post_fields;
|
||||||
struct curl_slist *httpheader;
|
struct curl_slist *http_header;
|
||||||
curl_httppost *post;
|
curl_httppost *post;
|
||||||
|
};
|
||||||
|
|
||||||
HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
|
|
||||||
|
HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
|
||||||
pool(pool_),
|
pool(pool_),
|
||||||
curl(NULL),
|
curl(NULL),
|
||||||
multi(NULL),
|
multi(NULL),
|
||||||
request(request_),
|
request(request_),
|
||||||
result(request_),
|
result(request_),
|
||||||
oss(std::ios::binary),
|
oss(std::ios::binary),
|
||||||
httpheader(NULL),
|
http_header(NULL),
|
||||||
post(NULL)
|
post(NULL)
|
||||||
{
|
{
|
||||||
curl = pool->alloc();
|
curl = pool->alloc();
|
||||||
if (curl != NULL) {
|
if (curl == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Set static cURL options
|
// Set static cURL options
|
||||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
||||||
|
@ -236,8 +252,7 @@ struct HTTPFetchOngoing
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
||||||
httpfetch_discardfunction);
|
httpfetch_discardfunction);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
||||||
httpfetch_writefunction);
|
httpfetch_writefunction);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
|
||||||
|
@ -250,8 +265,7 @@ struct HTTPFetchOngoing
|
||||||
curl_httppost *last = NULL;
|
curl_httppost *last = NULL;
|
||||||
for (std::map<std::string, std::string>::iterator it =
|
for (std::map<std::string, std::string>::iterator it =
|
||||||
request.post_fields.begin();
|
request.post_fields.begin();
|
||||||
it != request.post_fields.end();
|
it != request.post_fields.end(); ++it) {
|
||||||
++it) {
|
|
||||||
curl_formadd(&post, &last,
|
curl_formadd(&post, &last,
|
||||||
CURLFORM_NAMELENGTH, it->first.size(),
|
CURLFORM_NAMELENGTH, it->first.size(),
|
||||||
CURLFORM_PTRNAME, it->first.c_str(),
|
CURLFORM_PTRNAME, it->first.c_str(),
|
||||||
|
@ -262,9 +276,8 @@ struct HTTPFetchOngoing
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
|
||||||
// request.post_fields must now *never* be
|
// request.post_fields must now *never* be
|
||||||
// modified until CURLOPT_HTTPPOST is cleared
|
// modified until CURLOPT_HTTPPOST is cleared
|
||||||
} else {
|
} else if (request.post_data.empty()) {
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||||
if (request.post_data.empty()) {
|
|
||||||
std::string str;
|
std::string str;
|
||||||
for (std::map<std::string, std::string>::iterator it =
|
for (std::map<std::string, std::string>::iterator it =
|
||||||
request.post_fields.begin();
|
request.post_fields.begin();
|
||||||
|
@ -281,6 +294,7 @@ struct HTTPFetchOngoing
|
||||||
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS,
|
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS,
|
||||||
str.c_str());
|
str.c_str());
|
||||||
} else {
|
} else {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
|
||||||
request.post_data.size());
|
request.post_data.size());
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
|
||||||
|
@ -288,76 +302,72 @@ struct HTTPFetchOngoing
|
||||||
// request.post_data must now *never* be
|
// request.post_data must now *never* be
|
||||||
// modified until CURLOPT_POSTFIELDS is cleared
|
// modified until CURLOPT_POSTFIELDS is cleared
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Set additional HTTP headers
|
// Set additional HTTP headers
|
||||||
for (size_t i = 0; i < request.extra_headers.size(); ++i) {
|
for (std::vector<std::string>::iterator it = request.extra_headers.begin();
|
||||||
httpheader = curl_slist_append(
|
it != request.extra_headers.end(); ++it) {
|
||||||
httpheader,
|
http_header = curl_slist_append(http_header, it->c_str());
|
||||||
request.extra_headers[i].c_str());
|
|
||||||
}
|
}
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, httpheader);
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);
|
||||||
|
|
||||||
if (!g_settings->getBool("curl_verify_cert")) {
|
if (!g_settings->getBool("curl_verify_cert")) {
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CURLcode start(CURLM *multi_)
|
CURLcode HTTPFetchOngoing::start(CURLM *multi_)
|
||||||
{
|
{
|
||||||
if (curl == NULL)
|
if (!curl)
|
||||||
return CURLE_FAILED_INIT;
|
return CURLE_FAILED_INIT;
|
||||||
|
|
||||||
if (multi_) {
|
if (!multi_) {
|
||||||
|
// Easy interface (sync)
|
||||||
|
return curl_easy_perform(curl);
|
||||||
|
}
|
||||||
|
|
||||||
// Multi interface (async)
|
// Multi interface (async)
|
||||||
CURLMcode mres = curl_multi_add_handle(multi_, curl);
|
CURLMcode mres = curl_multi_add_handle(multi_, curl);
|
||||||
if (mres != CURLM_OK) {
|
if (mres != CURLM_OK) {
|
||||||
errorstream<<"curl_multi_add_handle"
|
errorstream << "curl_multi_add_handle"
|
||||||
<<" returned error code "<<mres
|
<< " returned error code " << mres
|
||||||
<<std::endl;
|
<< std::endl;
|
||||||
return CURLE_FAILED_INIT;
|
return CURLE_FAILED_INIT;
|
||||||
}
|
}
|
||||||
multi = multi_; // store for curl_multi_remove_handle
|
multi = multi_; // store for curl_multi_remove_handle
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Easy interface (sync)
|
|
||||||
return curl_easy_perform(curl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void complete(CURLcode res)
|
const HTTPFetchResult * HTTPFetchOngoing::complete(CURLcode res)
|
||||||
{
|
{
|
||||||
result.succeeded = (res == CURLE_OK);
|
result.succeeded = (res == CURLE_OK);
|
||||||
result.timeout = (res == CURLE_OPERATION_TIMEDOUT);
|
result.timeout = (res == CURLE_OPERATION_TIMEDOUT);
|
||||||
result.data = oss.str();
|
result.data = oss.str();
|
||||||
|
|
||||||
// Get HTTP/FTP response code
|
// Get HTTP/FTP response code
|
||||||
result.response_code = 0;
|
result.response_code = 0;
|
||||||
if (curl != NULL) {
|
if (curl && (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
|
||||||
if (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
|
&result.response_code) != CURLE_OK)) {
|
||||||
&result.response_code) != CURLE_OK) {
|
// We failed to get a return code, make sure it is still 0
|
||||||
//we failed to get a return code make sure it is still 0
|
|
||||||
result.response_code = 0;
|
result.response_code = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (res != CURLE_OK) {
|
if (res != CURLE_OK) {
|
||||||
errorstream<<request.url<<" not found ("
|
errorstream << request.url << " not found ("
|
||||||
<<curl_easy_strerror(res)<<")"
|
<< curl_easy_strerror(res) << ")"
|
||||||
<<" (response code "<<result.response_code<<")"
|
<< " (response code " << result.response_code << ")"
|
||||||
<<std::endl;
|
<< std::endl;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~HTTPFetchOngoing()
|
return &result;
|
||||||
{
|
}
|
||||||
if (multi != NULL) {
|
|
||||||
|
HTTPFetchOngoing::~HTTPFetchOngoing()
|
||||||
|
{
|
||||||
|
if (multi) {
|
||||||
CURLMcode mres = curl_multi_remove_handle(multi, curl);
|
CURLMcode mres = curl_multi_remove_handle(multi, curl);
|
||||||
if (mres != CURLM_OK) {
|
if (mres != CURLM_OK) {
|
||||||
errorstream<<"curl_multi_remove_handle"
|
errorstream << "curl_multi_remove_handle"
|
||||||
<<" returned error code "<<mres
|
<< " returned error code " << mres
|
||||||
<<std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,19 +376,19 @@ struct HTTPFetchOngoing
|
||||||
httpfetch_discardfunction);
|
httpfetch_discardfunction);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
||||||
if (httpheader != NULL) {
|
if (http_header) {
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
|
||||||
curl_slist_free_all(httpheader);
|
curl_slist_free_all(http_header);
|
||||||
}
|
}
|
||||||
if (post != NULL) {
|
if (post) {
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, NULL);
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, NULL);
|
||||||
curl_formfree(post);
|
curl_formfree(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the cURL handle for reuse
|
// Store the cURL handle for reuse
|
||||||
pool->free(curl);
|
pool->free(curl);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
class CurlFetchThread : public JThread
|
class CurlFetchThread : public JThread
|
||||||
{
|
{
|
||||||
|
@ -391,7 +401,7 @@ protected:
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
RequestType type;
|
RequestType type;
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetch_request;
|
||||||
Event *event;
|
Event *event;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -412,11 +422,11 @@ public:
|
||||||
m_parallel_limit = 1;
|
m_parallel_limit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void requestFetch(const HTTPFetchRequest &fetchrequest)
|
void requestFetch(const HTTPFetchRequest &fetch_request)
|
||||||
{
|
{
|
||||||
Request req;
|
Request req;
|
||||||
req.type = RT_FETCH;
|
req.type = RT_FETCH;
|
||||||
req.fetchrequest = fetchrequest;
|
req.fetch_request = fetch_request;
|
||||||
req.event = NULL;
|
req.event = NULL;
|
||||||
m_requests.push_back(req);
|
m_requests.push_back(req);
|
||||||
}
|
}
|
||||||
|
@ -425,7 +435,7 @@ public:
|
||||||
{
|
{
|
||||||
Request req;
|
Request req;
|
||||||
req.type = RT_CLEAR;
|
req.type = RT_CLEAR;
|
||||||
req.fetchrequest.caller = caller;
|
req.fetch_request.caller = caller;
|
||||||
req.event = event;
|
req.event = event;
|
||||||
m_requests.push_back(req);
|
m_requests.push_back(req);
|
||||||
}
|
}
|
||||||
|
@ -446,25 +456,25 @@ protected:
|
||||||
if (req.type == RT_FETCH) {
|
if (req.type == RT_FETCH) {
|
||||||
// New fetch, queue until there are less
|
// New fetch, queue until there are less
|
||||||
// than m_parallel_limit ongoing fetches
|
// than m_parallel_limit ongoing fetches
|
||||||
m_queued_fetches.push_back(req.fetchrequest);
|
m_queued_fetches.push_back(req.fetch_request);
|
||||||
|
|
||||||
// see processQueued() for what happens next
|
// see processQueued() for what happens next
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (req.type == RT_CLEAR) {
|
else if (req.type == RT_CLEAR) {
|
||||||
unsigned long caller = req.fetchrequest.caller;
|
unsigned long caller = req.fetch_request.caller;
|
||||||
|
|
||||||
// Abort all ongoing fetches for the caller
|
// Abort all ongoing fetches for the caller
|
||||||
for (std::vector<HTTPFetchOngoing*>::iterator
|
for (std::vector<HTTPFetchOngoing*>::iterator
|
||||||
it = m_all_ongoing.begin();
|
it = m_all_ongoing.begin();
|
||||||
it != m_all_ongoing.end();) {
|
it != m_all_ongoing.end();) {
|
||||||
if ((*it)->request.caller == caller) {
|
if ((*it)->getRequest().caller == caller) {
|
||||||
delete (*it);
|
delete (*it);
|
||||||
it = m_all_ongoing.erase(it);
|
it = m_all_ongoing.erase(it);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Also abort all queued fetches for the caller
|
// Also abort all queued fetches for the caller
|
||||||
for (std::list<HTTPFetchRequest>::iterator
|
for (std::list<HTTPFetchRequest>::iterator
|
||||||
|
@ -503,8 +513,7 @@ protected:
|
||||||
m_all_ongoing.push_back(ongoing);
|
m_all_ongoing.push_back(ongoing);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ongoing->complete(res);
|
httpfetch_deliver_result(*ongoing->complete(res));
|
||||||
httpfetch_deliver_result(ongoing->result);
|
|
||||||
delete ongoing;
|
delete ongoing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,7 +526,7 @@ protected:
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (i = 0; i < m_all_ongoing.size(); ++i) {
|
for (i = 0; i < m_all_ongoing.size(); ++i) {
|
||||||
if (m_all_ongoing[i]->curl == msg->easy_handle) {
|
if (m_all_ongoing[i]->getEasyHandle() == msg->easy_handle) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -525,8 +534,7 @@ protected:
|
||||||
if (msg->msg == CURLMSG_DONE && found) {
|
if (msg->msg == CURLMSG_DONE && found) {
|
||||||
// m_all_ongoing[i] succeeded or failed.
|
// m_all_ongoing[i] succeeded or failed.
|
||||||
HTTPFetchOngoing *ongoing = m_all_ongoing[i];
|
HTTPFetchOngoing *ongoing = m_all_ongoing[i];
|
||||||
ongoing->complete(msg->data.result);
|
httpfetch_deliver_result(*ongoing->complete(msg->data.result));
|
||||||
httpfetch_deliver_result(ongoing->result);
|
|
||||||
delete ongoing;
|
delete ongoing;
|
||||||
m_all_ongoing.erase(m_all_ongoing.begin() + i);
|
m_all_ongoing.erase(m_all_ongoing.begin() + i);
|
||||||
}
|
}
|
||||||
|
@ -719,9 +727,9 @@ void httpfetch_cleanup()
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpfetch_async(const HTTPFetchRequest &fetchrequest)
|
void httpfetch_async(const HTTPFetchRequest &fetch_request)
|
||||||
{
|
{
|
||||||
g_httpfetch_thread->requestFetch(fetchrequest);
|
g_httpfetch_thread->requestFetch(fetch_request);
|
||||||
if (!g_httpfetch_thread->IsRunning())
|
if (!g_httpfetch_thread->IsRunning())
|
||||||
g_httpfetch_thread->Start();
|
g_httpfetch_thread->Start();
|
||||||
}
|
}
|
||||||
|
@ -738,18 +746,17 @@ static void httpfetch_request_clear(unsigned long caller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpfetch_sync(const HTTPFetchRequest &fetchrequest,
|
void httpfetch_sync(const HTTPFetchRequest &fetch_request,
|
||||||
HTTPFetchResult &fetchresult)
|
HTTPFetchResult &fetch_result)
|
||||||
{
|
{
|
||||||
// Create ongoing fetch data and make a cURL handle
|
// Create ongoing fetch data and make a cURL handle
|
||||||
// Set cURL options based on HTTPFetchRequest
|
// Set cURL options based on HTTPFetchRequest
|
||||||
CurlHandlePool pool;
|
CurlHandlePool pool;
|
||||||
HTTPFetchOngoing ongoing(fetchrequest, &pool);
|
HTTPFetchOngoing ongoing(fetch_request, &pool);
|
||||||
// Do the fetch (curl_easy_perform)
|
// Do the fetch (curl_easy_perform)
|
||||||
CURLcode res = ongoing.start(NULL);
|
CURLcode res = ongoing.start(NULL);
|
||||||
// Update fetchresult
|
// Update fetch result
|
||||||
ongoing.complete(res);
|
fetch_result = *ongoing.complete(res);
|
||||||
fetchresult = ongoing.result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // USE_CURL
|
#else // USE_CURL
|
||||||
|
@ -768,26 +775,26 @@ void httpfetch_cleanup()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpfetch_async(const HTTPFetchRequest &fetchrequest)
|
void httpfetch_async(const HTTPFetchRequest &fetch_request)
|
||||||
{
|
{
|
||||||
errorstream<<"httpfetch_async: unable to fetch "<<fetchrequest.url
|
errorstream << "httpfetch_async: unable to fetch " << fetch_request.url
|
||||||
<<" because USE_CURL=0"<<std::endl;
|
<< " because USE_CURL=0" << std::endl;
|
||||||
|
|
||||||
HTTPFetchResult fetchresult(fetchrequest); // sets succeeded = false etc.
|
HTTPFetchResult fetch_result(fetch_request); // sets succeeded = false etc.
|
||||||
httpfetch_deliver_result(fetchresult);
|
httpfetch_deliver_result(fetch_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void httpfetch_request_clear(unsigned long caller)
|
static void httpfetch_request_clear(unsigned long caller)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpfetch_sync(const HTTPFetchRequest &fetchrequest,
|
void httpfetch_sync(const HTTPFetchRequest &fetch_request,
|
||||||
HTTPFetchResult &fetchresult)
|
HTTPFetchResult &fetch_result)
|
||||||
{
|
{
|
||||||
errorstream<<"httpfetch_sync: unable to fetch "<<fetchrequest.url
|
errorstream << "httpfetch_sync: unable to fetch " << fetch_request.url
|
||||||
<<" because USE_CURL=0"<<std::endl;
|
<< " because USE_CURL=0" << std::endl;
|
||||||
|
|
||||||
fetchresult = HTTPFetchResult(fetchrequest); // sets succeeded = false etc.
|
fetch_result = HTTPFetchResult(fetch_request); // sets succeeded = false etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USE_CURL
|
#endif // USE_CURL
|
||||||
|
|
|
@ -88,14 +88,14 @@ struct HTTPFetchResult
|
||||||
request_id = 0;
|
request_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPFetchResult(const HTTPFetchRequest &fetchrequest)
|
HTTPFetchResult(const HTTPFetchRequest &fetch_request)
|
||||||
{
|
{
|
||||||
succeeded = false;
|
succeeded = false;
|
||||||
timeout = false;
|
timeout = false;
|
||||||
response_code = 0;
|
response_code = 0;
|
||||||
data = "";
|
data = "";
|
||||||
caller = fetchrequest.caller;
|
caller = fetch_request.caller;
|
||||||
request_id = fetchrequest.request_id;
|
request_id = fetch_request.request_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -107,11 +107,11 @@ void httpfetch_init(int parallel_limit);
|
||||||
void httpfetch_cleanup();
|
void httpfetch_cleanup();
|
||||||
|
|
||||||
// Starts an asynchronous HTTP fetch request
|
// Starts an asynchronous HTTP fetch request
|
||||||
void httpfetch_async(const HTTPFetchRequest &fetchrequest);
|
void httpfetch_async(const HTTPFetchRequest &fetch_request);
|
||||||
|
|
||||||
// If any fetch for the given caller ID is complete, removes it from the
|
// If any fetch for the given caller ID is complete, removes it from the
|
||||||
// result queue, sets fetchresult and returns true. Otherwise returns false.
|
// result queue, sets the fetch result and returns true. Otherwise returns false.
|
||||||
bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetchresult);
|
bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result);
|
||||||
|
|
||||||
// Allocates a caller ID for httpfetch_async
|
// Allocates a caller ID for httpfetch_async
|
||||||
// Not required if you want to set caller = HTTPFETCH_DISCARD
|
// Not required if you want to set caller = HTTPFETCH_DISCARD
|
||||||
|
@ -124,8 +124,8 @@ void httpfetch_caller_free(unsigned long caller);
|
||||||
|
|
||||||
// Performs a synchronous HTTP request. This blocks and therefore should
|
// Performs a synchronous HTTP request. This blocks and therefore should
|
||||||
// only be used from background threads.
|
// only be used from background threads.
|
||||||
void httpfetch_sync(const HTTPFetchRequest &fetchrequest,
|
void httpfetch_sync(const HTTPFetchRequest &fetch_request,
|
||||||
HTTPFetchResult &fetchresult);
|
HTTPFetchResult &fetch_result);
|
||||||
|
|
||||||
|
|
||||||
#endif // !HTTPFETCH_HEADER
|
#endif // !HTTPFETCH_HEADER
|
||||||
|
|
11
src/mods.cpp
11
src/mods.cpp
|
@ -339,19 +339,14 @@ Json::Value getModstoreUrl(std::string url)
|
||||||
|
|
||||||
bool special_http_header = true;
|
bool special_http_header = true;
|
||||||
|
|
||||||
try{
|
try {
|
||||||
special_http_header = g_settings->getBool("modstore_disable_special_http_header");
|
special_http_header = g_settings->getBool("modstore_disable_special_http_header");
|
||||||
}
|
} catch (SettingNotFoundException) {}
|
||||||
catch(SettingNotFoundException &e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (special_http_header) {
|
if (special_http_header) {
|
||||||
extra_headers.push_back("Accept: application/vnd.minetest.mmdb-v1+json");
|
extra_headers.push_back("Accept: application/vnd.minetest.mmdb-v1+json");
|
||||||
return fetchJsonValue(url, &extra_headers);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return fetchJsonValue(url, NULL);
|
|
||||||
}
|
}
|
||||||
|
return fetchJsonValue(url, special_http_header ? &extra_headers : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,17 +70,24 @@ std::vector<ServerListSpec> getOnline()
|
||||||
Json::Value root = fetchJsonValue(
|
Json::Value root = fetchJsonValue(
|
||||||
(g_settings->get("serverlist_url") + "/list").c_str(), NULL);
|
(g_settings->get("serverlist_url") + "/list").c_str(), NULL);
|
||||||
|
|
||||||
std::vector<ServerListSpec> serverlist;
|
std::vector<ServerListSpec> server_list;
|
||||||
|
|
||||||
|
if (!root.isObject()) {
|
||||||
|
return server_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
root = root["list"];
|
||||||
|
if (!root.isArray()) {
|
||||||
|
return server_list;
|
||||||
|
}
|
||||||
|
|
||||||
if (root.isArray()) {
|
|
||||||
for (unsigned int i = 0; i < root.size(); i++) {
|
for (unsigned int i = 0; i < root.size(); i++) {
|
||||||
if (root[i].isObject()) {
|
if (root[i].isObject()) {
|
||||||
serverlist.push_back(root[i]);
|
server_list.push_back(root[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return serverlist;
|
return server_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,11 +243,11 @@ void sendAnnounce(const std::string &action,
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::FastWriter writer;
|
Json::FastWriter writer;
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetch_request;
|
||||||
fetchrequest.url = g_settings->get("serverlist_url") + std::string("/announce");
|
fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce");
|
||||||
fetchrequest.post_fields["json"] = writer.write(server);
|
fetch_request.post_fields["json"] = writer.write(server);
|
||||||
fetchrequest.multipart = true;
|
fetch_request.multipart = true;
|
||||||
httpfetch_async(fetchrequest);
|
httpfetch_async(fetch_request);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue