Guest User

Untitled

a guest
May 28th, 2018
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.50 KB | None | 0 0
  1. -----------------------------------------------------------------------------
  2. -- URI parsing, composition and relative URL resolution
  3. -- LuaSocket toolkit.
  4. -- Author: Diego Nehab
  5. -----------------------------------------------------------------------------
  6.  
  7. -----------------------------------------------------------------------------
  8. -- Declare module
  9. -----------------------------------------------------------------------------
  10. local string = require("string")
  11. local base = _G
  12. local table = require("table")
  13. local socket = require("socket")
  14.  
  15. socket.url = {}
  16. local _M = socket.url
  17.  
  18. -----------------------------------------------------------------------------
  19. -- Module version
  20. -----------------------------------------------------------------------------
  21. _M._VERSION = "URL 1.0.3"
  22.  
  23. -----------------------------------------------------------------------------
  24. -- Encodes a string into its escaped hexadecimal representation
  25. -- Input
  26. -- s: binary string to be encoded
  27. -- Returns
  28. -- escaped representation of string binary
  29. -----------------------------------------------------------------------------
  30. function _M.escape(s)
  31. return (string.gsub(s, "([^A-Za-z0-9_])", function(c)
  32. return string.format("%%%02x", string.byte(c))
  33. end))
  34. end
  35.  
  36. -----------------------------------------------------------------------------
  37. -- Protects a path segment, to prevent it from interfering with the
  38. -- url parsing.
  39. -- Input
  40. -- s: binary string to be encoded
  41. -- Returns
  42. -- escaped representation of string binary
  43. -----------------------------------------------------------------------------
  44. local function make_set(t)
  45. local s = {}
  46. for i,v in base.ipairs(t) do
  47. s[t[i]] = 1
  48. end
  49. return s
  50. end
  51.  
  52. -- these are allowed within a path segment, along with alphanum
  53. -- other characters must be escaped
  54. local segment_set = make_set {
  55. "-", "_", ".", "!", "~", "*", "'", "(",
  56. ")", ":", "@", "&", "=", "+", "$", ",",
  57. }
  58.  
  59. local function protect_segment(s)
  60. return string.gsub(s, "([^A-Za-z0-9_])", function (c)
  61. if segment_set[c] then return c
  62. else return string.format("%%%02X", string.byte(c)) end
  63. end)
  64. end
  65.  
  66. -----------------------------------------------------------------------------
  67. -- Unencodes a escaped hexadecimal string into its binary representation
  68. -- Input
  69. -- s: escaped hexadecimal string to be unencoded
  70. -- Returns
  71. -- unescaped binary representation of escaped hexadecimal binary
  72. -----------------------------------------------------------------------------
  73. function _M.unescape(s)
  74. return (string.gsub(s, "%%(%x%x)", function(hex)
  75. return string.char(base.tonumber(hex, 16))
  76. end))
  77. end
  78.  
  79. -----------------------------------------------------------------------------
  80. -- Builds a path from a base path and a relative path
  81. -- Input
  82. -- base_path
  83. -- relative_path
  84. -- Returns
  85. -- corresponding absolute path
  86. -----------------------------------------------------------------------------
  87. local function absolute_path(base_path, relative_path)
  88. if string.sub(relative_path, 1, 1) == "/" then return relative_path end
  89. local path = string.gsub(base_path, "[^/]*$", "")
  90. path = path .. relative_path
  91. path = string.gsub(path, "([^/]*%./)", function (s)
  92. if s ~= "./" then return s else return "" end
  93. end)
  94. path = string.gsub(path, "/%.$", "/")
  95. local reduced
  96. while reduced ~= path do
  97. reduced = path
  98. path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
  99. if s ~= "../../" then return "" else return s end
  100. end)
  101. end
  102. path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
  103. if s ~= "../.." then return "" else return s end
  104. end)
  105. return path
  106. end
  107.  
  108. -----------------------------------------------------------------------------
  109. -- Parses a url and returns a table with all its parts according to RFC 2396
  110. -- The following grammar describes the names given to the URL parts
  111. -- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
  112. -- <authority> ::= <userinfo>@<host>:<port>
  113. -- <userinfo> ::= <user>[:<password>]
  114. -- <path> :: = {<segment>/}<segment>
  115. -- Input
  116. -- url: uniform resource locator of request
  117. -- default: table with default values for each field
  118. -- Returns
  119. -- table with the following fields, where RFC naming conventions have
  120. -- been preserved:
  121. -- scheme, authority, userinfo, user, password, host, port,
  122. -- path, params, query, fragment
  123. -- Obs:
  124. -- the leading '/' in {/<path>} is considered part of <path>
  125. -----------------------------------------------------------------------------
  126. function _M.parse(url, default)
  127. -- initialize default parameters
  128. local parsed = {}
  129. for i,v in base.pairs(default or parsed) do parsed[i] = v end
  130. -- empty url is parsed to nil
  131. if not url or url == "" then return nil, "invalid url" end
  132. -- remove whitespace
  133. -- url = string.gsub(url, "%s", "")
  134. -- get scheme
  135. url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
  136. function(s) parsed.scheme = s; return "" end)
  137. -- get authority
  138. url = string.gsub(url, "^//([^/]*)", function(n)
  139. parsed.authority = n
  140. return ""
  141. end)
  142. -- get fragment
  143. url = string.gsub(url, "#(.*)$", function(f)
  144. parsed.fragment = f
  145. return ""
  146. end)
  147. -- get query string
  148. url = string.gsub(url, "%?(.*)", function(q)
  149. parsed.query = q
  150. return ""
  151. end)
  152. -- get params
  153. url = string.gsub(url, "%;(.*)", function(p)
  154. parsed.params = p
  155. return ""
  156. end)
  157. -- path is whatever was left
  158. if url ~= "" then parsed.path = url end
  159. local authority = parsed.authority
  160. if not authority then return parsed end
  161. authority = string.gsub(authority,"^([^@]*)@",
  162. function(u) parsed.userinfo = u; return "" end)
  163. authority = string.gsub(authority, ":([^:%]]*)$",
  164. function(p) parsed.port = p; return "" end)
  165. if authority ~= "" then
  166. -- IPv6?
  167. parsed.host = string.match(authority, "^%[(.+)%]$") or authority
  168. end
  169. local userinfo = parsed.userinfo
  170. if not userinfo then return parsed end
  171. userinfo = string.gsub(userinfo, ":([^:]*)$",
  172. function(p) parsed.password = p; return "" end)
  173. parsed.user = userinfo
  174. return parsed
  175. end
  176.  
  177. -----------------------------------------------------------------------------
  178. -- Rebuilds a parsed URL from its components.
  179. -- Components are protected if any reserved or unallowed characters are found
  180. -- Input
  181. -- parsed: parsed URL, as returned by parse
  182. -- Returns
  183. -- a stringing with the corresponding URL
  184. -----------------------------------------------------------------------------
  185. function _M.build(parsed)
  186. --local ppath = _M.parse_path(parsed.path or "")
  187. --local url = _M.build_path(ppath)
  188. local url = parsed.path or ""
  189. if parsed.params then url = url .. ";" .. parsed.params end
  190. if parsed.query then url = url .. "?" .. parsed.query end
  191. local authority = parsed.authority
  192. if parsed.host then
  193. authority = parsed.host
  194. if string.find(authority, ":") then -- IPv6?
  195. authority = "[" .. authority .. "]"
  196. end
  197. if parsed.port then authority = authority .. ":" .. base.tostring(parsed.port) end
  198. local userinfo = parsed.userinfo
  199. if parsed.user then
  200. userinfo = parsed.user
  201. if parsed.password then
  202. userinfo = userinfo .. ":" .. parsed.password
  203. end
  204. end
  205. if userinfo then authority = userinfo .. "@" .. authority end
  206. end
  207. if authority then url = "//" .. authority .. url end
  208. if parsed.scheme then url = parsed.scheme .. ":" .. url end
  209. if parsed.fragment then url = url .. "#" .. parsed.fragment end
  210. -- url = string.gsub(url, "%s", "")
  211. return url
  212. end
  213.  
  214. -----------------------------------------------------------------------------
  215. -- Builds a absolute URL from a base and a relative URL according to RFC 2396
  216. -- Input
  217. -- base_url
  218. -- relative_url
  219. -- Returns
  220. -- corresponding absolute url
  221. -----------------------------------------------------------------------------
  222. function _M.absolute(base_url, relative_url)
  223. local base_parsed
  224. if base.type(base_url) == "table" then
  225. base_parsed = base_url
  226. base_url = _M.build(base_parsed)
  227. else
  228. base_parsed = _M.parse(base_url)
  229. end
  230. local relative_parsed = _M.parse(relative_url)
  231. if not base_parsed then return relative_url
  232. elseif not relative_parsed then return base_url
  233. elseif relative_parsed.scheme then return relative_url
  234. else
  235. relative_parsed.scheme = base_parsed.scheme
  236. if not relative_parsed.authority then
  237. relative_parsed.authority = base_parsed.authority
  238. if not relative_parsed.path then
  239. relative_parsed.path = base_parsed.path
  240. if not relative_parsed.params then
  241. relative_parsed.params = base_parsed.params
  242. if not relative_parsed.query then
  243. relative_parsed.query = base_parsed.query
  244. end
  245. end
  246. else
  247. relative_parsed.path = absolute_path(base_parsed.path or "",
  248. relative_parsed.path)
  249. end
  250. end
  251. return _M.build(relative_parsed)
  252. end
  253. end
  254.  
  255. -----------------------------------------------------------------------------
  256. -- Breaks a path into its segments, unescaping the segments
  257. -- Input
  258. -- path
  259. -- Returns
  260. -- segment: a table with one entry per segment
  261. -----------------------------------------------------------------------------
  262. function _M.parse_path(path)
  263. local parsed = {}
  264. path = path or ""
  265. --path = string.gsub(path, "%s", "")
  266. string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
  267. for i = 1, #parsed do
  268. parsed[i] = _M.unescape(parsed[i])
  269. end
  270. if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
  271. if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
  272. return parsed
  273. end
  274.  
  275. -----------------------------------------------------------------------------
  276. -- Builds a path component from its segments, escaping protected characters.
  277. -- Input
  278. -- parsed: path segments
  279. -- unsafe: if true, segments are not protected before path is built
  280. -- Returns
  281. -- path: corresponding path stringing
  282. -----------------------------------------------------------------------------
  283. function _M.build_path(parsed, unsafe)
  284. local path = ""
  285. local n = #parsed
  286. if unsafe then
  287. for i = 1, n-1 do
  288. path = path .. parsed[i]
  289. path = path .. "/"
  290. end
  291. if n > 0 then
  292. path = path .. parsed[n]
  293. if parsed.is_directory then path = path .. "/" end
  294. end
  295. else
  296. for i = 1, n-1 do
  297. path = path .. protect_segment(parsed[i])
  298. path = path .. "/"
  299. end
  300. if n > 0 then
  301. path = path .. protect_segment(parsed[n])
  302. if parsed.is_directory then path = path .. "/" end
  303. end
  304. end
  305. if parsed.is_absolute then path = "/" .. path end
  306. return path
  307. end
  308.  
  309. return _M
  310. -----------------------------------------------------------------------------
  311. -- Unified SMTP/FTP subsystem
  312. -- LuaSocket toolkit.
  313. -- Author: Diego Nehab
  314. -----------------------------------------------------------------------------
  315.  
  316. -----------------------------------------------------------------------------
  317. -- Declare module and import dependencies
  318. -----------------------------------------------------------------------------
  319. local base = _G
  320. local string = require("string")
  321. local socket = require("socket")
  322. local ltn12 = require("ltn12")
  323.  
  324. socket.tp = {}
  325. local _M = socket.tp
  326.  
  327. -----------------------------------------------------------------------------
  328. -- Program constants
  329. -----------------------------------------------------------------------------
  330. _M.TIMEOUT = 60
  331.  
  332. -----------------------------------------------------------------------------
  333. -- Implementation
  334. -----------------------------------------------------------------------------
  335. -- gets server reply (works for SMTP and FTP)
  336. local function get_reply(c)
  337. local code, current, sep
  338. local line, err = c:receive()
  339. local reply = line
  340. if err then return nil, err end
  341. code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
  342. if not code then return nil, "invalid server reply" end
  343. if sep == "-" then -- reply is multiline
  344. repeat
  345. line, err = c:receive()
  346. if err then return nil, err end
  347. current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
  348. reply = reply .. "\n" .. line
  349. -- reply ends with same code
  350. until code == current and sep == " "
  351. end
  352. return code, reply
  353. end
  354.  
  355. -- metatable for sock object
  356. local metat = { __index = {} }
  357.  
  358. function metat.__index:getpeername()
  359. return self.c:getpeername()
  360. end
  361.  
  362. function metat.__index:getsockname()
  363. return self.c:getpeername()
  364. end
  365.  
  366. function metat.__index:check(ok)
  367. local code, reply = get_reply(self.c)
  368. if not code then return nil, reply end
  369. if base.type(ok) ~= "function" then
  370. if base.type(ok) == "table" then
  371. for i, v in base.ipairs(ok) do
  372. if string.find(code, v) then
  373. return base.tonumber(code), reply
  374. end
  375. end
  376. return nil, reply
  377. else
  378. if string.find(code, ok) then return base.tonumber(code), reply
  379. else return nil, reply end
  380. end
  381. else return ok(base.tonumber(code), reply) end
  382. end
  383.  
  384. function metat.__index:command(cmd, arg)
  385. cmd = string.upper(cmd)
  386. if arg then
  387. return self.c:send(cmd .. " " .. arg.. "\r\n")
  388. else
  389. return self.c:send(cmd .. "\r\n")
  390. end
  391. end
  392.  
  393. function metat.__index:sink(snk, pat)
  394. local chunk, err = self.c:receive(pat)
  395. return snk(chunk, err)
  396. end
  397.  
  398. function metat.__index:send(data)
  399. return self.c:send(data)
  400. end
  401.  
  402. function metat.__index:receive(pat)
  403. return self.c:receive(pat)
  404. end
  405.  
  406. function metat.__index:getfd()
  407. return self.c:getfd()
  408. end
  409.  
  410. function metat.__index:dirty()
  411. return self.c:dirty()
  412. end
  413.  
  414. function metat.__index:getcontrol()
  415. return self.c
  416. end
  417.  
  418. function metat.__index:source(source, step)
  419. local sink = socket.sink("keep-open", self.c)
  420. local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
  421. return ret, err
  422. end
  423.  
  424. -- closes the underlying c
  425. function metat.__index:close()
  426. self.c:close()
  427. return 1
  428. end
  429.  
  430. -- connect with server and return c object
  431. function _M.connect(host, port, timeout, create)
  432. local c, e = (create or socket.tcp)()
  433. if not c then return nil, e end
  434. c:settimeout(timeout or _M.TIMEOUT)
  435. local r, e = c:connect(host, port)
  436. if not r then
  437. c:close()
  438. return nil, e
  439. end
  440. return base.setmetatable({c = c}, metat)
  441. end
  442.  
  443. return _M
  444. -----------------------------------------------------------------------------
  445. -- LuaSocket helper module
  446. -- Author: Diego Nehab
  447. -----------------------------------------------------------------------------
  448.  
  449. -----------------------------------------------------------------------------
  450. -- Declare module and import dependencies
  451. -----------------------------------------------------------------------------
  452. local base = _G
  453. local string = require("string")
  454. local math = require("math")
  455. local socket = require("socket.core")
  456.  
  457. local _M = socket
  458.  
  459. -----------------------------------------------------------------------------
  460. -- Exported auxiliar functions
  461. -----------------------------------------------------------------------------
  462. function _M.connect4(address, port, laddress, lport)
  463. return socket.connect(address, port, laddress, lport, "inet")
  464. end
  465.  
  466. function _M.connect6(address, port, laddress, lport)
  467. return socket.connect(address, port, laddress, lport, "inet6")
  468. end
  469.  
  470. function _M.bind(host, port, backlog)
  471. if host == "*" then host = "0.0.0.0" end
  472. local addrinfo, err = socket.dns.getaddrinfo(host);
  473. if not addrinfo then return nil, err end
  474. local sock, res
  475. err = "no info on address"
  476. for i, alt in base.ipairs(addrinfo) do
  477. if alt.family == "inet" then
  478. sock, err = socket.tcp4()
  479. else
  480. sock, err = socket.tcp6()
  481. end
  482. if not sock then return nil, err end
  483. sock:setoption("reuseaddr", true)
  484. res, err = sock:bind(alt.addr, port)
  485. if not res then
  486. sock:close()
  487. else
  488. res, err = sock:listen(backlog)
  489. if not res then
  490. sock:close()
  491. else
  492. return sock
  493. end
  494. end
  495. end
  496. return nil, err
  497. end
  498.  
  499. _M.try = _M.newtry()
  500.  
  501. function _M.choose(table)
  502. return function(name, opt1, opt2)
  503. if base.type(name) ~= "string" then
  504. name, opt1, opt2 = "default", name, opt1
  505. end
  506. local f = table[name or "nil"]
  507. if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
  508. else return f(opt1, opt2) end
  509. end
  510. end
  511.  
  512. -----------------------------------------------------------------------------
  513. -- Socket sources and sinks, conforming to LTN12
  514. -----------------------------------------------------------------------------
  515. -- create namespaces inside LuaSocket namespace
  516. local sourcet, sinkt = {}, {}
  517. _M.sourcet = sourcet
  518. _M.sinkt = sinkt
  519.  
  520. _M.BLOCKSIZE = 2048
  521.  
  522. sinkt["close-when-done"] = function(sock)
  523. return base.setmetatable({
  524. getfd = function() return sock:getfd() end,
  525. dirty = function() return sock:dirty() end
  526. }, {
  527. __call = function(self, chunk, err)
  528. if not chunk then
  529. sock:close()
  530. return 1
  531. else return sock:send(chunk) end
  532. end
  533. })
  534. end
  535.  
  536. sinkt["keep-open"] = function(sock)
  537. return base.setmetatable({
  538. getfd = function() return sock:getfd() end,
  539. dirty = function() return sock:dirty() end
  540. }, {
  541. __call = function(self, chunk, err)
  542. if chunk then return sock:send(chunk)
  543. else return 1 end
  544. end
  545. })
  546. end
  547.  
  548. sinkt["default"] = sinkt["keep-open"]
  549.  
  550. _M.sink = _M.choose(sinkt)
  551.  
  552. sourcet["by-length"] = function(sock, length)
  553. return base.setmetatable({
  554. getfd = function() return sock:getfd() end,
  555. dirty = function() return sock:dirty() end
  556. }, {
  557. __call = function()
  558. if length <= 0 then return nil end
  559. local size = math.min(socket.BLOCKSIZE, length)
  560. local chunk, err = sock:receive(size)
  561. if err then return nil, err end
  562. length = length - string.len(chunk)
  563. return chunk
  564. end
  565. })
  566. end
  567.  
  568. sourcet["until-closed"] = function(sock)
  569. local done
  570. return base.setmetatable({
  571. getfd = function() return sock:getfd() end,
  572. dirty = function() return sock:dirty() end
  573. }, {
  574. __call = function()
  575. if done then return nil end
  576. local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
  577. if not err then return chunk
  578. elseif err == "closed" then
  579. sock:close()
  580. done = 1
  581. return partial
  582. else return nil, err end
  583. end
  584. })
  585. end
  586.  
  587.  
  588. sourcet["default"] = sourcet["until-closed"]
  589.  
  590. _M.source = _M.choose(sourcet)
  591.  
  592. return _M
  593. -----------------------------------------------------------------------------
  594. -- MIME support for the Lua language.
  595. -- Author: Diego Nehab
  596. -- Conforming to RFCs 2045-2049
  597. -----------------------------------------------------------------------------
  598.  
  599. -----------------------------------------------------------------------------
  600. -- Declare module and import dependencies
  601. -----------------------------------------------------------------------------
  602. local base = _G
  603. local ltn12 = require("ltn12")
  604. local mime = require("mime.core")
  605. local io = require("io")
  606. local string = require("string")
  607. local _M = mime
  608.  
  609. -- encode, decode and wrap algorithm tables
  610. local encodet, decodet, wrapt = {},{},{}
  611.  
  612. _M.encodet = encodet
  613. _M.decodet = decodet
  614. _M.wrapt = wrapt
  615.  
  616. -- creates a function that chooses a filter by name from a given table
  617. local function choose(table)
  618. return function(name, opt1, opt2)
  619. if base.type(name) ~= "string" then
  620. name, opt1, opt2 = "default", name, opt1
  621. end
  622. local f = table[name or "nil"]
  623. if not f then
  624. base.error("unknown key (" .. base.tostring(name) .. ")", 3)
  625. else return f(opt1, opt2) end
  626. end
  627. end
  628.  
  629. -- define the encoding filters
  630. encodet['base64'] = function()
  631. return ltn12.filter.cycle(_M.b64, "")
  632. end
  633.  
  634. encodet['quoted-printable'] = function(mode)
  635. return ltn12.filter.cycle(_M.qp, "",
  636. (mode == "binary") and "=0D=0A" or "\r\n")
  637. end
  638.  
  639. -- define the decoding filters
  640. decodet['base64'] = function()
  641. return ltn12.filter.cycle(_M.unb64, "")
  642. end
  643.  
  644. decodet['quoted-printable'] = function()
  645. return ltn12.filter.cycle(_M.unqp, "")
  646. end
  647.  
  648. local function format(chunk)
  649. if chunk then
  650. if chunk == "" then return "''"
  651. else return string.len(chunk) end
  652. else return "nil" end
  653. end
  654.  
  655. -- define the line-wrap filters
  656. wrapt['text'] = function(length)
  657. length = length or 76
  658. return ltn12.filter.cycle(_M.wrp, length, length)
  659. end
  660. wrapt['base64'] = wrapt['text']
  661. wrapt['default'] = wrapt['text']
  662.  
  663. wrapt['quoted-printable'] = function()
  664. return ltn12.filter.cycle(_M.qpwrp, 76, 76)
  665. end
  666.  
  667. -- function that choose the encoding, decoding or wrap algorithm
  668. _M.encode = choose(encodet)
  669. _M.decode = choose(decodet)
  670. _M.wrap = choose(wrapt)
  671.  
  672. -- define the end-of-line normalization filter
  673. function _M.normalize(marker)
  674. return ltn12.filter.cycle(_M.eol, 0, marker)
  675. end
  676.  
  677. -- high level stuffing filter
  678. function _M.stuff()
  679. return ltn12.filter.cycle(_M.dot, 2)
  680. end
  681.  
  682. return _M local _M = {}
  683.  
  684. if module then
  685. mbox = _M
  686. end
  687.  
  688. function _M.split_message(message_s)
  689. local message = {}
  690. message_s = string.gsub(message_s, "\r\n", "\n")
  691. string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
  692. string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
  693. if not message.body then
  694. string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
  695. end
  696. if not message.headers and not message.body then
  697. message.headers = message_s
  698. end
  699. return message.headers or "", message.body or ""
  700. end
  701.  
  702. function _M.split_headers(headers_s)
  703. local headers = {}
  704. headers_s = string.gsub(headers_s, "\r\n", "\n")
  705. headers_s = string.gsub(headers_s, "\n[ ]+", " ")
  706. string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(headers, h) end)
  707. return headers
  708. end
  709.  
  710. function _M.parse_header(header_s)
  711. header_s = string.gsub(header_s, "\n[ ]+", " ")
  712. header_s = string.gsub(header_s, "\n+", "")
  713. local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
  714. return name, value
  715. end
  716.  
  717. function _M.parse_headers(headers_s)
  718. local headers_t = _M.split_headers(headers_s)
  719. local headers = {}
  720. for i = 1, #headers_t do
  721. local name, value = _M.parse_header(headers_t[i])
  722. if name then
  723. name = string.lower(name)
  724. if headers[name] then
  725. headers[name] = headers[name] .. ", " .. value
  726. else headers[name] = value end
  727. end
  728. end
  729. return headers
  730. end
  731.  
  732. function _M.parse_from(from)
  733. local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
  734. if not address then
  735. _, __, address = string.find(from, "%s*(.+)%s*")
  736. end
  737. name = name or ""
  738. address = address or ""
  739. if name == "" then name = address end
  740. name = string.gsub(name, '"', "")
  741. return name, address
  742. end
  743.  
  744. function _M.split_mbox(mbox_s)
  745. local mbox = {}
  746. mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
  747. local nj, i, j = 1, 1, 1
  748. while 1 do
  749. i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
  750. if not i then break end
  751. local message = string.sub(mbox_s, j, i-1)
  752. table.insert(mbox, message)
  753. j = nj+1
  754. end
  755. return mbox
  756. end
  757.  
  758. function _M.parse(mbox_s)
  759. local mbox = _M.split_mbox(mbox_s)
  760. for i = 1, #mbox do
  761. mbox[i] = _M.parse_message(mbox[i])
  762. end
  763. return mbox
  764. end
  765.  
  766. function _M.parse_message(message_s)
  767. local message = {}
  768. message.headers, message.body = _M.split_message(message_s)
  769. message.headers = _M.parse_headers(message.headers)
  770. return message
  771. end
  772.  
  773. return _M
  774. -----------------------------------------------------------------------------
  775. -- LTN12 - Filters, sources, sinks and pumps.
  776. -- LuaSocket toolkit.
  777. -- Author: Diego Nehab
  778. -----------------------------------------------------------------------------
  779.  
  780. -----------------------------------------------------------------------------
  781. -- Declare module
  782. -----------------------------------------------------------------------------
  783. local string = require("string")
  784. local table = require("table")
  785. local unpack = unpack or table.unpack
  786. local base = _G
  787. local _M = {}
  788. if module then -- heuristic for exporting a global package table
  789. ltn12 = _M
  790. end
  791. local filter,source,sink,pump = {},{},{},{}
  792.  
  793. _M.filter = filter
  794. _M.source = source
  795. _M.sink = sink
  796. _M.pump = pump
  797.  
  798. local unpack = unpack or table.unpack
  799. local select = base.select
  800.  
  801. -- 2048 seems to be better in windows...
  802. _M.BLOCKSIZE = 2048
  803. _M._VERSION = "LTN12 1.0.3"
  804.  
  805. -----------------------------------------------------------------------------
  806. -- Filter stuff
  807. -----------------------------------------------------------------------------
  808. -- returns a high level filter that cycles a low-level filter
  809. function filter.cycle(low, ctx, extra)
  810. base.assert(low)
  811. return function(chunk)
  812. local ret
  813. ret, ctx = low(ctx, chunk, extra)
  814. return ret
  815. end
  816. end
  817.  
  818. -- chains a bunch of filters together
  819. -- (thanks to Wim Couwenberg)
  820. function filter.chain(...)
  821. local arg = {...}
  822. local n = base.select('#',...)
  823. local top, index = 1, 1
  824. local retry = ""
  825. return function(chunk)
  826. retry = chunk and retry
  827. while true do
  828. if index == top then
  829. chunk = arg[index](chunk)
  830. if chunk == "" or top == n then return chunk
  831. elseif chunk then index = index + 1
  832. else
  833. top = top+1
  834. index = top
  835. end
  836. else
  837. chunk = arg[index](chunk or "")
  838. if chunk == "" then
  839. index = index - 1
  840. chunk = retry
  841. elseif chunk then
  842. if index == n then return chunk
  843. else index = index + 1 end
  844. else base.error("filter returned inappropriate nil") end
  845. end
  846. end
  847. end
  848. end
  849.  
  850. -----------------------------------------------------------------------------
  851. -- Source stuff
  852. -----------------------------------------------------------------------------
  853. -- create an empty source
  854. local function empty()
  855. return nil
  856. end
  857.  
  858. function source.empty()
  859. return empty
  860. end
  861.  
  862. -- returns a source that just outputs an error
  863. function source.error(err)
  864. return function()
  865. return nil, err
  866. end
  867. end
  868.  
  869. -- creates a file source
  870. function source.file(handle, io_err)
  871. if handle then
  872. return function()
  873. local chunk = handle:read(_M.BLOCKSIZE)
  874. if not chunk then handle:close() end
  875. return chunk
  876. end
  877. else return source.error(io_err or "unable to open file") end
  878. end
  879.  
  880. -- turns a fancy source into a simple source
  881. function source.simplify(src)
  882. base.assert(src)
  883. return function()
  884. local chunk, err_or_new = src()
  885. src = err_or_new or src
  886. if not chunk then return nil, err_or_new
  887. else return chunk end
  888. end
  889. end
  890.  
  891. -- creates string source
  892. function source.string(s)
  893. if s then
  894. local i = 1
  895. return function()
  896. local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
  897. i = i + _M.BLOCKSIZE
  898. if chunk ~= "" then return chunk
  899. else return nil end
  900. end
  901. else return source.empty() end
  902. end
  903.  
  904. -- creates rewindable source
  905. function source.rewind(src)
  906. base.assert(src)
  907. local t = {}
  908. return function(chunk)
  909. if not chunk then
  910. chunk = table.remove(t)
  911. if not chunk then return src()
  912. else return chunk end
  913. else
  914. table.insert(t, chunk)
  915. end
  916. end
  917. end
  918.  
  919. -- chains a source with one or several filter(s)
  920. function source.chain(src, f, ...)
  921. if ... then f=filter.chain(f, ...) end
  922. base.assert(src and f)
  923. local last_in, last_out = "", ""
  924. local state = "feeding"
  925. local err
  926. return function()
  927. if not last_out then
  928. base.error('source is empty!', 2)
  929. end
  930. while true do
  931. if state == "feeding" then
  932. last_in, err = src()
  933. if err then return nil, err end
  934. last_out = f(last_in)
  935. if not last_out then
  936. if last_in then
  937. base.error('filter returned inappropriate nil')
  938. else
  939. return nil
  940. end
  941. elseif last_out ~= "" then
  942. state = "eating"
  943. if last_in then last_in = "" end
  944. return last_out
  945. end
  946. else
  947. last_out = f(last_in)
  948. if last_out == "" then
  949. if last_in == "" then
  950. state = "feeding"
  951. else
  952. base.error('filter returned ""')
  953. end
  954. elseif not last_out then
  955. if last_in then
  956. base.error('filter returned inappropriate nil')
  957. else
  958. return nil
  959. end
  960. else
  961. return last_out
  962. end
  963. end
  964. end
  965. end
  966. end
  967.  
  968. -- creates a source that produces contents of several sources, one after the
  969. -- other, as if they were concatenated
  970. -- (thanks to Wim Couwenberg)
  971. function source.cat(...)
  972. local arg = {...}
  973. local src = table.remove(arg, 1)
  974. return function()
  975. while src do
  976. local chunk, err = src()
  977. if chunk then return chunk end
  978. if err then return nil, err end
  979. src = table.remove(arg, 1)
  980. end
  981. end
  982. end
  983.  
  984. -----------------------------------------------------------------------------
  985. -- Sink stuff
  986. -----------------------------------------------------------------------------
  987. -- creates a sink that stores into a table
  988. function sink.table(t)
  989. t = t or {}
  990. local f = function(chunk, err)
  991. if chunk then table.insert(t, chunk) end
  992. return 1
  993. end
  994. return f, t
  995. end
  996.  
  997. -- turns a fancy sink into a simple sink
  998. function sink.simplify(snk)
  999. base.assert(snk)
  1000. return function(chunk, err)
  1001. local ret, err_or_new = snk(chunk, err)
  1002. if not ret then return nil, err_or_new end
  1003. snk = err_or_new or snk
  1004. return 1
  1005. end
  1006. end
  1007.  
  1008. -- creates a file sink
  1009. function sink.file(handle, io_err)
  1010. if handle then
  1011. return function(chunk, err)
  1012. if not chunk then
  1013. handle:close()
  1014. return 1
  1015. else return handle:write(chunk) end
  1016. end
  1017. else return sink.error(io_err or "unable to open file") end
  1018. end
  1019.  
  1020. -- creates a sink that discards data
  1021. local function null()
  1022. return 1
  1023. end
  1024.  
  1025. function sink.null()
  1026. return null
  1027. end
  1028.  
  1029. -- creates a sink that just returns an error
  1030. function sink.error(err)
  1031. return function()
  1032. return nil, err
  1033. end
  1034. end
  1035.  
  1036. -- chains a sink with one or several filter(s)
  1037. function sink.chain(f, snk, ...)
  1038. if ... then
  1039. local args = { f, snk, ... }
  1040. snk = table.remove(args, #args)
  1041. f = filter.chain(unpack(args))
  1042. end
  1043. base.assert(f and snk)
  1044. return function(chunk, err)
  1045. if chunk ~= "" then
  1046. local filtered = f(chunk)
  1047. local done = chunk and ""
  1048. while true do
  1049. local ret, snkerr = snk(filtered, err)
  1050. if not ret then return nil, snkerr end
  1051. if filtered == done then return 1 end
  1052. filtered = f(done)
  1053. end
  1054. else return 1 end
  1055. end
  1056. end
  1057.  
  1058. -----------------------------------------------------------------------------
  1059. -- Pump stuff
  1060. -----------------------------------------------------------------------------
  1061. -- pumps one chunk from the source to the sink
  1062. function pump.step(src, snk)
  1063. local chunk, src_err = src()
  1064. local ret, snk_err = snk(chunk, src_err)
  1065. if chunk and ret then return 1
  1066. else return nil, src_err or snk_err end
  1067. end
  1068.  
  1069. -- pumps all data from a source to a sink, using a step function
  1070. function pump.all(src, snk, step)
  1071. base.assert(src and snk)
  1072. step = step or pump.step
  1073. while true do
  1074. local ret, err = step(src, snk)
  1075. if not ret then
  1076. if err then return nil, err
  1077. else return 1 end
  1078. end
  1079. end
  1080. end
  1081.  
  1082. return _M
  1083. -----------------------------------------------------------------------------
  1084. -- HTTP/1.1 client support for the Lua language.
  1085. -- LuaSocket toolkit.
  1086. -- Author: Diego Nehab
  1087. -----------------------------------------------------------------------------
  1088.  
  1089. -----------------------------------------------------------------------------
  1090. -- Declare module and import dependencies
  1091. -------------------------------------------------------------------------------
  1092. local socket = require("socket")
  1093. local url = require("socket.url")
  1094. local ltn12 = require("ltn12")
  1095. local mime = require("mime")
  1096. local string = require("string")
  1097. local headers = require("socket.headers")
  1098. local base = _G
  1099. local table = require("table")
  1100. socket.http = {}
  1101. local _M = socket.http
  1102.  
  1103. -----------------------------------------------------------------------------
  1104. -- Program constants
  1105. -----------------------------------------------------------------------------
  1106. -- connection timeout in seconds
  1107. _M.TIMEOUT = 60
  1108. -- user agent field sent in request
  1109. _M.USERAGENT = socket._VERSION
  1110.  
  1111. -- supported schemes
  1112. local SCHEMES = { ["http"] = true }
  1113. -- default port for document retrieval
  1114. local PORT = 80
  1115.  
  1116. -----------------------------------------------------------------------------
  1117. -- Reads MIME headers from a connection, unfolding where needed
  1118. -----------------------------------------------------------------------------
  1119. local function receiveheaders(sock, headers)
  1120. local line, name, value, err
  1121. headers = headers or {}
  1122. -- get first line
  1123. line, err = sock:receive()
  1124. if err then return nil, err end
  1125. -- headers go until a blank line is found
  1126. while line ~= "" do
  1127. -- get field-name and value
  1128. name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
  1129. if not (name and value) then return nil, "malformed reponse headers" end
  1130. name = string.lower(name)
  1131. -- get next line (value might be folded)
  1132. line, err = sock:receive()
  1133. if err then return nil, err end
  1134. -- unfold any folded values
  1135. while string.find(line, "^%s") do
  1136. value = value .. line
  1137. line = sock:receive()
  1138. if err then return nil, err end
  1139. end
  1140. -- save pair in table
  1141. if headers[name] then headers[name] = headers[name] .. ", " .. value
  1142. else headers[name] = value end
  1143. end
  1144. return headers
  1145. end
  1146.  
  1147. -----------------------------------------------------------------------------
  1148. -- Extra sources and sinks
  1149. -----------------------------------------------------------------------------
  1150. socket.sourcet["http-chunked"] = function(sock, headers)
  1151. return base.setmetatable({
  1152. getfd = function() return sock:getfd() end,
  1153. dirty = function() return sock:dirty() end
  1154. }, {
  1155. __call = function()
  1156. -- get chunk size, skip extention
  1157. local line, err = sock:receive()
  1158. if err then return nil, err end
  1159. local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
  1160. if not size then return nil, "invalid chunk size" end
  1161. -- was it the last chunk?
  1162. if size > 0 then
  1163. -- if not, get chunk and skip terminating CRLF
  1164. local chunk, err, part = sock:receive(size)
  1165. if chunk then sock:receive() end
  1166. return chunk, err
  1167. else
  1168. -- if it was, read trailers into headers table
  1169. headers, err = receiveheaders(sock, headers)
  1170. if not headers then return nil, err end
  1171. end
  1172. end
  1173. })
  1174. end
  1175.  
  1176. socket.sinkt["http-chunked"] = function(sock)
  1177. return base.setmetatable({
  1178. getfd = function() return sock:getfd() end,
  1179. dirty = function() return sock:dirty() end
  1180. }, {
  1181. __call = function(self, chunk, err)
  1182. if not chunk then return sock:send("0\r\n\r\n") end
  1183. local size = string.format("%X\r\n", string.len(chunk))
  1184. return sock:send(size .. chunk .. "\r\n")
  1185. end
  1186. })
  1187. end
  1188.  
  1189. -----------------------------------------------------------------------------
  1190. -- Low level HTTP API
  1191. -----------------------------------------------------------------------------
  1192. local metat = { __index = {} }
  1193.  
  1194. function _M.open(host, port, create)
  1195. -- create socket with user connect function, or with default
  1196. local c = socket.try((create or socket.tcp)())
  1197. local h = base.setmetatable({ c = c }, metat)
  1198. -- create finalized try
  1199. h.try = socket.newtry(function() h:close() end)
  1200. -- set timeout before connecting
  1201. h.try(c:settimeout(_M.TIMEOUT))
  1202. h.try(c:connect(host, port or PORT))
  1203. -- here everything worked
  1204. return h
  1205. end
  1206.  
  1207. function metat.__index:sendrequestline(method, uri)
  1208. local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
  1209. return self.try(self.c:send(reqline))
  1210. end
  1211.  
  1212. function metat.__index:sendheaders(tosend)
  1213. local canonic = headers.canonic
  1214. local h = "\r\n"
  1215. for f, v in base.pairs(tosend) do
  1216. h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
  1217. end
  1218. self.try(self.c:send(h))
  1219. return 1
  1220. end
  1221.  
  1222. function metat.__index:sendbody(headers, source, step)
  1223. source = source or ltn12.source.empty()
  1224. step = step or ltn12.pump.step
  1225. -- if we don't know the size in advance, send chunked and hope for the best
  1226. local mode = "http-chunked"
  1227. if headers["content-length"] then mode = "keep-open" end
  1228. return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
  1229. end
  1230.  
  1231. function metat.__index:receivestatusline()
  1232. local status = self.try(self.c:receive(5))
  1233. -- identify HTTP/0.9 responses, which do not contain a status line
  1234. -- this is just a heuristic, but is what the RFC recommends
  1235. if status ~= "HTTP/" then return nil, status end
  1236. -- otherwise proceed reading a status line
  1237. status = self.try(self.c:receive("*l", status))
  1238. local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
  1239. return self.try(base.tonumber(code), status)
  1240. end
  1241.  
  1242. function metat.__index:receiveheaders()
  1243. return self.try(receiveheaders(self.c))
  1244. end
  1245.  
  1246. function metat.__index:receivebody(headers, sink, step)
  1247. sink = sink or ltn12.sink.null()
  1248. step = step or ltn12.pump.step
  1249. local length = base.tonumber(headers["content-length"])
  1250. local t = headers["transfer-encoding"] -- shortcut
  1251. local mode = "default" -- connection close
  1252. if t and t ~= "identity" then mode = "http-chunked"
  1253. elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
  1254. return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
  1255. sink, step))
  1256. end
  1257.  
  1258. function metat.__index:receive09body(status, sink, step)
  1259. local source = ltn12.source.rewind(socket.source("until-closed", self.c))
  1260. source(status)
  1261. return self.try(ltn12.pump.all(source, sink, step))
  1262. end
  1263.  
  1264. function metat.__index:close()
  1265. return self.c:close()
  1266. end
  1267.  
  1268. -----------------------------------------------------------------------------
  1269. -- High level HTTP API
  1270. -----------------------------------------------------------------------------
  1271. local function adjusturi(reqt)
  1272. local u = reqt
  1273. -- if there is a proxy, we need the full url. otherwise, just a part.
  1274. if not reqt.proxy and not _M.PROXY then
  1275. u = {
  1276. path = socket.try(reqt.path, "invalid path 'nil'"),
  1277. params = reqt.params,
  1278. query = reqt.query,
  1279. fragment = reqt.fragment
  1280. }
  1281. end
  1282. return url.build(u)
  1283. end
  1284.  
  1285. local function adjustproxy(reqt)
  1286. local proxy = reqt.proxy or _M.PROXY
  1287. if proxy then
  1288. proxy = url.parse(proxy)
  1289. return proxy.host, proxy.port or 3128
  1290. else
  1291. return reqt.host, reqt.port
  1292. end
  1293. end
  1294.  
  1295. local function adjustheaders(reqt)
  1296. -- default headers
  1297. local host = string.gsub(reqt.authority, "^.-@", "")
  1298. local lower = {
  1299. ["user-agent"] = _M.USERAGENT,
  1300. ["host"] = host,
  1301. ["connection"] = "close, TE",
  1302. ["te"] = "trailers"
  1303. }
  1304. -- if we have authentication information, pass it along
  1305. if reqt.user and reqt.password then
  1306. lower["authorization"] =
  1307. "Basic " .. (mime.b64(reqt.user .. ":" ..
  1308. url.unescape(reqt.password)))
  1309. end
  1310. -- if we have proxy authentication information, pass it along
  1311. local proxy = reqt.proxy or _M.PROXY
  1312. if proxy then
  1313. proxy = url.parse(proxy)
  1314. if proxy.user and proxy.password then
  1315. lower["proxy-authorization"] =
  1316. "Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password))
  1317. end
  1318. end
  1319. -- override with user headers
  1320. for i,v in base.pairs(reqt.headers or lower) do
  1321. lower[string.lower(i)] = v
  1322. end
  1323. return lower
  1324. end
  1325.  
  1326. -- default url parts
  1327. local default = {
  1328. host = "",
  1329. port = PORT,
  1330. path ="/",
  1331. scheme = "http"
  1332. }
  1333.  
  1334. local function adjustrequest(reqt)
  1335. -- parse url if provided
  1336. local nreqt = reqt.url and url.parse(reqt.url, default) or {}
  1337. -- explicit components override url
  1338. for i,v in base.pairs(reqt) do nreqt[i] = v end
  1339. if nreqt.port == "" then nreqt.port = PORT end
  1340. if not (nreqt.host and nreqt.host ~= "") then
  1341. socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
  1342. end
  1343. -- compute uri if user hasn't overriden
  1344. nreqt.uri = reqt.uri or adjusturi(nreqt)
  1345. -- adjust headers in request
  1346. nreqt.headers = adjustheaders(nreqt)
  1347. -- ajust host and port if there is a proxy
  1348. nreqt.host, nreqt.port = adjustproxy(nreqt)
  1349. return nreqt
  1350. end
  1351.  
  1352. local function shouldredirect(reqt, code, headers)
  1353. local location = headers.location
  1354. if not location then return false end
  1355. location = string.gsub(location, "%s", "")
  1356. if location == "" then return false end
  1357. local scheme = string.match(location, "^([%w][%w%+%-%.]*)%:")
  1358. if scheme and not SCHEMES[scheme] then return false end
  1359. return (reqt.redirect ~= false) and
  1360. (code == 301 or code == 302 or code == 303 or code == 307) and
  1361. (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
  1362. and (not reqt.nredirects or reqt.nredirects < 5)
  1363. end
  1364.  
  1365. local function shouldreceivebody(reqt, code)
  1366. if reqt.method == "HEAD" then return nil end
  1367. if code == 204 or code == 304 then return nil end
  1368. if code >= 100 and code < 200 then return nil end
  1369. return 1
  1370. end
  1371.  
  1372. -- forward declarations
  1373. local trequest, tredirect
  1374.  
  1375. --[[local]] function tredirect(reqt, location)
  1376. local result, code, headers, status = trequest {
  1377. -- the RFC says the redirect URL has to be absolute, but some
  1378. -- servers do not respect that
  1379. url = url.absolute(reqt.url, location),
  1380. source = reqt.source,
  1381. sink = reqt.sink,
  1382. headers = reqt.headers,
  1383. proxy = reqt.proxy,
  1384. nredirects = (reqt.nredirects or 0) + 1,
  1385. create = reqt.create
  1386. }
  1387. -- pass location header back as a hint we redirected
  1388. headers = headers or {}
  1389. headers.location = headers.location or location
  1390. return result, code, headers, status
  1391. end
  1392.  
  1393. --[[local]] function trequest(reqt)
  1394. -- we loop until we get what we want, or
  1395. -- until we are sure there is no way to get it
  1396. local nreqt = adjustrequest(reqt)
  1397. local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
  1398. -- send request line and headers
  1399. h:sendrequestline(nreqt.method, nreqt.uri)
  1400. h:sendheaders(nreqt.headers)
  1401. -- if there is a body, send it
  1402. if nreqt.source then
  1403. h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
  1404. end
  1405. local code, status = h:receivestatusline()
  1406. -- if it is an HTTP/0.9 server, simply get the body and we are done
  1407. if not code then
  1408. h:receive09body(status, nreqt.sink, nreqt.step)
  1409. return 1, 200
  1410. end
  1411. local headers
  1412. -- ignore any 100-continue messages
  1413. while code == 100 do
  1414. headers = h:receiveheaders()
  1415. code, status = h:receivestatusline()
  1416. end
  1417. headers = h:receiveheaders()
  1418. -- at this point we should have a honest reply from the server
  1419. -- we can't redirect if we already used the source, so we report the error
  1420. if shouldredirect(nreqt, code, headers) and not nreqt.source then
  1421. h:close()
  1422. return tredirect(reqt, headers.location)
  1423. end
  1424. -- here we are finally done
  1425. if shouldreceivebody(nreqt, code) then
  1426. h:receivebody(headers, nreqt.sink, nreqt.step)
  1427. end
  1428. h:close()
  1429. return 1, code, headers, status
  1430. end
  1431.  
  1432. -- turns an url and a body into a generic request
  1433. local function genericform(u, b)
  1434. local t = {}
  1435. local reqt = {
  1436. url = u,
  1437. sink = ltn12.sink.table(t),
  1438. target = t
  1439. }
  1440. if b then
  1441. reqt.source = ltn12.source.string(b)
  1442. reqt.headers = {
  1443. ["content-length"] = string.len(b),
  1444. ["content-type"] = "application/x-www-form-urlencoded"
  1445. }
  1446. reqt.method = "POST"
  1447. end
  1448. return reqt
  1449. end
  1450.  
  1451. _M.genericform = genericform
  1452.  
  1453. local function srequest(u, b)
  1454. local reqt = genericform(u, b)
  1455. local _, code, headers, status = trequest(reqt)
  1456. return table.concat(reqt.target), code, headers, status
  1457. end
  1458.  
  1459. _M.request = socket.protect(function(reqt, body)
  1460. if base.type(reqt) == "string" then return srequest(reqt, body)
  1461. else return trequest(reqt) end
  1462. end)
  1463.  
  1464. return _M
  1465. -----------------------------------------------------------------------------
  1466. -- Canonic header field capitalization
  1467. -- LuaSocket toolkit.
  1468. -- Author: Diego Nehab
  1469. -----------------------------------------------------------------------------
  1470. local socket = require("socket")
  1471. socket.headers = {}
  1472. local _M = socket.headers
  1473.  
  1474. _M.canonic = {
  1475. ["accept"] = "Accept",
  1476. ["accept-charset"] = "Accept-Charset",
  1477. ["accept-encoding"] = "Accept-Encoding",
  1478. ["accept-language"] = "Accept-Language",
  1479. ["accept-ranges"] = "Accept-Ranges",
  1480. ["action"] = "Action",
  1481. ["alternate-recipient"] = "Alternate-Recipient",
  1482. ["age"] = "Age",
  1483. ["allow"] = "Allow",
  1484. ["arrival-date"] = "Arrival-Date",
  1485. ["authorization"] = "Authorization",
  1486. ["bcc"] = "Bcc",
  1487. ["cache-control"] = "Cache-Control",
  1488. ["cc"] = "Cc",
  1489. ["comments"] = "Comments",
  1490. ["connection"] = "Connection",
  1491. ["content-description"] = "Content-Description",
  1492. ["content-disposition"] = "Content-Disposition",
  1493. ["content-encoding"] = "Content-Encoding",
  1494. ["content-id"] = "Content-ID",
  1495. ["content-language"] = "Content-Language",
  1496. ["content-length"] = "Content-Length",
  1497. ["content-location"] = "Content-Location",
  1498. ["content-md5"] = "Content-MD5",
  1499. ["content-range"] = "Content-Range",
  1500. ["content-transfer-encoding"] = "Content-Transfer-Encoding",
  1501. ["content-type"] = "Content-Type",
  1502. ["cookie"] = "Cookie",
  1503. ["date"] = "Date",
  1504. ["diagnostic-code"] = "Diagnostic-Code",
  1505. ["dsn-gateway"] = "DSN-Gateway",
  1506. ["etag"] = "ETag",
  1507. ["expect"] = "Expect",
  1508. ["expires"] = "Expires",
  1509. ["final-log-id"] = "Final-Log-ID",
  1510. ["final-recipient"] = "Final-Recipient",
  1511. ["from"] = "From",
  1512. ["host"] = "Host",
  1513. ["if-match"] = "If-Match",
  1514. ["if-modified-since"] = "If-Modified-Since",
  1515. ["if-none-match"] = "If-None-Match",
  1516. ["if-range"] = "If-Range",
  1517. ["if-unmodified-since"] = "If-Unmodified-Since",
  1518. ["in-reply-to"] = "In-Reply-To",
  1519. ["keywords"] = "Keywords",
  1520. ["last-attempt-date"] = "Last-Attempt-Date",
  1521. ["last-modified"] = "Last-Modified",
  1522. ["location"] = "Location",
  1523. ["max-forwards"] = "Max-Forwards",
  1524. ["message-id"] = "Message-ID",
  1525. ["mime-version"] = "MIME-Version",
  1526. ["original-envelope-id"] = "Original-Envelope-ID",
  1527. ["original-recipient"] = "Original-Recipient",
  1528. ["pragma"] = "Pragma",
  1529. ["proxy-authenticate"] = "Proxy-Authenticate",
  1530. ["proxy-authorization"] = "Proxy-Authorization",
  1531. ["range"] = "Range",
  1532. ["received"] = "Received",
  1533. ["received-from-mta"] = "Received-From-MTA",
  1534. ["references"] = "References",
  1535. ["referer"] = "Referer",
  1536. ["remote-mta"] = "Remote-MTA",
  1537. ["reply-to"] = "Reply-To",
  1538. ["reporting-mta"] = "Reporting-MTA",
  1539. ["resent-bcc"] = "Resent-Bcc",
  1540. ["resent-cc"] = "Resent-Cc",
  1541. ["resent-date"] = "Resent-Date",
  1542. ["resent-from"] = "Resent-From",
  1543. ["resent-message-id"] = "Resent-Message-ID",
  1544. ["resent-reply-to"] = "Resent-Reply-To",
  1545. ["resent-sender"] = "Resent-Sender",
  1546. ["resent-to"] = "Resent-To",
  1547. ["retry-after"] = "Retry-After",
  1548. ["return-path"] = "Return-Path",
  1549. ["sender"] = "Sender",
  1550. ["server"] = "Server",
  1551. ["smtp-remote-recipient"] = "SMTP-Remote-Recipient",
  1552. ["status"] = "Status",
  1553. ["subject"] = "Subject",
  1554. ["te"] = "TE",
  1555. ["to"] = "To",
  1556. ["trailer"] = "Trailer",
  1557. ["transfer-encoding"] = "Transfer-Encoding",
  1558. ["upgrade"] = "Upgrade",
  1559. ["user-agent"] = "User-Agent",
  1560. ["vary"] = "Vary",
  1561. ["via"] = "Via",
  1562. ["warning"] = "Warning",
  1563. ["will-retry-until"] = "Will-Retry-Until",
  1564. ["www-authenticate"] = "WWW-Authenticate",
  1565. ["x-mailer"] = "X-Mailer",
  1566. }
  1567.  
  1568. return
Add Comment
Please, Sign In to add comment