Added configurable selectionbox width. Min width = 1, Max = 5
[oweals/minetest.git] / src / httpfetch.cpp
index 4342a8b2a9509d680502434ad8d5d932053af9a7..c651055bca5364c969352f10ea139836c7f03c11 100644 (file)
@@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 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>
@@ -30,11 +32,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #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;
@@ -168,6 +185,7 @@ struct HTTPFetchOngoing
        std::ostringstream oss;
        char *post_fields;
        struct curl_slist *httpheader;
+       curl_httppost *post;
 
        HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
                pool(pool_),
@@ -176,7 +194,8 @@ struct HTTPFetchOngoing
                request(request_),
                result(request_),
                oss(std::ios::binary),
-               httpheader(NULL)
+               httpheader(NULL),
+               post(NULL)
        {
                curl = pool->alloc();
                if (curl != NULL) {
@@ -206,6 +225,10 @@ struct HTTPFetchOngoing
                                        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
@@ -219,18 +242,52 @@ struct HTTPFetchOngoing
                                                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) {
@@ -239,6 +296,10 @@ struct HTTPFetchOngoing
                                        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);
+                       }
                }
        }
 
@@ -276,12 +337,13 @@ struct HTTPFetchOngoing
                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;
@@ -308,13 +370,17 @@ struct HTTPFetchOngoing
                        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 {
@@ -515,19 +581,26 @@ protected:
                        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);
                        }
                }
        }
@@ -538,6 +611,8 @@ protected:
                log_register_thread("CurlFetchThread");
                DSTACK(__FUNCTION_NAME);
 
+               porting::setThreadName("CurlFetchThread");
+
                CurlHandlePool pool;
 
                m_multi = curl_multi_init();
@@ -548,7 +623,7 @@ protected:
 
                assert(m_all_ongoing.empty());
 
-               while (getRun()) {
+               while (!StopRequested()) {
                        BEGIN_DEBUG_EXCEPTION_HANDLER
 
                        /*
@@ -556,7 +631,7 @@ protected:
                        */
 
                        while (!m_requests.empty()) {
-                               Request req = m_requests.pop_front();
+                               Request req = m_requests.pop_frontNoEx();
                                processRequest(req);
                        }
                        processQueued(&pool);
@@ -636,9 +711,9 @@ void httpfetch_cleanup()
 {
        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();