1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
--[[
-- This module is part of the LuaHTTP package
-- The purpose of this module is to make HTTP requests and return the response.
--
-- Dependencies:
-- dkjson
-- luasec
-- ltn12
-- feedparser
]]
local moduleName = fetch
local M = {}
---------- Dependencies ------------------------
local http = require("socket.http")
local urlsocket = require("socket.url")
local https = require("ssl.https")
local dkjson = require("dkjson")
local ltn12 = require("ltn12")
local feedparser = require("feedparser")
---------- Local variables ---------------------
---------- Helper functions --------------------
--- Makes an HTTP request using the provided request parameter.
-- @param request table containing the request parameters
-- @return the response as a table
local function http_request(request)
local url = request.url
print("\nConnecting to " .. url)
-- Detect HTTPS
local client = http
if url:lower():find("^https://") then
client = https
end
-- Save optional body
local body = request.body
-- Prepare request
local response = {}
local request = {
method = request.method or "GET",
url = url,
headers = request.headers or nil,
redirect = request.redirect or false,
sink = ltn12.sink.table(response)
}
-- Send optional body
if body then
if type(body) == "table" then
body = dkjson.encode(body)
end
request.source = ltn12.source.string(body)
request.headers["Content-Length"] = #body
end
-- Make the request
local response_status, response_code, response_header, response_message = client.request(request)
local message = response_message or "(No response message recieved)"
if response_status == nil then
error("\n!!! Error connecting to " .. url .. "\nResponse: " .. response_code .. "\nMessage: " .. message)
end
-- Check for redirects and return body
if response_code == 301 or response_code == 302 or response_code == 303 then
print("\nResponse " .. message)
local redirect_url = response_header["location"]
if redirect_url == url then
error("\n!!! Error connecting to " .. url .. " results in a redirection loop")
else
print("\n!! Warning: redirecting to " .. redirect_url)
request.url = redirect_url
return http_request(request)
end
elseif response_code == 200 then
print("\nResponse " .. message)
if response == null or not next(response) then
error("\n!!! Error empty response")
end
return response
else
error("\n!!! Error connecting to " .. url .. "\nResponse: " .. response_code .. "\nMessage: " .. message)
end
end
--- Parse the given JSON-file.
-- @param file_path path to JSON-file
-- @return table containing the JSON data
local function parse_json_file(file_path)
local file = io.open(file_path, "r")
local content = file:read("*all")
file:close()
return dkjson.decode(content)
end
--- Split a given string on the first occurence of a given character.
-- @param str string containing the given character
-- @param char target character at which the string gets split
-- @return table containing the first part of the string as the key and the second part as the value
local function split_first(str, char)
local result = {}
local pos = str:find(char)
local key = str:sub(1, pos - 1)
local value = str:sub(pos + 1)
result[key] = value
return result
end
---------- Module functions --------------------
--- Make a GET request using the provided URL
-- @param url target URL
-- @return table containg the response
function M.json(url)
local request = {
method = "GET",
url = url,
headers = {
["Accept"] = "application/json"
},
}
local response = http_request(request)
return dkjson.decode(table.concat(response))
end
--- Make a request using the provided JSON-file
-- @param json_file_path path to JSON-file
-- @return table containg the response
function M.json_using_file(json_file_path)
print("\nUsing file " .. json_file_path)
local request = parse_json_file(json_file_path)
local response = http_request(request)
return dkjson.decode(table.concat(response))
end
--- Make a GET request using the provided URL
-- @param url target URL
-- @return table containg the response
function M.rss(url)
local request = {
method = "GET",
url = url,
headers = {
["Accept"] = "application/rss+xml"
},
}
local response = http_request(request)
return feedparser.parse(table.concat(response))
end
--- Fetch image data using the provided URL
-- @param url target URL leading to an image
-- @return image data
function M.image(url)
local request = {
method = "GET",
url = url
}
local response = http_request(request)
return table.concat(response)
end
--- Make a POST request using the provided URL and query parameters
-- @param url target URL
-- @param query_parameters parameters sent in the URL
-- @return table containg the response
function M.json_using_query(url, query_parameters)
local url = url
for _, value in ipairs(query_parameters) do
local params = split_first(value, "=")
for k, v in pairs(params) do
v = string.gsub(v, "\n", "")
url = url .. k .. "=" .. urlsocket.escape(v)
end
end
print("\nURL: " .. url)
local request = {
method = "POST",
url = url,
headers = {
["Accept"] = "application/json",
["Content-Type"] = "application/x-www-form-urlencoded";
},
redirect = false
}
local response = http_request(request)
return dkjson.decode(table.concat(response))
end
return M
|