Skip to content

Commit 715a123

Browse files
authoredJul 29, 2020
Add PUT and DELETE request + specific method value to HTTP API (#9909)
1 parent f34abae commit 715a123

File tree

8 files changed

+98
-44
lines changed

8 files changed

+98
-44
lines changed
 

‎doc/lua_api.txt

+9-3
Original file line numberDiff line numberDiff line change
@@ -8071,11 +8071,13 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
80718071
timeout = 10,
80728072
-- Timeout for connection in seconds. Default is 3 seconds.
80738073

8074-
post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
8075-
-- Optional, if specified a POST request with post_data is performed.
8074+
method = "GET", "POST", "PUT" or "DELETE"
8075+
-- The http method to use. Defaults to "GET".
8076+
8077+
data = "Raw request data string" OR {field1 = "data1", field2 = "data2"},
8078+
-- Data for the POST, PUT or DELETE request.
80768079
-- Accepts both a string and a table. If a table is specified, encodes
80778080
-- table as x-www-form-urlencoded key-value pairs.
8078-
-- If post_data is not specified, a GET request is performed instead.
80798081

80808082
user_agent = "ExampleUserAgent",
80818083
-- Optional, if specified replaces the default minetest user agent with
@@ -8089,6 +8091,10 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
80898091
multipart = boolean
80908092
-- Optional, if true performs a multipart HTTP request.
80918093
-- Default is false.
8094+
-- Post only, data must be array
8095+
8096+
post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
8097+
-- Deprecated, use `data` instead. Forces `method = "POST"`.
80928098
}
80938099

80948100
`HTTPRequestResult` definition

‎src/client/clientmedia.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ void ClientMediaDownloader::initialStep(Client *client)
260260
fetch_request.request_id = m_httpfetch_next_id; // == i
261261
fetch_request.timeout = m_httpfetch_timeout;
262262
fetch_request.connect_timeout = m_httpfetch_timeout;
263-
fetch_request.post_data = required_hash_set;
263+
fetch_request.method = HTTP_POST;
264+
fetch_request.raw_data = required_hash_set;
264265
fetch_request.extra_headers.emplace_back(
265266
"Content-Type: application/octet-stream");
266267

‎src/httpfetch.cpp

+39-27
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,11 @@ HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_,
294294
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
295295
}
296296

297-
// Set POST (or GET) data
298-
if (request.post_fields.empty() && request.post_data.empty()) {
299-
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
300-
} else if (request.multipart) {
297+
// Set data from fields or raw_data
298+
if (request.multipart) {
301299
curl_httppost *last = NULL;
302-
for (StringMap::iterator it = request.post_fields.begin();
303-
it != request.post_fields.end(); ++it) {
300+
for (StringMap::iterator it = request.fields.begin();
301+
it != request.fields.end(); ++it) {
304302
curl_formadd(&post, &last,
305303
CURLFORM_NAMELENGTH, it->first.size(),
306304
CURLFORM_PTRNAME, it->first.c_str(),
@@ -311,28 +309,42 @@ HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_,
311309
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
312310
// request.post_fields must now *never* be
313311
// modified until CURLOPT_HTTPPOST is cleared
314-
} else if (request.post_data.empty()) {
315-
curl_easy_setopt(curl, CURLOPT_POST, 1);
316-
std::string str;
317-
for (auto &post_field : request.post_fields) {
318-
if (!str.empty())
319-
str += "&";
320-
str += urlencode(post_field.first);
321-
str += "=";
322-
str += urlencode(post_field.second);
323-
}
324-
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
325-
str.size());
326-
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS,
327-
str.c_str());
328312
} else {
329-
curl_easy_setopt(curl, CURLOPT_POST, 1);
330-
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
331-
request.post_data.size());
332-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
333-
request.post_data.c_str());
334-
// request.post_data must now *never* be
335-
// modified until CURLOPT_POSTFIELDS is cleared
313+
switch (request.method) {
314+
case HTTP_GET:
315+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
316+
break;
317+
case HTTP_POST:
318+
curl_easy_setopt(curl, CURLOPT_POST, 1);
319+
break;
320+
case HTTP_PUT:
321+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
322+
break;
323+
case HTTP_DELETE:
324+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
325+
break;
326+
}
327+
if (request.method != HTTP_GET) {
328+
if (!request.raw_data.empty()) {
329+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
330+
request.raw_data.size());
331+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
332+
request.raw_data.c_str());
333+
} else if (!request.fields.empty()) {
334+
std::string str;
335+
for (auto &field : request.fields) {
336+
if (!str.empty())
337+
str += "&";
338+
str += urlencode(field.first);
339+
str += "=";
340+
str += urlencode(field.second);
341+
}
342+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
343+
str.size());
344+
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS,
345+
str.c_str());
346+
}
347+
}
336348
}
337349
// Set additional HTTP headers
338350
for (const std::string &extra_header : request.extra_headers) {

‎src/httpfetch.h

+17-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2828
#define HTTPFETCH_DISCARD 0
2929
#define HTTPFETCH_SYNC 1
3030

31+
// Methods
32+
enum HttpMethod : u8
33+
{
34+
HTTP_GET,
35+
HTTP_POST,
36+
HTTP_PUT,
37+
HTTP_DELETE,
38+
};
39+
3140
struct HTTPFetchRequest
3241
{
3342
std::string url = "";
@@ -50,12 +59,15 @@ struct HTTPFetchRequest
5059
// application/x-www-form-urlencoded. POST-only.
5160
bool multipart = false;
5261

53-
// POST fields. Fields are escaped properly.
54-
// If this is empty a GET request is done instead.
55-
StringMap post_fields;
62+
// The Method to use default = GET
63+
// Avaible methods GET, POST, PUT, DELETE
64+
HttpMethod method = HTTP_GET;
65+
66+
// Fields of the request
67+
StringMap fields;
5668

57-
// Raw POST data, overrides post_fields.
58-
std::string post_data;
69+
// Raw data of the request overrides fields
70+
std::string raw_data;
5971

6072
// If not empty, should contain entries such as "Accept: text/html"
6173
std::vector<std::string> extra_headers;

‎src/network/networkprotocol.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ const static std::string accessDeniedStrings[SERVER_ACCESSDENIED_MAX] = {
10341034
"This server has experienced an internal error. You will now be disconnected."
10351035
};
10361036

1037-
enum PlayerListModifer: u8
1037+
enum PlayerListModifer : u8
10381038
{
10391039
PLAYER_LIST_INIT,
10401040
PLAYER_LIST_ADD,

‎src/script/lua_api/l_http.cpp

+26-3
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,40 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
4949
req.multipart = getboolfield_default(L, 1, "multipart", false);
5050
req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000;
5151

52-
// post_data: if table, post form data, otherwise raw data
52+
lua_getfield(L, 1, "method");
53+
if (lua_isstring(L, -1)) {
54+
std::string mth = getstringfield_default(L, 1, "method", "");
55+
if (mth == "GET")
56+
req.method = HTTP_GET;
57+
else if (mth == "POST")
58+
req.method = HTTP_POST;
59+
else if (mth == "PUT")
60+
req.method = HTTP_PUT;
61+
else if (mth == "DELETE")
62+
req.method = HTTP_DELETE;
63+
}
64+
lua_pop(L, 1);
65+
66+
// post_data: if table, post form data, otherwise raw data DEPRECATED use data and method instead
5367
lua_getfield(L, 1, "post_data");
68+
if (lua_isnil(L, 2)) {
69+
lua_pop(L, 1);
70+
lua_getfield(L, 1, "data");
71+
}
72+
else {
73+
req.method = HTTP_POST;
74+
}
75+
5476
if (lua_istable(L, 2)) {
5577
lua_pushnil(L);
5678
while (lua_next(L, 2) != 0) {
57-
req.post_fields[readParam<std::string>(L, -2)] = readParam<std::string>(L, -1);
79+
req.fields[readParam<std::string>(L, -2)] = readParam<std::string>(L, -1);
5880
lua_pop(L, 1);
5981
}
6082
} else if (lua_isstring(L, 2)) {
61-
req.post_data = readParam<std::string>(L, 2);
83+
req.raw_data = readParam<std::string>(L, 2);
6284
}
85+
6386
lua_pop(L, 1);
6487

6588
lua_getfield(L, 1, "extra_headers");

‎src/script/lua_api/l_http.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ class ModApiHttp : public ModApiBase {
3232
static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
3333
static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true);
3434

35-
// http_fetch_sync({url=, timeout=, post_data=})
35+
// http_fetch_sync({url=, timeout=, data=})
3636
static int l_http_fetch_sync(lua_State *L);
3737

38-
// http_fetch_async({url=, timeout=, post_data=})
38+
// http_fetch_async({url=, timeout=, data=})
3939
static int l_http_fetch_async(lua_State *L);
4040

4141
// http_fetch_async_get(handle)

‎src/serverlist.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,11 @@ void sendAnnounce(AnnounceAction action,
261261

262262
HTTPFetchRequest fetch_request;
263263
fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce");
264-
fetch_request.post_fields["json"] = fastWriteJson(server);
264+
fetch_request.method = HTTP_POST;
265+
fetch_request.fields["json"] = fastWriteJson(server);
265266
fetch_request.multipart = true;
266267
httpfetch_async(fetch_request);
267268
}
268269
#endif
269270

270271
} // namespace ServerList
271-

0 commit comments

Comments
 (0)
Please sign in to comment.