summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clientmedia.cpp2
-rw-r--r--src/httpfetch.cpp59
-rw-r--r--src/httpfetch.h13
-rw-r--r--src/serverlist.cpp7
4 files changed, 63 insertions, 18 deletions
diff --git a/src/clientmedia.cpp b/src/clientmedia.cpp
index b3e7e8e06..c1043c769 100644
--- a/src/clientmedia.cpp
+++ b/src/clientmedia.cpp
@@ -266,7 +266,7 @@ void ClientMediaDownloader::initialStep(Client *client)
fetchrequest.request_id = m_httpfetch_next_id; // == i
fetchrequest.timeout = m_httpfetch_timeout;
fetchrequest.connect_timeout = m_httpfetch_timeout;
- fetchrequest.post_fields = required_hash_set;
+ fetchrequest.post_data = required_hash_set;
fetchrequest.extra_headers.push_back(
"Content-Type: application/octet-stream");
httpfetch_async(fetchrequest);
diff --git a/src/httpfetch.cpp b/src/httpfetch.cpp
index 69c366ee0..c651055bc 100644
--- a/src/httpfetch.cpp
+++ b/src/httpfetch.cpp
@@ -46,6 +46,7 @@ HTTPFetchRequest::HTTPFetchRequest()
request_id = 0;
timeout = g_settings->getS32("curl_timeout");
connect_timeout = timeout;
+ multipart = false;
useragent = std::string("Minetest/") + minetest_version_hash + " (" + porting::get_sysinfo() + ")";
}
@@ -184,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_),
@@ -192,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) {
@@ -239,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) {
@@ -333,6 +370,10 @@ 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);
diff --git a/src/httpfetch.h b/src/httpfetch.h
index e02e92b4a..aba7482c2 100644
--- a/src/httpfetch.h
+++ b/src/httpfetch.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <vector>
+#include <map>
#include "config.h"
// Can be used in place of "caller" in asynchronous transfers to discard result
@@ -47,10 +48,16 @@ struct HTTPFetchRequest
// Timeout for the connection phase, in milliseconds
long connect_timeout;
- // POST data (should be application/x-www-form-urlencoded
- // unless a Content-Type header is specified in extra_headers)
+ // Indicates if this is multipart/form-data or
+ // application/x-www-form-urlencoded. POST-only.
+ bool multipart;
+
+ // POST fields. Fields are escaped properly.
// If this is empty a GET request is done instead.
- std::string post_fields;
+ std::map<std::string, std::string> post_fields;
+
+ // Raw POST data, overrides post_fields.
+ std::string post_data;
// If not empty, should contain entries such as "Accept: text/html"
std::vector<std::string> extra_headers;
diff --git a/src/serverlist.cpp b/src/serverlist.cpp
index 8a85b33b3..315e23688 100644
--- a/src/serverlist.cpp
+++ b/src/serverlist.cpp
@@ -230,11 +230,8 @@ void sendAnnounce(std::string action, const std::vector<std::string> & clients_n
Json::FastWriter writer;
HTTPFetchRequest fetchrequest;
fetchrequest.url = g_settings->get("serverlist_url") + std::string("/announce");
- std::string query = std::string("json=") + urlencode(writer.write(server));
- if (query.size() < 1000)
- fetchrequest.url += "?" + query;
- else
- fetchrequest.post_fields = query;
+ fetchrequest.post_fields["json"] = writer.write(server);
+ fetchrequest.multipart = true;
httpfetch_async(fetchrequest);
}
#endif