51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "socket.h" // for select()
+#include "porting.h" // for sleep_ms(), get_sysinfo()
#include "httpfetch.h"
#include <iostream>
#include <sstream>
#include "log.h"
#include "util/container.h"
#include "util/thread.h"
-#include "socket.h" // for select()
+#include "version.h"
+#include "main.h"
+#include "settings.h"
JMutex g_httpfetch_mutex;
std::map<unsigned long, std::list<HTTPFetchResult> > g_httpfetch_results;
+HTTPFetchRequest::HTTPFetchRequest()
+{
+ url = "";
+ caller = HTTPFETCH_DISCARD;
+ request_id = 0;
+ timeout = g_settings->getS32("curl_timeout");
+ connect_timeout = timeout;
+ multipart = false;
+
+ useragent = std::string("Minetest/") + minetest_version_hash + " (" + porting::get_sysinfo() + ")";
+}
+
+
static void httpfetch_deliver_result(const HTTPFetchResult &fetchresult)
{
unsigned long caller = fetchresult.caller;
std::ostringstream oss;
char *post_fields;
struct curl_slist *httpheader;
+ curl_httppost *post;
HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
pool(pool_),
request(request_),
result(request_),
oss(std::ios::binary),
- httpheader(NULL)
+ httpheader(NULL),
+ post(NULL)
{
curl = pool->alloc();
if (curl != NULL) {
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
httpfetch_writefunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
}
+
// Set POST (or GET) data
if (request.post_fields.empty()) {
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
- }
- else {
- curl_easy_setopt(curl, CURLOPT_POST, 1);
- curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
- request.post_fields.size());
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
- request.post_fields.c_str());
+ } 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_POSTFIELDS is cleared
+ // 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) {
request.extra_headers[i].c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, httpheader);
+
+ if (!g_settings->getBool("curl_verify_cert")) {
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
+ }
}
}
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) {
- infostream<<request.url<<" not found ("
+ errorstream<<request.url<<" not found ("
<<curl_easy_strerror(res)<<")"
<<" (response code "<<result.response_code<<")"
<<std::endl;
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);
+ }
// Store the cURL handle for reuse
pool->free(curl);
}
};
-class CurlFetchThread : public SimpleThread
+class CurlFetchThread : public JThread
{
protected:
enum RequestType {
select_timeout = timeout;
if (select_timeout > 0) {
- select_tv.tv_sec = select_timeout / 1000;
- select_tv.tv_usec = (select_timeout % 1000) * 1000;
- int retval = select(max_fd + 1, &read_fd_set,
- &write_fd_set, &exc_fd_set,
- &select_tv);
- if (retval == -1) {
- #ifdef _WIN32
- errorstream<<"select returned error code "
- <<WSAGetLastError()<<std::endl;
- #else
- errorstream<<"select returned error code "
- <<errno<<std::endl;
- #endif
+ // in Winsock it is forbidden to pass three empty
+ // fd_sets to select(), so in that case use sleep_ms
+ if (max_fd != -1) {
+ select_tv.tv_sec = select_timeout / 1000;
+ select_tv.tv_usec = (select_timeout % 1000) * 1000;
+ int retval = select(max_fd + 1, &read_fd_set,
+ &write_fd_set, &exc_fd_set,
+ &select_tv);
+ if (retval == -1) {
+ #ifdef _WIN32
+ errorstream<<"select returned error code "
+ <<WSAGetLastError()<<std::endl;
+ #else
+ errorstream<<"select returned error code "
+ <<errno<<std::endl;
+ #endif
+ }
+ }
+ else {
+ sleep_ms(select_timeout);
}
}
}
log_register_thread("CurlFetchThread");
DSTACK(__FUNCTION_NAME);
+ porting::setThreadName("CurlFetchThread");
+
CurlHandlePool pool;
m_multi = curl_multi_init();
assert(m_all_ongoing.empty());
- while (getRun()) {
+ while (!StopRequested()) {
BEGIN_DEBUG_EXCEPTION_HANDLER
/*
*/
while (!m_requests.empty()) {
- Request req = m_requests.pop_front();
+ Request req = m_requests.pop_frontNoEx();
processRequest(req);
}
processQueued(&pool);
{
verbosestream<<"httpfetch_cleanup: cleaning up"<<std::endl;
- g_httpfetch_thread->setRun(false);
+ g_httpfetch_thread->Stop();
g_httpfetch_thread->requestWakeUp();
- g_httpfetch_thread->stop();
+ g_httpfetch_thread->Wait();
delete g_httpfetch_thread;
curl_global_cleanup();