forked from Mirrorlandia_minetest/minetest
Add support for multipart/form-data to HTTPFetch for server announcing
This commit is contained in:
parent
1c01ed5f13
commit
b2dfde8c8c
@ -266,7 +266,7 @@ void ClientMediaDownloader::initialStep(Client *client)
|
|||||||
fetchrequest.request_id = m_httpfetch_next_id; // == i
|
fetchrequest.request_id = m_httpfetch_next_id; // == i
|
||||||
fetchrequest.timeout = m_httpfetch_timeout;
|
fetchrequest.timeout = m_httpfetch_timeout;
|
||||||
fetchrequest.connect_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(
|
fetchrequest.extra_headers.push_back(
|
||||||
"Content-Type: application/octet-stream");
|
"Content-Type: application/octet-stream");
|
||||||
httpfetch_async(fetchrequest);
|
httpfetch_async(fetchrequest);
|
||||||
|
@ -46,6 +46,7 @@ HTTPFetchRequest::HTTPFetchRequest()
|
|||||||
request_id = 0;
|
request_id = 0;
|
||||||
timeout = g_settings->getS32("curl_timeout");
|
timeout = g_settings->getS32("curl_timeout");
|
||||||
connect_timeout = timeout;
|
connect_timeout = timeout;
|
||||||
|
multipart = false;
|
||||||
|
|
||||||
useragent = std::string("Minetest/") + minetest_version_hash + " (" + porting::get_sysinfo() + ")";
|
useragent = std::string("Minetest/") + minetest_version_hash + " (" + porting::get_sysinfo() + ")";
|
||||||
}
|
}
|
||||||
@ -184,6 +185,7 @@ struct HTTPFetchOngoing
|
|||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
char *post_fields;
|
char *post_fields;
|
||||||
struct curl_slist *httpheader;
|
struct curl_slist *httpheader;
|
||||||
|
curl_httppost *post;
|
||||||
|
|
||||||
HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
|
HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
|
||||||
pool(pool_),
|
pool(pool_),
|
||||||
@ -192,7 +194,8 @@ struct HTTPFetchOngoing
|
|||||||
request(request_),
|
request(request_),
|
||||||
result(request_),
|
result(request_),
|
||||||
oss(std::ios::binary),
|
oss(std::ios::binary),
|
||||||
httpheader(NULL)
|
httpheader(NULL),
|
||||||
|
post(NULL)
|
||||||
{
|
{
|
||||||
curl = pool->alloc();
|
curl = pool->alloc();
|
||||||
if (curl != NULL) {
|
if (curl != NULL) {
|
||||||
@ -239,19 +242,53 @@ struct HTTPFetchOngoing
|
|||||||
httpfetch_writefunction);
|
httpfetch_writefunction);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set POST (or GET) data
|
// Set POST (or GET) data
|
||||||
if (request.post_fields.empty()) {
|
if (request.post_fields.empty()) {
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
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 {
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
|
||||||
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());
|
|
||||||
// request.post_fields must now *never* be
|
// 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
|
// modified until CURLOPT_POSTFIELDS is cleared
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Set additional HTTP headers
|
// Set additional HTTP headers
|
||||||
for (size_t i = 0; i < request.extra_headers.size(); ++i) {
|
for (size_t i = 0; i < request.extra_headers.size(); ++i) {
|
||||||
httpheader = curl_slist_append(
|
httpheader = curl_slist_append(
|
||||||
@ -333,6 +370,10 @@ struct HTTPFetchOngoing
|
|||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
|
||||||
curl_slist_free_all(httpheader);
|
curl_slist_free_all(httpheader);
|
||||||
}
|
}
|
||||||
|
if (post != NULL) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, NULL);
|
||||||
|
curl_formfree(post);
|
||||||
|
}
|
||||||
|
|
||||||
// Store the cURL handle for reuse
|
// Store the cURL handle for reuse
|
||||||
pool->free(curl);
|
pool->free(curl);
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
// Can be used in place of "caller" in asynchronous transfers to discard result
|
// 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
|
// Timeout for the connection phase, in milliseconds
|
||||||
long connect_timeout;
|
long connect_timeout;
|
||||||
|
|
||||||
// POST data (should be application/x-www-form-urlencoded
|
// Indicates if this is multipart/form-data or
|
||||||
// unless a Content-Type header is specified in extra_headers)
|
// 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.
|
// 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"
|
// If not empty, should contain entries such as "Accept: text/html"
|
||||||
std::vector<std::string> extra_headers;
|
std::vector<std::string> extra_headers;
|
||||||
|
@ -230,11 +230,8 @@ void sendAnnounce(std::string action, const std::vector<std::string> & clients_n
|
|||||||
Json::FastWriter writer;
|
Json::FastWriter writer;
|
||||||
HTTPFetchRequest fetchrequest;
|
HTTPFetchRequest fetchrequest;
|
||||||
fetchrequest.url = g_settings->get("serverlist_url") + std::string("/announce");
|
fetchrequest.url = g_settings->get("serverlist_url") + std::string("/announce");
|
||||||
std::string query = std::string("json=") + urlencode(writer.write(server));
|
fetchrequest.post_fields["json"] = writer.write(server);
|
||||||
if (query.size() < 1000)
|
fetchrequest.multipart = true;
|
||||||
fetchrequest.url += "?" + query;
|
|
||||||
else
|
|
||||||
fetchrequest.post_fields = query;
|
|
||||||
httpfetch_async(fetchrequest);
|
httpfetch_async(fetchrequest);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user