-
Notifications
You must be signed in to change notification settings - Fork 0
Luasec HTTPS Module
The HTTPS module (https.lua) is the result of integrating the HTTP functions from Luasocket into the Luasec module itself. The parameters are same as the Luasocket HTTP module with support for extra parameters.
The request function has two forms. The simple form downloads a URL using the GET
or POST
method and is based on strings. The generic form performs any HTTP method and is LTN12
based.
If the first argument of the request function is a string, it should be an url. In that case, if a body is provided as a string, the function will perform a POST
method in the url. Otherwise, it performs a GET
in the url.
If the first argument is instead a table, the most important fields are the url and the simple LTN12
sink that will receive the downloaded content. Any part of the url can be overridden by including the appropriate field in the request table. If authentication information is provided, the function uses the Basic Authentication Scheme to retrieve the document. If sink is nil, the function discards the downloaded data.
The optional parameters are the following:
-
method: The HTTP request method. Defaults to
GET
. -
headers: Any additional HTTP headers to send with the request.
-
source: simple
LTN12
source to provide the request body. If there is a body, you need to provide an appropriate "content-length" request header field, or the function will attempt to send the body as "chunked" (something few servers support). Defaults to the empty source. -
step: LTN12 pump step function used to move data. Defaults to the LTN12 pump.step function.
-
proxy: The URL of a proxy server to use. Defaults to no proxy. A
CONNECT
tunnel is created between the proxy and the luasec client. -
redirect: Set to false to prevent the function from automatically following 301 or 302 server redirect messages.It defaults to true.
-
unsaferedirect: Defaults to false to prevent redirects(downgrades) from HTTPS -> HTTP.
-
create: An optional function to be used instead of socket.tcp when the communications socket is created.
In case of failure, the function returns nil followed by an error message. If successful, the simple form returns the response body as a string, followed by the response status code, the response headers and the response status line. The generic function returns the same information, except the first return value is just the number 1 (the body goes to the sink).
Even when the server fails to provide the contents of the requested URL (URL not found, for example), it usually returns a message body (a web page informing the URL was not found or some other useless page). To make sure the operation was successful, check the returned status code. For a list of the possible values and their meanings, refer to RFC 2616.
First require the libraries into the namespace and make a table for holding the final result.
local https = require("ssl.https")
local ltn12 = require('ltn12')
local result_table = {}
This is the second form of the function where we pass a request table and a sink. We are querying https://google.com while setting redirect
to true.
local reqt = {
url = 'https://google.com',
redirect = true,
target = {},
}
reqt.sink = ltn12.sink.table(result_table)
Then pass the request table to the https.request
function.
local result, code, headers, status = https.request(reqt)
Now result_table
would contain the data transferred from the connection and headers
table would have all the HTTP headers in the response.
print(code, status)
-- 200 OK
If we want to route the HTTPS session through a proxy we modify the request table like this. On the background it actually creates a CONNECT tunnel between the client and the proxy. On the proxies end, it just starts forwarding packets to and fro between the destination server and luasec.
local reqt = {
url = 'https://google.com',
redirect = true,
target = {},
proxy = "http://<proxy ip address>:<proxy port>",
}
reqt.sink = ltn12.sink.table(result_table)
local result, code, headers, status = https.request(reqt)
If we want to allow unsafe redirects from HTTP->HTTPS downgrade we have to set the unsaferedirects
parameter to true
. In this case once luasec gets to know about the redirect, it checks for the unsaferedirect
paramter and if it is set to true
opens a new tunnel with the proxy with the final destination as the HTTP site. The sample request would look like this:
local reqt = {
url = 'https://goo.gl/tBfqNu',
redirect = true,
target = {},
proxy = "http://<proxy ip address>:<proxy port>",
unsaferedirect = true,
}
reqt.sink = ltn12.sink.table(result_table)
local result, code, headers, status = https.request(reqt)
It can also redirect from HTTP-> HTTPS which is allowed by default. This also works when the proxy is enabled.
local reqt = {
url = 'http://goo.gl/UBCUc5',
redirect = true,
target = {},
proxy = "http://<proxy ip address>:<proxy port>",
unsaferedirect = true,
}
reqt.sink = ltn12.sink.table(result_table)
local result, code, headers, status = https.request(reqt)\
Here is a complete example with the proxy
parameter set. It prints out the entire HTML received for different cases.
local https = require("ssl.https")
local ltn12 = require('ltn12')
local result_table = {}
local function doreq(url)
local reqt = {
url = url,
redirect = true,
target = {},
proxy = "http://172.28.128.1:4444",
-- unsaferedirect = true, -- uncomment this line when testing the security case
}
reqt.sink = ltn12.sink.table(result_table)
local result, code, headers, status = https.request(reqt)
print("Fetching:",url,"==>",code, status)
if result then for k,v in pairs(headers) do print("",k,v) end end
if result then for k,v in pairs(result_table) do print("",k,v) end end
print(result)
return result, code, headers, status
end
-- local result, code, headers, status = doreq("http://example.com")--simple http
-- local result, code, headers, status = doreq("http://goo.gl/tBfqNu") -- http --> http redirect
-- local result, code, headers, status = doreq("https://example.com") --simple https
local result, code, headers, status = doreq("https://google.com") -- https --> https redirect
-- local result, code, headers, status = doreq("http://goo.gl/UBCUc5") -- http --> https redirect
-- local result, code, headers, status = doreq("https://goo.gl/tBfqNu") -- https --> http security test case