-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathhttps.lua
145 lines (130 loc) · 4.08 KB
/
https.lua
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
----------------------------------------------------------------------------
-- LuaSec 0.4.1
-- Copyright (C) 2009-2011 PUC-Rio
--
-- Author: Pablo Musa
-- Author: Tomas Guisasola
---------------------------------------------------------------------------
local socket = require("socket")
local ssl = require("ssl")
local ltn12 = require("ltn12")
local http = require("socket.http")
local url = require("socket.url")
local table = require("table")
local string = require("string")
local try = socket.try
local type = type
local pairs = pairs
local getmetatable = getmetatable
module("ssl.https")
_VERSION = "0.4.1"
_COPYRIGHT = "LuaSec 0.4.1 - Copyright (C) 2009-2011 PUC-Rio"
-- Default settings
PORT = 443
local cfg = {
protocol = "tlsv1",
options = "all",
verify = "none",
}
--------------------------------------------------------------------
-- Auxiliar Functions
--------------------------------------------------------------------
-- Insert default HTTPS port.
local function default_https_port(u)
return url.build(url.parse(u, {port = PORT}))
end
-- Convert an URL to a table according to Luasocket needs.
local function urlstring_totable(url, body, result_table)
url = {
url = default_https_port(url),
method = body and "POST" or "GET",
sink = ltn12.sink.table(result_table)
}
if body then
url.source = ltn12.source.string(body)
url.headers = {
["content-length"] = #body,
["content-type"] = "application/x-www-form-urlencoded",
}
end
return url
end
-- Forward calls to the real connection object.
local function reg(conn)
local mt = getmetatable(conn.sock).__index
for name, method in pairs(mt) do
if type(method) == "function" then
conn[name] = function (self, ...)
return method(self.sock, ...)
end
end
end
end
local digests = {}
-- Return a function which performs the SSL/TLS connection.
local function tcp(params)
params = params or {}
-- Default settings
for k, v in pairs(cfg) do
params[k] = params[k] or v
end
-- Force client mode
params.mode = "client"
-- 'create' function for LuaSocket
local ret
ret = function ()
local conn = {}
conn.sock = try(socket.tcp())
local st = getmetatable(conn.sock).__index.settimeout
function conn:settimeout(...)
return st(self.sock, ...)
end
-- Replace TCP's connection function
function conn:connect(host, port)
try(self.sock:connect(host, port))
self.sock = try(ssl.wrap(self.sock, params))
try(self.sock:dohandshake())
digests[ret] = self.sock:getpeercertificate():digest("sha256")
reg(self, getmetatable(self.sock))
return 1
end
return conn
end
return ret
end
--------------------------------------------------------------------
-- Main Function
--------------------------------------------------------------------
-- Make a HTTP request over secure connection. This function receives
-- the same parameters of LuaSocket's HTTP module (except 'proxy' and
-- 'redirect') plus LuaSec parameters.
--
-- @param url mandatory (string or table)
-- @param body optional (string)
-- @return (string if url == string or 1), code, headers, status
--
function request(url, body)
local result_table = {}
local stringrequest = type(url) == "string"
if stringrequest then
url = urlstring_totable(url, body, result_table)
else
url.url = default_https_port(url.url)
end
if http.PROXY or url.proxy then
return nil, "proxy not supported"
elseif url.redirect then
return nil, "redirect not supported"
elseif url.create then
return nil, "create function not permitted"
end
-- New 'create' function to establish a secure connection
url.create = tcp(url)
local res, code, headers, status = http.request(url)
local digest = digests[url.create]
digests[url.create] = nil
if res and stringrequest then
return table.concat(result_table), code, headers, status, digest
end
return res, code, headers, status, digest
end