51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "socket.h" // for select()
-#include "porting.h" // for sleep_ms(), get_sysinfo(), secure_rand_fill_buf()
#include "httpfetch.h"
+#include "porting.h" // for sleep_ms(), get_sysinfo(), secure_rand_fill_buf()
#include <iostream>
#include <sstream>
#include <list>
-#include <map>
-#include <errno.h>
+#include <unordered_map>
+#include <cerrno>
#include <mutex>
+#include "network/socket.h" // for select()
#include "threading/event.h"
#include "config.h"
#include "exceptions.h"
#include "settings.h"
#include "noise.h"
-std::mutex g_httpfetch_mutex;
-std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
-PcgRandom g_callerid_randomness;
+static std::mutex g_httpfetch_mutex;
+static std::unordered_map<unsigned long, std::queue<HTTPFetchResult>>
+ g_httpfetch_results;
+static PcgRandom g_callerid_randomness;
HTTPFetchRequest::HTTPFetchRequest() :
timeout(g_settings->getS32("curl_timeout")),
- connect_timeout(timeout),
+ connect_timeout(10 * 1000),
useragent(std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")")
{
}
unsigned long caller = fetch_result.caller;
if (caller != HTTPFETCH_DISCARD) {
MutexAutoLock lock(g_httpfetch_mutex);
- g_httpfetch_results[caller].push(fetch_result);
+ g_httpfetch_results[caller].emplace(fetch_result);
}
}
// Check each caller ID except HTTPFETCH_DISCARD
const unsigned long discard = HTTPFETCH_DISCARD;
for (unsigned long caller = discard + 1; caller != discard; ++caller) {
- std::map<unsigned long, std::queue<HTTPFetchResult> >::iterator
- it = g_httpfetch_results.find(caller);
+ auto it = g_httpfetch_results.find(caller);
if (it == g_httpfetch_results.end()) {
verbosestream << "httpfetch_caller_alloc: allocating "
<< caller << std::endl;
MutexAutoLock lock(g_httpfetch_mutex);
// Check that caller exists
- std::map<unsigned long, std::queue<HTTPFetchResult> >::iterator
- it = g_httpfetch_results.find(caller);
+ auto it = g_httpfetch_results.find(caller);
if (it == g_httpfetch_results.end())
return false;
return false;
// Pop first result
- fetch_result = caller_results.front();
+ fetch_result = std::move(caller_results.front());
caller_results.pop();
return true;
}
std::list<CURL*> handles;
public:
- CurlHandlePool() {}
+ CurlHandlePool() = default;
+
~CurlHandlePool()
{
for (std::list<CURL*>::iterator it = handles.begin();
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);
+ curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3);
+ curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
std::string bind_address = g_settings->get("bind_address");
if (!bind_address.empty()) {
curl_easy_setopt(curl, CURLOPT_INTERFACE, bind_address.c_str());
}
+ if (!g_settings->getBool("enable_ipv6")) {
+ curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ }
+
#if LIBCURL_VERSION_NUM >= 0x071304
// Restrict protocols so that curl vulnerabilities in
// other protocols don't affect us.
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS,
request.connect_timeout);
- if (request.useragent != "")
+ if (!request.useragent.empty())
curl_easy_setopt(curl, CURLOPT_USERAGENT, request.useragent.c_str());
// Set up a write callback that writes to the
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
}
- // Set POST (or GET) data
- if (request.post_fields.empty() && request.post_data.empty()) {
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
- } else if (request.multipart) {
+ // Set data from fields or raw_data
+ if (request.multipart) {
curl_httppost *last = NULL;
- for (StringMap::iterator it = request.post_fields.begin();
- it != request.post_fields.end(); ++it) {
+ for (StringMap::iterator it = request.fields.begin();
+ it != request.fields.end(); ++it) {
curl_formadd(&post, &last,
CURLFORM_NAMELENGTH, it->first.size(),
CURLFORM_PTRNAME, it->first.c_str(),
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 (StringMap::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
+ switch (request.method) {
+ case HTTP_GET:
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
+ break;
+ case HTTP_POST:
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ break;
+ case HTTP_PUT:
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
+ break;
+ case HTTP_DELETE:
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
+ break;
+ }
+ if (request.method != HTTP_GET) {
+ if (!request.raw_data.empty()) {
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
+ request.raw_data.size());
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
+ request.raw_data.c_str());
+ } else if (!request.fields.empty()) {
+ std::string str;
+ for (auto &field : request.fields) {
+ if (!str.empty())
+ str += "&";
+ str += urlencode(field.first);
+ str += "=";
+ str += urlencode(field.second);
+ }
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
+ str.size());
+ curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS,
+ str.c_str());
+ }
+ }
}
// 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());
+ for (const std::string &extra_header : request.extra_headers) {
+ http_header = curl_slist_append(http_header, extra_header.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);
void *run()
{
- DSTACK(FUNCTION_NAME);
-
CurlHandlePool pool;
m_multi = curl_multi_init();
}
// Call curl_multi_remove_handle and cleanup easy handles
- for (size_t i = 0; i < m_all_ongoing.size(); ++i) {
- delete m_all_ongoing[i];
+ for (HTTPFetchOngoing *i : m_all_ongoing) {
+ delete i;
}
m_all_ongoing.clear();