diff options
-rw-r--r-- | src/clientmedia.cpp | 60 | ||||
-rw-r--r-- | src/clientmedia.h | 4 | ||||
-rw-r--r-- | src/convert_json.cpp | 39 | ||||
-rw-r--r-- | src/guiEngine.cpp | 23 | ||||
-rw-r--r-- | src/httpfetch.cpp | 437 | ||||
-rw-r--r-- | src/httpfetch.h | 16 | ||||
-rw-r--r-- | src/mods.cpp | 11 | ||||
-rw-r--r-- | src/serverlist.cpp | 31 |
8 files changed, 309 insertions, 312 deletions
diff --git a/src/clientmedia.cpp b/src/clientmedia.cpp index c1043c769..e2679ed46 100644 --- a/src/clientmedia.cpp +++ b/src/clientmedia.cpp @@ -140,17 +140,17 @@ void ClientMediaDownloader::step(Client *client) // Remote media: check for completion of fetches if (m_httpfetch_active) { 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--; fetched_something = true; // Is this a hashset (index.mth) or a media file? - if (fetchresult.request_id < m_remotes.size()) - remoteHashSetReceived(fetchresult); + if (fetch_result.request_id < m_remotes.size()) + remoteHashSetReceived(fetch_result); else - remoteMediaReceived(fetchresult, client); + remoteMediaReceived(fetch_result, client); } if (fetched_something) @@ -259,17 +259,17 @@ void ClientMediaDownloader::initialStep(Client *client) actionstream << "Client: Contacting remote server \"" << remote->baseurl << "\"" << std::endl; - HTTPFetchRequest fetchrequest; - fetchrequest.url = + HTTPFetchRequest fetch_request; + fetch_request.url = remote->baseurl + MTHASHSET_FILE_NAME; - fetchrequest.caller = m_httpfetch_caller; - fetchrequest.request_id = m_httpfetch_next_id; // == i - fetchrequest.timeout = m_httpfetch_timeout; - fetchrequest.connect_timeout = m_httpfetch_timeout; - fetchrequest.post_data = required_hash_set; - fetchrequest.extra_headers.push_back( + fetch_request.caller = m_httpfetch_caller; + fetch_request.request_id = m_httpfetch_next_id; // == i + fetch_request.timeout = m_httpfetch_timeout; + fetch_request.connect_timeout = m_httpfetch_timeout; + fetch_request.post_data = required_hash_set; + fetch_request.extra_headers.push_back( "Content-Type: application/octet-stream"); - httpfetch_async(fetchrequest); + httpfetch_async(fetch_request); m_httpfetch_active++; m_httpfetch_next_id++; @@ -279,21 +279,21 @@ void ClientMediaDownloader::initialStep(Client *client) } 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()); RemoteServerStatus *remote = m_remotes[remote_id]; m_outstanding_hash_sets--; - if (fetchresult.succeeded) { + if (fetch_result.succeeded) { try { // Server sent a list of file hashes that are // available on it, try to parse the list std::set<std::string> sha1_set; - deSerializeHashSet(fetchresult.data, sha1_set); + deSerializeHashSet(fetch_result.data, sha1_set); // Parsing succeeded: For every file that is // 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, // because different servers respond differently - if (!fetchresult.succeeded && !fetchresult.timeout) { + if (!fetch_result.succeeded && !fetch_result.timeout) { infostream << "Client: Enabling compatibility mode for remote " << "server \"" << remote->baseurl << "\"" << std::endl; remote->request_by_filename = true; @@ -338,7 +338,7 @@ void ClientMediaDownloader::remoteHashSetReceived( } void ClientMediaDownloader::remoteMediaReceived( - const HTTPFetchResult &fetchresult, + const HTTPFetchResult &fetch_result, Client *client) { // Some remote server sent us a file. @@ -349,7 +349,7 @@ void ClientMediaDownloader::remoteMediaReceived( std::string name; { 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()); name = it->second; m_remote_file_transfers.erase(it); @@ -368,9 +368,9 @@ void ClientMediaDownloader::remoteMediaReceived( // If fetch succeeded, try to load media file - if (fetchresult.succeeded) { + if (fetch_result.succeeded) { bool success = checkAndLoad(name, filestatus->sha1, - fetchresult.data, false, client); + fetch_result.data, false, client); if (success) { filestatus->received = true; assert(m_uncached_received_count < m_uncached_count); @@ -445,14 +445,14 @@ void ClientMediaDownloader::startRemoteMediaTransfers() << "\"" << name << "\" " << "\"" << url << "\"" << std::endl; - HTTPFetchRequest fetchrequest; - fetchrequest.url = url; - fetchrequest.caller = m_httpfetch_caller; - fetchrequest.request_id = m_httpfetch_next_id; - fetchrequest.timeout = 0; // no data timeout! - fetchrequest.connect_timeout = + HTTPFetchRequest fetch_request; + fetch_request.url = url; + fetch_request.caller = m_httpfetch_caller; + fetch_request.request_id = m_httpfetch_next_id; + fetch_request.timeout = 0; // no data timeout! + fetch_request.connect_timeout = m_httpfetch_timeout; - httpfetch_async(fetchrequest); + httpfetch_async(fetch_request); m_remote_file_transfers.insert(std::make_pair( m_httpfetch_next_id, diff --git a/src/clientmedia.h b/src/clientmedia.h index 540044239..1f0da70d9 100644 --- a/src/clientmedia.h +++ b/src/clientmedia.h @@ -96,8 +96,8 @@ private: }; void initialStep(Client *client); - void remoteHashSetReceived(const HTTPFetchResult &fetchresult); - void remoteMediaReceived(const HTTPFetchResult &fetchresult, + void remoteHashSetReceived(const HTTPFetchResult &fetch_result); + void remoteMediaReceived(const HTTPFetchResult &fetch_result, Client *client); s32 selectRemoteServer(FileStatus *filestatus); void startRemoteMediaTransfers(); diff --git a/src/convert_json.cpp b/src/convert_json.cpp index c5c69d93c..cea089623 100644 --- a/src/convert_json.cpp +++ b/src/convert_json.cpp @@ -30,45 +30,34 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "httpfetch.h" #include "porting.h" -Json::Value fetchJsonValue(const std::string &url, - std::vector<std::string> *extra_headers) { - - HTTPFetchRequest fetchrequest; - HTTPFetchResult fetchresult; - fetchrequest.url = url; - fetchrequest.caller = HTTPFETCH_SYNC; +Json::Value fetchJsonValue(const std::string &url, + std::vector<std::string> *extra_headers) +{ + HTTPFetchRequest fetch_request; + HTTPFetchResult fetch_result; + fetch_request.url = url; + fetch_request.caller = HTTPFETCH_SYNC; 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(); } Json::Value root; 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 << "Failed to parse json data " << reader.getFormattedErrorMessages(); - errorstream << "data: \"" << fetchresult.data << "\"" << std::endl; + errorstream << "data: \"" << fetch_result.data << "\"" << std::endl; return Json::Value(); } - if (root.isArray()) { - return root; - } - if ((root["list"].isArray())) { - return root["list"]; - } - else { - return root; - } - - return Json::Value(); + return root; } std::vector<ModStoreMod> readModStoreList(Json::Value& modlist) { diff --git a/src/guiEngine.cpp b/src/guiEngine.cpp index 0a1d72206..03b2766d8 100644 --- a/src/guiEngine.cpp +++ b/src/guiEngine.cpp @@ -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 - 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; } - HTTPFetchRequest fetchrequest; - HTTPFetchResult fetchresult; - fetchrequest.url = url; - fetchrequest.caller = HTTPFETCH_SYNC; - fetchrequest.timeout = g_settings->getS32("curl_file_download_timeout"); - httpfetch_sync(fetchrequest, fetchresult); + HTTPFetchRequest fetch_request; + HTTPFetchResult fetch_result; + fetch_request.url = url; + fetch_request.caller = HTTPFETCH_SYNC; + fetch_request.timeout = g_settings->getS32("curl_file_download_timeout"); + httpfetch_sync(fetch_request, fetch_result); - if (fetchresult.succeeded) { - targetfile << fetchresult.data; - } else { + if (!fetch_result.succeeded) { return false; } + target_file << fetch_result.data; return true; #else diff --git a/src/httpfetch.cpp b/src/httpfetch.cpp index c651055bc..f61dbbf71 100644 --- a/src/httpfetch.cpp +++ b/src/httpfetch.cpp @@ -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) { 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); @@ -108,13 +108,13 @@ bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetchresult) return false; // Check that result queue is nonempty - std::list<HTTPFetchResult> &callerresults = it->second; - if (callerresults.empty()) + std::list<HTTPFetchResult> &caller_results = it->second; + if (caller_results.empty()) return false; // Pop first result - fetchresult = callerresults.front(); - callerresults.pop_front(); + fetch_result = caller_results.front(); + caller_results.pop_front(); 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; CURL *curl; CURLM *multi; @@ -184,201 +195,200 @@ struct HTTPFetchOngoing HTTPFetchResult result; std::ostringstream oss; char *post_fields; - struct curl_slist *httpheader; + struct curl_slist *http_header; curl_httppost *post; +}; - HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_): - pool(pool_), - curl(NULL), - multi(NULL), - request(request_), - result(request_), - oss(std::ios::binary), - httpheader(NULL), - post(NULL) - { - curl = pool->alloc(); - if (curl != NULL) { - // Set static cURL options - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1); -#if LIBCURL_VERSION_NUM >= 0x071304 - // Restrict protocols so that curl vulnerabilities in - // other protocols don't affect us. - // These settings were introduced in curl 7.19.4. - long protocols = - CURLPROTO_HTTP | - CURLPROTO_HTTPS | - CURLPROTO_FTP | - CURLPROTO_FTPS; - curl_easy_setopt(curl, CURLOPT_PROTOCOLS, protocols); - curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, protocols); -#endif +HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_): + pool(pool_), + curl(NULL), + multi(NULL), + request(request_), + result(request_), + oss(std::ios::binary), + http_header(NULL), + post(NULL) +{ + curl = pool->alloc(); + if (curl == NULL) { + return; + } - // Set cURL options based on HTTPFetchRequest - curl_easy_setopt(curl, CURLOPT_URL, - request.url.c_str()); - curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, - request.timeout); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, - request.connect_timeout); - - if (request.useragent != "") - curl_easy_setopt(curl, CURLOPT_USERAGENT, request.useragent.c_str()); - - // Set up a write callback that writes to the - // ostringstream ongoing->oss, unless the data - // is to be discarded - if (request.caller == HTTPFETCH_DISCARD) { - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, - httpfetch_discardfunction); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); - } - else { - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, - httpfetch_writefunction); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss); - } + // Set static cURL options + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1); - // Set POST (or GET) data - if (request.post_fields.empty()) { - curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); - } else if (request.multipart) { - curl_httppost *last = NULL; - for (std::map<std::string, std::string>::iterator it = - request.post_fields.begin(); - it != request.post_fields.end(); - ++it) { - curl_formadd(&post, &last, - CURLFORM_NAMELENGTH, it->first.size(), - CURLFORM_PTRNAME, it->first.c_str(), - CURLFORM_CONTENTSLENGTH, it->second.size(), - CURLFORM_PTRCONTENTS, it->second.c_str(), - CURLFORM_END); - } - curl_easy_setopt(curl, CURLOPT_HTTPPOST, post); - // request.post_fields must now *never* be - // modified until CURLOPT_HTTPPOST is cleared - } else { - curl_easy_setopt(curl, CURLOPT_POST, 1); - if (request.post_data.empty()) { - std::string str; - for (std::map<std::string, std::string>::iterator it = - request.post_fields.begin(); - it != request.post_fields.end(); - ++it) { - if (str != "") - str += "&"; - str += urlencode(it->first); - str += "="; - str += urlencode(it->second); - } - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, - str.size()); - curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, - str.c_str()); - } else { - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, - request.post_data.size()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, - request.post_data.c_str()); - // request.post_data must now *never* be - // modified until CURLOPT_POSTFIELDS is cleared - } - } - // Set additional HTTP headers - for (size_t i = 0; i < request.extra_headers.size(); ++i) { - httpheader = curl_slist_append( - httpheader, - request.extra_headers[i].c_str()); - } - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, httpheader); +#if LIBCURL_VERSION_NUM >= 0x071304 + // Restrict protocols so that curl vulnerabilities in + // other protocols don't affect us. + // These settings were introduced in curl 7.19.4. + long protocols = + CURLPROTO_HTTP | + CURLPROTO_HTTPS | + CURLPROTO_FTP | + CURLPROTO_FTPS; + curl_easy_setopt(curl, CURLOPT_PROTOCOLS, protocols); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, protocols); +#endif - if (!g_settings->getBool("curl_verify_cert")) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); - } - } + // Set cURL options based on HTTPFetchRequest + curl_easy_setopt(curl, CURLOPT_URL, + request.url.c_str()); + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, + request.timeout); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, + request.connect_timeout); + + if (request.useragent != "") + curl_easy_setopt(curl, CURLOPT_USERAGENT, request.useragent.c_str()); + + // Set up a write callback that writes to the + // ostringstream ongoing->oss, unless the data + // is to be discarded + if (request.caller == HTTPFETCH_DISCARD) { + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + httpfetch_discardfunction); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); + } else { + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + httpfetch_writefunction); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss); } - CURLcode start(CURLM *multi_) - { - if (curl == NULL) - return CURLE_FAILED_INIT; - - if (multi_) { - // Multi interface (async) - CURLMcode mres = curl_multi_add_handle(multi_, curl); - if (mres != CURLM_OK) { - errorstream<<"curl_multi_add_handle" - <<" returned error code "<<mres - <<std::endl; - return CURLE_FAILED_INIT; - } - multi = multi_; // store for curl_multi_remove_handle - return CURLE_OK; + // Set POST (or GET) data + if (request.post_fields.empty()) { + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); + } else if (request.multipart) { + curl_httppost *last = NULL; + for (std::map<std::string, std::string>::iterator it = + request.post_fields.begin(); + it != request.post_fields.end(); ++it) { + curl_formadd(&post, &last, + CURLFORM_NAMELENGTH, it->first.size(), + CURLFORM_PTRNAME, it->first.c_str(), + CURLFORM_CONTENTSLENGTH, it->second.size(), + CURLFORM_PTRCONTENTS, it->second.c_str(), + CURLFORM_END); } - else { - // Easy interface (sync) - return curl_easy_perform(curl); + curl_easy_setopt(curl, CURLOPT_HTTPPOST, post); + // request.post_fields must now *never* be + // modified until CURLOPT_HTTPPOST is cleared + } else if (request.post_data.empty()) { + curl_easy_setopt(curl, CURLOPT_POST, 1); + std::string str; + for (std::map<std::string, std::string>::iterator it = + request.post_fields.begin(); + it != request.post_fields.end(); + ++it) { + if (str != "") + str += "&"; + str += urlencode(it->first); + str += "="; + str += urlencode(it->second); } + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, + str.size()); + curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, + str.c_str()); + } else { + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, + request.post_data.size()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, + request.post_data.c_str()); + // request.post_data must now *never* be + // modified until CURLOPT_POSTFIELDS is cleared + } + // Set additional HTTP headers + for (std::vector<std::string>::iterator it = request.extra_headers.begin(); + it != request.extra_headers.end(); ++it) { + http_header = curl_slist_append(http_header, it->c_str()); } + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header); - void complete(CURLcode res) - { - result.succeeded = (res == CURLE_OK); - result.timeout = (res == CURLE_OPERATION_TIMEDOUT); - result.data = oss.str(); + if (!g_settings->getBool("curl_verify_cert")) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + } +} + +CURLcode HTTPFetchOngoing::start(CURLM *multi_) +{ + if (!curl) + return CURLE_FAILED_INIT; + + if (!multi_) { + // Easy interface (sync) + return curl_easy_perform(curl); + } - // Get HTTP/FTP response code + // Multi interface (async) + CURLMcode mres = curl_multi_add_handle(multi_, curl); + if (mres != CURLM_OK) { + errorstream << "curl_multi_add_handle" + << " returned error code " << mres + << std::endl; + return CURLE_FAILED_INIT; + } + multi = multi_; // store for curl_multi_remove_handle + return CURLE_OK; +} + +const HTTPFetchResult * HTTPFetchOngoing::complete(CURLcode res) +{ + result.succeeded = (res == CURLE_OK); + result.timeout = (res == CURLE_OPERATION_TIMEDOUT); + result.data = oss.str(); + + // Get HTTP/FTP response code + result.response_code = 0; + if (curl && (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, + &result.response_code) != CURLE_OK)) { + // We failed to get a return code, make sure it is still 0 result.response_code = 0; - if (curl != NULL) { - if (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, - &result.response_code) != CURLE_OK) { - //we failed to get a return code make sure it is still 0 - result.response_code = 0; - } - } + } - if (res != CURLE_OK) { - errorstream<<request.url<<" not found (" - <<curl_easy_strerror(res)<<")" - <<" (response code "<<result.response_code<<")" - <<std::endl; - } + if (res != CURLE_OK) { + errorstream << request.url << " not found (" + << curl_easy_strerror(res) << ")" + << " (response code " << result.response_code << ")" + << std::endl; } - ~HTTPFetchOngoing() - { - if (multi != NULL) { - CURLMcode mres = curl_multi_remove_handle(multi, curl); - if (mres != CURLM_OK) { - errorstream<<"curl_multi_remove_handle" - <<" returned error code "<<mres - <<std::endl; - } - } + return &result; +} - // Set safe options for the reusable cURL handle - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, - httpfetch_discardfunction); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL); - if (httpheader != NULL) { - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); - curl_slist_free_all(httpheader); - } - if (post != NULL) { - curl_easy_setopt(curl, CURLOPT_HTTPPOST, NULL); - curl_formfree(post); +HTTPFetchOngoing::~HTTPFetchOngoing() +{ + if (multi) { + CURLMcode mres = curl_multi_remove_handle(multi, curl); + if (mres != CURLM_OK) { + errorstream << "curl_multi_remove_handle" + << " returned error code " << mres + << std::endl; } + } - // Store the cURL handle for reuse - pool->free(curl); + // Set safe options for the reusable cURL handle + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + httpfetch_discardfunction); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL); + if (http_header) { + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); + curl_slist_free_all(http_header); } -}; + if (post) { + curl_easy_setopt(curl, CURLOPT_HTTPPOST, NULL); + curl_formfree(post); + } + + // Store the cURL handle for reuse + pool->free(curl); +} + class CurlFetchThread : public JThread { @@ -391,7 +401,7 @@ protected: struct Request { RequestType type; - HTTPFetchRequest fetchrequest; + HTTPFetchRequest fetch_request; Event *event; }; @@ -412,11 +422,11 @@ public: m_parallel_limit = 1; } - void requestFetch(const HTTPFetchRequest &fetchrequest) + void requestFetch(const HTTPFetchRequest &fetch_request) { Request req; req.type = RT_FETCH; - req.fetchrequest = fetchrequest; + req.fetch_request = fetch_request; req.event = NULL; m_requests.push_back(req); } @@ -425,7 +435,7 @@ public: { Request req; req.type = RT_CLEAR; - req.fetchrequest.caller = caller; + req.fetch_request.caller = caller; req.event = event; m_requests.push_back(req); } @@ -446,24 +456,24 @@ protected: if (req.type == RT_FETCH) { // New fetch, queue until there are less // 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 } 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 for (std::vector<HTTPFetchOngoing*>::iterator it = m_all_ongoing.begin(); it != m_all_ongoing.end();) { - if ((*it)->request.caller == caller) { + if ((*it)->getRequest().caller == caller) { delete (*it); it = m_all_ongoing.erase(it); - } - else + } else { ++it; + } } // Also abort all queued fetches for the caller @@ -503,8 +513,7 @@ protected: m_all_ongoing.push_back(ongoing); } else { - ongoing->complete(res); - httpfetch_deliver_result(ongoing->result); + httpfetch_deliver_result(*ongoing->complete(res)); delete ongoing; } } @@ -517,7 +526,7 @@ protected: size_t i = 0; bool found = false; 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; break; } @@ -525,8 +534,7 @@ protected: if (msg->msg == CURLMSG_DONE && found) { // m_all_ongoing[i] succeeded or failed. HTTPFetchOngoing *ongoing = m_all_ongoing[i]; - ongoing->complete(msg->data.result); - httpfetch_deliver_result(ongoing->result); + httpfetch_deliver_result(*ongoing->complete(msg->data.result)); delete ongoing; m_all_ongoing.erase(m_all_ongoing.begin() + i); } @@ -719,9 +727,9 @@ void httpfetch_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()) g_httpfetch_thread->Start(); } @@ -738,18 +746,17 @@ static void httpfetch_request_clear(unsigned long caller) } } -void httpfetch_sync(const HTTPFetchRequest &fetchrequest, - HTTPFetchResult &fetchresult) +void httpfetch_sync(const HTTPFetchRequest &fetch_request, + HTTPFetchResult &fetch_result) { // Create ongoing fetch data and make a cURL handle // Set cURL options based on HTTPFetchRequest CurlHandlePool pool; - HTTPFetchOngoing ongoing(fetchrequest, &pool); + HTTPFetchOngoing ongoing(fetch_request, &pool); // Do the fetch (curl_easy_perform) CURLcode res = ongoing.start(NULL); - // Update fetchresult - ongoing.complete(res); - fetchresult = ongoing.result; + // Update fetch result + fetch_result = *ongoing.complete(res); } #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 - <<" because USE_CURL=0"<<std::endl; + errorstream << "httpfetch_async: unable to fetch " << fetch_request.url + << " because USE_CURL=0" << std::endl; - HTTPFetchResult fetchresult(fetchrequest); // sets succeeded = false etc. - httpfetch_deliver_result(fetchresult); + HTTPFetchResult fetch_result(fetch_request); // sets succeeded = false etc. + httpfetch_deliver_result(fetch_result); } static void httpfetch_request_clear(unsigned long caller) { } -void httpfetch_sync(const HTTPFetchRequest &fetchrequest, - HTTPFetchResult &fetchresult) +void httpfetch_sync(const HTTPFetchRequest &fetch_request, + HTTPFetchResult &fetch_result) { - errorstream<<"httpfetch_sync: unable to fetch "<<fetchrequest.url - <<" because USE_CURL=0"<<std::endl; + errorstream << "httpfetch_sync: unable to fetch " << fetch_request.url + << " 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 diff --git a/src/httpfetch.h b/src/httpfetch.h index aba7482c2..50a4c93d8 100644 --- a/src/httpfetch.h +++ b/src/httpfetch.h @@ -88,14 +88,14 @@ struct HTTPFetchResult request_id = 0; } - HTTPFetchResult(const HTTPFetchRequest &fetchrequest) + HTTPFetchResult(const HTTPFetchRequest &fetch_request) { succeeded = false; timeout = false; response_code = 0; data = ""; - caller = fetchrequest.caller; - request_id = fetchrequest.request_id; + caller = fetch_request.caller; + request_id = fetch_request.request_id; } }; @@ -107,11 +107,11 @@ void httpfetch_init(int parallel_limit); void httpfetch_cleanup(); // 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 -// result queue, sets fetchresult and returns true. Otherwise returns false. -bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetchresult); +// result queue, sets the fetch result and returns true. Otherwise returns false. +bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result); // Allocates a caller ID for httpfetch_async // 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 // only be used from background threads. -void httpfetch_sync(const HTTPFetchRequest &fetchrequest, - HTTPFetchResult &fetchresult); +void httpfetch_sync(const HTTPFetchRequest &fetch_request, + HTTPFetchResult &fetch_result); #endif // !HTTPFETCH_HEADER diff --git a/src/mods.cpp b/src/mods.cpp index b4e075b1e..7d6b4f5f7 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -339,19 +339,14 @@ Json::Value getModstoreUrl(std::string url) bool special_http_header = true; - try{ + try { special_http_header = g_settings->getBool("modstore_disable_special_http_header"); - } - catch(SettingNotFoundException &e) { - } + } catch (SettingNotFoundException) {} if (special_http_header) { 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 diff --git a/src/serverlist.cpp b/src/serverlist.cpp index cc41216ff..245a8b800 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -70,17 +70,24 @@ std::vector<ServerListSpec> getOnline() Json::Value root = fetchJsonValue( (g_settings->get("serverlist_url") + "/list").c_str(), NULL); - std::vector<ServerListSpec> serverlist; + std::vector<ServerListSpec> server_list; + + if (!root.isObject()) { + return server_list; + } - if (root.isArray()) { - for (unsigned int i = 0; i < root.size(); i++) { - if (root[i].isObject()) { - serverlist.push_back(root[i]); - } + root = root["list"]; + if (!root.isArray()) { + return server_list; + } + + for (unsigned int i = 0; i < root.size(); i++) { + if (root[i].isObject()) { + server_list.push_back(root[i]); } } - return serverlist; + return server_list; } @@ -236,11 +243,11 @@ void sendAnnounce(const std::string &action, } Json::FastWriter writer; - HTTPFetchRequest fetchrequest; - fetchrequest.url = g_settings->get("serverlist_url") + std::string("/announce"); - fetchrequest.post_fields["json"] = writer.write(server); - fetchrequest.multipart = true; - httpfetch_async(fetchrequest); + HTTPFetchRequest fetch_request; + fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce"); + fetch_request.post_fields["json"] = writer.write(server); + fetch_request.multipart = true; + httpfetch_async(fetch_request); } #endif |