Add PUT and DELETE request + specific method value to HTTP API (#9909)
parent
f34abaedd2
commit
715a123a33
|
@ -8071,11 +8071,13 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
|
||||||
timeout = 10,
|
timeout = 10,
|
||||||
-- Timeout for connection in seconds. Default is 3 seconds.
|
-- Timeout for connection in seconds. Default is 3 seconds.
|
||||||
|
|
||||||
post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
|
method = "GET", "POST", "PUT" or "DELETE"
|
||||||
-- Optional, if specified a POST request with post_data is performed.
|
-- The http method to use. Defaults to "GET".
|
||||||
|
|
||||||
|
data = "Raw request data string" OR {field1 = "data1", field2 = "data2"},
|
||||||
|
-- Data for the POST, PUT or DELETE request.
|
||||||
-- Accepts both a string and a table. If a table is specified, encodes
|
-- Accepts both a string and a table. If a table is specified, encodes
|
||||||
-- table as x-www-form-urlencoded key-value pairs.
|
-- table as x-www-form-urlencoded key-value pairs.
|
||||||
-- If post_data is not specified, a GET request is performed instead.
|
|
||||||
|
|
||||||
user_agent = "ExampleUserAgent",
|
user_agent = "ExampleUserAgent",
|
||||||
-- Optional, if specified replaces the default minetest user agent with
|
-- Optional, if specified replaces the default minetest user agent with
|
||||||
|
@ -8089,6 +8091,10 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
|
||||||
multipart = boolean
|
multipart = boolean
|
||||||
-- Optional, if true performs a multipart HTTP request.
|
-- Optional, if true performs a multipart HTTP request.
|
||||||
-- Default is false.
|
-- Default is false.
|
||||||
|
-- Post only, data must be array
|
||||||
|
|
||||||
|
post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
|
||||||
|
-- Deprecated, use `data` instead. Forces `method = "POST"`.
|
||||||
}
|
}
|
||||||
|
|
||||||
`HTTPRequestResult` definition
|
`HTTPRequestResult` definition
|
||||||
|
|
|
@ -260,7 +260,8 @@ void ClientMediaDownloader::initialStep(Client *client)
|
||||||
fetch_request.request_id = m_httpfetch_next_id; // == i
|
fetch_request.request_id = m_httpfetch_next_id; // == i
|
||||||
fetch_request.timeout = m_httpfetch_timeout;
|
fetch_request.timeout = m_httpfetch_timeout;
|
||||||
fetch_request.connect_timeout = m_httpfetch_timeout;
|
fetch_request.connect_timeout = m_httpfetch_timeout;
|
||||||
fetch_request.post_data = required_hash_set;
|
fetch_request.method = HTTP_POST;
|
||||||
|
fetch_request.raw_data = required_hash_set;
|
||||||
fetch_request.extra_headers.emplace_back(
|
fetch_request.extra_headers.emplace_back(
|
||||||
"Content-Type: application/octet-stream");
|
"Content-Type: application/octet-stream");
|
||||||
|
|
||||||
|
|
|
@ -294,13 +294,11 @@ HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_,
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set POST (or GET) data
|
// Set data from fields or raw_data
|
||||||
if (request.post_fields.empty() && request.post_data.empty()) {
|
if (request.multipart) {
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
|
||||||
} else if (request.multipart) {
|
|
||||||
curl_httppost *last = NULL;
|
curl_httppost *last = NULL;
|
||||||
for (StringMap::iterator it = request.post_fields.begin();
|
for (StringMap::iterator it = request.fields.begin();
|
||||||
it != request.post_fields.end(); ++it) {
|
it != request.fields.end(); ++it) {
|
||||||
curl_formadd(&post, &last,
|
curl_formadd(&post, &last,
|
||||||
CURLFORM_NAMELENGTH, it->first.size(),
|
CURLFORM_NAMELENGTH, it->first.size(),
|
||||||
CURLFORM_PTRNAME, it->first.c_str(),
|
CURLFORM_PTRNAME, it->first.c_str(),
|
||||||
|
@ -311,28 +309,42 @@ HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_,
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
|
||||||
// request.post_fields must now *never* be
|
// request.post_fields must now *never* be
|
||||||
// modified until CURLOPT_HTTPPOST is cleared
|
// modified until CURLOPT_HTTPPOST is cleared
|
||||||
} else if (request.post_data.empty()) {
|
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
|
||||||
std::string str;
|
|
||||||
for (auto &post_field : request.post_fields) {
|
|
||||||
if (!str.empty())
|
|
||||||
str += "&";
|
|
||||||
str += urlencode(post_field.first);
|
|
||||||
str += "=";
|
|
||||||
str += urlencode(post_field.second);
|
|
||||||
}
|
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
|
|
||||||
str.size());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS,
|
|
||||||
str.c_str());
|
|
||||||
} else {
|
} else {
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
switch (request.method) {
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
|
case HTTP_GET:
|
||||||
request.post_data.size());
|
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
|
break;
|
||||||
request.post_data.c_str());
|
case HTTP_POST:
|
||||||
// request.post_data must now *never* be
|
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||||
// modified until CURLOPT_POSTFIELDS is cleared
|
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
|
// Set additional HTTP headers
|
||||||
for (const std::string &extra_header : request.extra_headers) {
|
for (const std::string &extra_header : request.extra_headers) {
|
||||||
|
|
|
@ -28,6 +28,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#define HTTPFETCH_DISCARD 0
|
#define HTTPFETCH_DISCARD 0
|
||||||
#define HTTPFETCH_SYNC 1
|
#define HTTPFETCH_SYNC 1
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
enum HttpMethod : u8
|
||||||
|
{
|
||||||
|
HTTP_GET,
|
||||||
|
HTTP_POST,
|
||||||
|
HTTP_PUT,
|
||||||
|
HTTP_DELETE,
|
||||||
|
};
|
||||||
|
|
||||||
struct HTTPFetchRequest
|
struct HTTPFetchRequest
|
||||||
{
|
{
|
||||||
std::string url = "";
|
std::string url = "";
|
||||||
|
@ -50,12 +59,15 @@ struct HTTPFetchRequest
|
||||||
// application/x-www-form-urlencoded. POST-only.
|
// application/x-www-form-urlencoded. POST-only.
|
||||||
bool multipart = false;
|
bool multipart = false;
|
||||||
|
|
||||||
// POST fields. Fields are escaped properly.
|
// The Method to use default = GET
|
||||||
// If this is empty a GET request is done instead.
|
// Avaible methods GET, POST, PUT, DELETE
|
||||||
StringMap post_fields;
|
HttpMethod method = HTTP_GET;
|
||||||
|
|
||||||
// Raw POST data, overrides post_fields.
|
// Fields of the request
|
||||||
std::string post_data;
|
StringMap fields;
|
||||||
|
|
||||||
|
// Raw data of the request overrides fields
|
||||||
|
std::string raw_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;
|
||||||
|
|
|
@ -1034,7 +1034,7 @@ const static std::string accessDeniedStrings[SERVER_ACCESSDENIED_MAX] = {
|
||||||
"This server has experienced an internal error. You will now be disconnected."
|
"This server has experienced an internal error. You will now be disconnected."
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PlayerListModifer: u8
|
enum PlayerListModifer : u8
|
||||||
{
|
{
|
||||||
PLAYER_LIST_INIT,
|
PLAYER_LIST_INIT,
|
||||||
PLAYER_LIST_ADD,
|
PLAYER_LIST_ADD,
|
||||||
|
|
|
@ -49,17 +49,40 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
|
||||||
req.multipart = getboolfield_default(L, 1, "multipart", false);
|
req.multipart = getboolfield_default(L, 1, "multipart", false);
|
||||||
req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000;
|
req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000;
|
||||||
|
|
||||||
// post_data: if table, post form data, otherwise raw data
|
lua_getfield(L, 1, "method");
|
||||||
|
if (lua_isstring(L, -1)) {
|
||||||
|
std::string mth = getstringfield_default(L, 1, "method", "");
|
||||||
|
if (mth == "GET")
|
||||||
|
req.method = HTTP_GET;
|
||||||
|
else if (mth == "POST")
|
||||||
|
req.method = HTTP_POST;
|
||||||
|
else if (mth == "PUT")
|
||||||
|
req.method = HTTP_PUT;
|
||||||
|
else if (mth == "DELETE")
|
||||||
|
req.method = HTTP_DELETE;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
// post_data: if table, post form data, otherwise raw data DEPRECATED use data and method instead
|
||||||
lua_getfield(L, 1, "post_data");
|
lua_getfield(L, 1, "post_data");
|
||||||
|
if (lua_isnil(L, 2)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_getfield(L, 1, "data");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
req.method = HTTP_POST;
|
||||||
|
}
|
||||||
|
|
||||||
if (lua_istable(L, 2)) {
|
if (lua_istable(L, 2)) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
while (lua_next(L, 2) != 0) {
|
while (lua_next(L, 2) != 0) {
|
||||||
req.post_fields[readParam<std::string>(L, -2)] = readParam<std::string>(L, -1);
|
req.fields[readParam<std::string>(L, -2)] = readParam<std::string>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
} else if (lua_isstring(L, 2)) {
|
} else if (lua_isstring(L, 2)) {
|
||||||
req.post_data = readParam<std::string>(L, 2);
|
req.raw_data = readParam<std::string>(L, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
lua_getfield(L, 1, "extra_headers");
|
lua_getfield(L, 1, "extra_headers");
|
||||||
|
|
|
@ -32,10 +32,10 @@ private:
|
||||||
static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
|
static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
|
||||||
static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true);
|
static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true);
|
||||||
|
|
||||||
// http_fetch_sync({url=, timeout=, post_data=})
|
// http_fetch_sync({url=, timeout=, data=})
|
||||||
static int l_http_fetch_sync(lua_State *L);
|
static int l_http_fetch_sync(lua_State *L);
|
||||||
|
|
||||||
// http_fetch_async({url=, timeout=, post_data=})
|
// http_fetch_async({url=, timeout=, data=})
|
||||||
static int l_http_fetch_async(lua_State *L);
|
static int l_http_fetch_async(lua_State *L);
|
||||||
|
|
||||||
// http_fetch_async_get(handle)
|
// http_fetch_async_get(handle)
|
||||||
|
|
|
@ -261,11 +261,11 @@ void sendAnnounce(AnnounceAction action,
|
||||||
|
|
||||||
HTTPFetchRequest fetch_request;
|
HTTPFetchRequest fetch_request;
|
||||||
fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce");
|
fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce");
|
||||||
fetch_request.post_fields["json"] = fastWriteJson(server);
|
fetch_request.method = HTTP_POST;
|
||||||
|
fetch_request.fields["json"] = fastWriteJson(server);
|
||||||
fetch_request.multipart = true;
|
fetch_request.multipart = true;
|
||||||
httpfetch_async(fetch_request);
|
httpfetch_async(fetch_request);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace ServerList
|
} // namespace ServerList
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue