From 16a2ccd876c3dac2331de3e20c74edf1d910f09c Mon Sep 17 00:00:00 2001 From: RodrigoDornelles Date: Wed, 7 Aug 2024 16:29:32 -0300 Subject: [PATCH] feat: standardize http --- src/engine/core/html5/engine.js | 13 +++++-- src/lib/engine/http.lua | 42 ++++++++++++++-------- src/lib/protocol/http_curl.lua | 15 +++++--- src/lib/protocol/http_ginga.lua | 22 ++++++------ src/lib/util/http.lua | 51 ++++++++++++++++++++++++++- tests/test_lib_common_http.lua | 4 +-- tests/test_lib_protocol_http_curl.lua | 30 ++++++++++++++-- 7 files changed, 140 insertions(+), 37 deletions(-) diff --git a/src/engine/core/html5/engine.js b/src/engine/core/html5/engine.js index 50af3ce..2fb61e9 100644 --- a/src/engine/core/html5/engine.js +++ b/src/engine/core/html5/engine.js @@ -66,8 +66,17 @@ document.addEventListener('DOMContentLoaded', async () => { } const browser_protocol_http = { handler: (self) => { - self.promise() - fetch(self.url) + const method = self.method + const headers = new Headers(self.headers_dict) + const params = new URLSearchParams(self.params_dict) + const url = `${self.url}` + '?' + params.toString() + const body = ['HEAD', 'GET'].includes(method)? null: self.body_content + self.promise() + fetch(url, { + body: body, + method: method, + headers: headers + }) .then((response) => { self.set('ok', response.ok) self.set('status', response.status) diff --git a/src/lib/engine/http.lua b/src/lib/engine/http.lua index 7bad3ec..ec27566 100644 --- a/src/lib/engine/http.lua +++ b/src/lib/engine/http.lua @@ -19,16 +19,16 @@ local function body(self, content) end local function param(self, name, value) - local index = #self.param_name_list + 1 - self.param_name_list[index] = name - self.param_value_list[index] = value + local index = #self.param_list + 1 + self.param_list[index] = name + self.param_dict[name] = value return self end local function header(self, name, value) - local index = #self.header_name_list + 1 - self.header_name_list[index] = name - self.header_value_list[index] = value + local index = #self.header_list + 1 + self.header_list[index] = name + self.header_dict[name] = value return self end @@ -65,10 +65,10 @@ local function request(method, std, game, application, protocol_handler) speed = '', method = method, body_content = '', - header_name_list = {}, - header_value_list = {}, - param_name_list = {}, - param_value_list = {}, + header_list = {}, + header_dict = {}, + param_list = {}, + param_dict = {}, callback_handler = callback_handler, success_handler = function () end, failed_handler = function () end, @@ -127,14 +127,27 @@ local function request(method, std, game, application, protocol_handler) self.std.http.error = nil self.std.http.status = nil end, + -- clean lists + function() + local index = 1 + while index <= #self.param_list do + self.param_dict[self.param_list[index]] = nil + index = index + 1 + end + index = 1 + while index <= #self.header_list do + self.header_dict[self.header_list[index]] = nil + index = index + 1 + end + end, -- clean gc function() self.url = nil self.body_content = nil - self.param_name_list = nil - self.param_value_list = nil - self.header_name_list = nil - self.header_value_list = nil + self.param_list = nil + self.param_dict = nil + self.header_list = nil + self.header_dict = nil self.success_handler = nil self.failed_handler = nil self.std = nil @@ -169,7 +182,6 @@ local function install(std, game, application, protocol) std.http.put=request('PUT', std, game, application, protocol_handler) std.http.delete=request('DELETE', std, game, application, protocol_handler) std.http.patch=request('PATCH', std, game, application, protocol_handler) - if protocol.install then protocol.install(std, game, application) diff --git a/src/lib/protocol/http_curl.lua b/src/lib/protocol/http_curl.lua index 387077f..6474653 100644 --- a/src/lib/protocol/http_curl.lua +++ b/src/lib/protocol/http_curl.lua @@ -1,16 +1,23 @@ +--! @todo support Body content in post +local http_util = require('src/lib/util/http') + local function http_handler(self) local index = 1 local cmd = 'curl -L --silent --insecure -w "\n%{http_code}" ' local protocol = self.method == 'HEAD' and '--HEAD' or '-X '..self.method + local params = http_util.url_search_param(self.param_list, self.param_dict) local headers, index = ' ', 1 - while self.header_name_list and index <= #self.header_name_list do - headers = headers..'-H "'..self.header_name_list[index]..': ' - headers = headers..self.header_value_list[index]..'" ' + + while self.header_list and index <= #self.header_list do + local header = self.header_list[index] + headers = headers..'-H "'..header..': ' + headers = headers..self.header_dict[self.header_list[index]]..'" ' index = index + 1 end - local handle = io and io.popen and io.popen(cmd..protocol..headers..self.url) + + local handle = io and io.popen and io.popen(cmd..protocol..headers..self.url..params) if handle then local stdout = handle:read("*a") diff --git a/src/lib/protocol/http_ginga.lua b/src/lib/protocol/http_ginga.lua index 98afabd..9e6a2a9 100644 --- a/src/lib/protocol/http_ginga.lua +++ b/src/lib/protocol/http_ginga.lua @@ -80,14 +80,16 @@ local http_util = require('src/lib/util/http') --! @cond local function http_connect(self) - local request = 'GET '..self.p_uri..' HTTP/1.1\r\n' - ..'Host: '..self.p_host..'\r\n' - ..'User-Agent: Mozilla/4.0 (compatible; MSIE 4.0; Windows 95; Win 9x 4.90)\r\n' - ..'Cache-Control: max-age=0\r\n' - ..'Accept: */*\r\n' - ..'Content-Length: '..tostring(#self.body_content)..'\r\n' - ..'Connection: close\r\n\r\n' - ..self.body_content..'\r\n\r\n' + local params = http_util.url_search_param(self.param_list, self.param_dict) + local headers = http_util.headers(self.header_list, self.header_dict, { + 'Host', self.p_host..params, false, + 'Accept', '*/*', true, + 'Cache-Control', 'max-age=0', false, + 'User-Agent', 'Mozilla/4.0 (compatible; MSIE 4.0; Windows 95; Win 9x 4.90)', true, + 'Content-Length', tostring(#self.body_content), false, + 'Connection', 'close', false + }) + local request = 'GET '..self.p_uri..' HTTP/1.1\r\n'..headers..'\r\n'..self.body_content..'\r\n\r\n' event.post({ class = 'tcp', @@ -101,7 +103,7 @@ end --! @cond local function http_connect_dns(self) if self.p_host == self.evt.host then - self.application.internal.dns_state = 2 + self.application.internal.http.dns_state = 2 else self.application.internal.http.context.dns(self) self.application.internal.http.dns_state = 3 @@ -397,11 +399,9 @@ local function event_loop(std, game, application, evt) local value = tostring(evt.value) local debug = evt.type..' '..tostring(evt.host)..' '..tostring(evt.connection)..' '..value:sub(1, (value:find('\n') or 30) - 2) - --game._debug = debug..'\r\n\r\n'..game._debug if self then local index = 'http_'..self.evt.type..self.speed - --game._debug = index..'\r\n'..game._debug application.internal.http.callbacks[index](self) end end diff --git a/src/lib/util/http.lua b/src/lib/util/http.lua index 9ae9b54..1d77614 100644 --- a/src/lib/util/http.lua +++ b/src/lib/util/http.lua @@ -6,7 +6,56 @@ local function is_redirect(status) return (status and 300 <= status and status < 400) or false end +local function url_search_param(param_list, param_dict) + local index, params = 1, '' + while param_list and param_dict and index <= #param_list do + local param = param_list[index] + if #params == 0 then + params = param..'?' + else + params = param..'&' + end + params = params..param..'='..param_dict[param_list[index]] + index = index + 1 + end + return params +end + +--! @todo document this function +local function headers(header_list, header_dict, config) + local headers = '' + + if not header_list or not header_dict then + header_list = {} + header_dict = {} + end + + local index = 1 + while index <= #config do + local header = config[index] + local default = config[index + 1] + local mutable = config[index + 2] + local value = default + if mutable then + value = header_dict[header] or default + end + headers = headers..header..': '..value..'\r\n' + index = index + 3 + end + + local index = 1 + while index <= #header_list do + local header = header_list[index] + headers = headers..header..': '..header_dict[header]..'\r\n' + index = index + 1 + end + + return headers +end + return { is_ok=is_ok, - is_redirect=is_redirect + is_redirect=is_redirect, + url_search_param=url_search_param, + headers=headers } diff --git a/tests/test_lib_common_http.lua b/tests/test_lib_common_http.lua index ccf85fa..d82dd2b 100644 --- a/tests/test_lib_common_http.lua +++ b/tests/test_lib_common_http.lua @@ -12,10 +12,10 @@ local http_handler = mock_http.requests({ ['example.com/set-status-body-param1-param2'] = { ok = true, status = function(http_object) - return http_object.param_value_list[1] + return http_object.param_dict[http_object.param_list[1]] end, body = function(http_object) - return http_object.param_value_list[2] + return http_object.param_dict[http_object.param_list[2]] end }, ['example.com/set-body-lower-with-body'] = { diff --git a/tests/test_lib_protocol_http_curl.lua b/tests/test_lib_protocol_http_curl.lua index 4093726..5d08466 100644 --- a/tests/test_lib_protocol_http_curl.lua +++ b/tests/test_lib_protocol_http_curl.lua @@ -11,6 +11,10 @@ local mock_popen = mock_io.open({ read=function () return 'method not allowed!\n403' end, close=function () return true, nil end }, + ['curl -L --silent --insecure -w "\n%{http_code}" -X POST pudim.com.brz&z=zoom'] = { + read=function () return 'me too!\n201' end, + close=function () return true, nil end + }, ['curl -L --silent --insecure -w "\n%{http_code}" --HEAD '] = { read=function () return '' end, close=function () return false, 'no URL specified!' end @@ -33,14 +37,36 @@ function test_http_get_200() luaunit.assertEquals(std.http.body, 'i love pudim!\n') end +function test_http_post_201() + local std = {http={}} + io.popen = mock_popen + + protocol_http.handler({ + std = std, + param_list = {'foo', 'bar', 'z'}, + param_dict = { + ['foo'] = 'zig', + ['bar'] = 'zag', + ['z'] = 'zoom' + }, + url = 'pudim.com.br', + method = 'POST' + }) + + luaunit.assertEquals(std.http.ok, true) + luaunit.assertEquals(std.http.error, nil) + luaunit.assertEquals(std.http.status, 201) + luaunit.assertEquals(std.http.body, 'me too!\n') +end + function test_http_post_403() local std = {http={}} io.popen = mock_popen protocol_http.handler({ std = std, - header_name_list = {'Authorization'}, - header_value_list = {'bearer secret'}, + header_list = {'Authorization'}, + header_dict = {['Authorization'] = 'bearer secret'}, url = 'pudim.com.br', method = 'POST' })