源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
12 KiB

  1. -- -----------------------------------------------------------------------------
  2. -- -- URI parsing, composition and relative URL resolution
  3. -- -- LuaSocket toolkit.
  4. -- -- Author: Diego Nehab
  5. -- -----------------------------------------------------------------------------
  6. -- -----------------------------------------------------------------------------
  7. -- -- Declare module
  8. -- -----------------------------------------------------------------------------
  9. -- local string = require("string")
  10. -- local base = _G
  11. -- local table = require("table")
  12. -- local socket = require("socket")
  13. -- socket.url = {}
  14. -- local _M = socket.url
  15. -- -----------------------------------------------------------------------------
  16. -- -- Module version
  17. -- -----------------------------------------------------------------------------
  18. -- _M._VERSION = "URL 1.0.3"
  19. -- -----------------------------------------------------------------------------
  20. -- -- Encodes a string into its escaped hexadecimal representation
  21. -- -- Input
  22. -- -- s: binary string to be encoded
  23. -- -- Returns
  24. -- -- escaped representation of string binary
  25. -- -----------------------------------------------------------------------------
  26. -- function _M.escape(s)
  27. -- return (string.gsub(s, "([^A-Za-z0-9_])", function(c)
  28. -- return string.format("%%%02x", string.byte(c))
  29. -- end))
  30. -- end
  31. -- -----------------------------------------------------------------------------
  32. -- -- Protects a path segment, to prevent it from interfering with the
  33. -- -- url parsing.
  34. -- -- Input
  35. -- -- s: binary string to be encoded
  36. -- -- Returns
  37. -- -- escaped representation of string binary
  38. -- -----------------------------------------------------------------------------
  39. -- local function make_set(t)
  40. -- local s = {}
  41. -- for i,v in base.ipairs(t) do
  42. -- s[t[i]] = 1
  43. -- end
  44. -- return s
  45. -- end
  46. -- -- these are allowed withing a path segment, along with alphanum
  47. -- -- other characters must be escaped
  48. -- local segment_set = make_set {
  49. -- "-", "_", ".", "!", "~", "*", "'", "(",
  50. -- ")", ":", "@", "&", "=", "+", "$", ",",
  51. -- }
  52. -- local function protect_segment(s)
  53. -- return string.gsub(s, "([^A-Za-z0-9_])", function (c)
  54. -- if segment_set[c] then return c
  55. -- else return string.format("%%%02x", string.byte(c)) end
  56. -- end)
  57. -- end
  58. -- -----------------------------------------------------------------------------
  59. -- -- Encodes a string into its escaped hexadecimal representation
  60. -- -- Input
  61. -- -- s: binary string to be encoded
  62. -- -- Returns
  63. -- -- escaped representation of string binary
  64. -- -----------------------------------------------------------------------------
  65. -- function _M.unescape(s)
  66. -- return (string.gsub(s, "%%(%x%x)", function(hex)
  67. -- return string.char(base.tonumber(hex, 16))
  68. -- end))
  69. -- end
  70. -- -----------------------------------------------------------------------------
  71. -- -- Builds a path from a base path and a relative path
  72. -- -- Input
  73. -- -- base_path
  74. -- -- relative_path
  75. -- -- Returns
  76. -- -- corresponding absolute path
  77. -- -----------------------------------------------------------------------------
  78. -- local function absolute_path(base_path, relative_path)
  79. -- if string.sub(relative_path, 1, 1) == "/" then return relative_path end
  80. -- local path = string.gsub(base_path, "[^/]*$", "")
  81. -- path = path .. relative_path
  82. -- path = string.gsub(path, "([^/]*%./)", function (s)
  83. -- if s ~= "./" then return s else return "" end
  84. -- end)
  85. -- path = string.gsub(path, "/%.$", "/")
  86. -- local reduced
  87. -- while reduced ~= path do
  88. -- reduced = path
  89. -- path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
  90. -- if s ~= "../../" then return "" else return s end
  91. -- end)
  92. -- end
  93. -- path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
  94. -- if s ~= "../.." then return "" else return s end
  95. -- end)
  96. -- return path
  97. -- end
  98. -- -----------------------------------------------------------------------------
  99. -- -- Parses a url and returns a table with all its parts according to RFC 2396
  100. -- -- The following grammar describes the names given to the URL parts
  101. -- -- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
  102. -- -- <authority> ::= <userinfo>@<host>:<port>
  103. -- -- <userinfo> ::= <user>[:<password>]
  104. -- -- <path> :: = {<segment>/}<segment>
  105. -- -- Input
  106. -- -- url: uniform resource locator of request
  107. -- -- default: table with default values for each field
  108. -- -- Returns
  109. -- -- table with the following fields, where RFC naming conventions have
  110. -- -- been preserved:
  111. -- -- scheme, authority, userinfo, user, password, host, port,
  112. -- -- path, params, query, fragment
  113. -- -- Obs:
  114. -- -- the leading '/' in {/<path>} is considered part of <path>
  115. -- -----------------------------------------------------------------------------
  116. -- function _M.parse(url, default)
  117. -- -- initialize default parameters
  118. -- local parsed = {}
  119. -- for i,v in base.pairs(default or parsed) do parsed[i] = v end
  120. -- -- empty url is parsed to nil
  121. -- if not url or url == "" then return nil, "invalid url" end
  122. -- -- remove whitespace
  123. -- -- url = string.gsub(url, "%s", "")
  124. -- -- get fragment
  125. -- url = string.gsub(url, "#(.*)$", function(f)
  126. -- parsed.fragment = f
  127. -- return ""
  128. -- end)
  129. -- -- get scheme
  130. -- url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
  131. -- function(s) parsed.scheme = s; return "" end)
  132. -- -- get authority
  133. -- url = string.gsub(url, "^//([^/]*)", function(n)
  134. -- parsed.authority = n
  135. -- return ""
  136. -- end)
  137. -- -- get query string
  138. -- url = string.gsub(url, "%?(.*)", function(q)
  139. -- parsed.query = q
  140. -- return ""
  141. -- end)
  142. -- -- get params
  143. -- url = string.gsub(url, "%;(.*)", function(p)
  144. -- parsed.params = p
  145. -- return ""
  146. -- end)
  147. -- -- path is whatever was left
  148. -- if url ~= "" then parsed.path = url end
  149. -- local authority = parsed.authority
  150. -- if not authority then return parsed end
  151. -- authority = string.gsub(authority,"^([^@]*)@",
  152. -- function(u) parsed.userinfo = u; return "" end)
  153. -- authority = string.gsub(authority, ":([^:%]]*)$",
  154. -- function(p) parsed.port = p; return "" end)
  155. -- if authority ~= "" then
  156. -- -- IPv6?
  157. -- parsed.host = string.match(authority, "^%[(.+)%]$") or authority
  158. -- end
  159. -- local userinfo = parsed.userinfo
  160. -- if not userinfo then return parsed end
  161. -- userinfo = string.gsub(userinfo, ":([^:]*)$",
  162. -- function(p) parsed.password = p; return "" end)
  163. -- parsed.user = userinfo
  164. -- return parsed
  165. -- end
  166. -- -----------------------------------------------------------------------------
  167. -- -- Rebuilds a parsed URL from its components.
  168. -- -- Components are protected if any reserved or unallowed characters are found
  169. -- -- Input
  170. -- -- parsed: parsed URL, as returned by parse
  171. -- -- Returns
  172. -- -- a stringing with the corresponding URL
  173. -- -----------------------------------------------------------------------------
  174. -- function _M.build(parsed)
  175. -- local ppath = _M.parse_path(parsed.path or "")
  176. -- local url = _M.build_path(ppath)
  177. -- if parsed.params then url = url .. ";" .. parsed.params end
  178. -- if parsed.query then url = url .. "?" .. parsed.query end
  179. -- local authority = parsed.authority
  180. -- if parsed.host then
  181. -- authority = parsed.host
  182. -- if string.find(authority, ":") then -- IPv6?
  183. -- authority = "[" .. authority .. "]"
  184. -- end
  185. -- if parsed.port then authority = authority .. ":" .. parsed.port end
  186. -- local userinfo = parsed.userinfo
  187. -- if parsed.user then
  188. -- userinfo = parsed.user
  189. -- if parsed.password then
  190. -- userinfo = userinfo .. ":" .. parsed.password
  191. -- end
  192. -- end
  193. -- if userinfo then authority = userinfo .. "@" .. authority end
  194. -- end
  195. -- if authority then url = "//" .. authority .. url end
  196. -- if parsed.scheme then url = parsed.scheme .. ":" .. url end
  197. -- if parsed.fragment then url = url .. "#" .. parsed.fragment end
  198. -- -- url = string.gsub(url, "%s", "")
  199. -- return url
  200. -- end
  201. -- -----------------------------------------------------------------------------
  202. -- -- Builds a absolute URL from a base and a relative URL according to RFC 2396
  203. -- -- Input
  204. -- -- base_url
  205. -- -- relative_url
  206. -- -- Returns
  207. -- -- corresponding absolute url
  208. -- -----------------------------------------------------------------------------
  209. -- function _M.absolute(base_url, relative_url)
  210. -- local base_parsed
  211. -- if base.type(base_url) == "table" then
  212. -- base_parsed = base_url
  213. -- base_url = _M.build(base_parsed)
  214. -- else
  215. -- base_parsed = _M.parse(base_url)
  216. -- end
  217. -- local relative_parsed = _M.parse(relative_url)
  218. -- if not base_parsed then return relative_url
  219. -- elseif not relative_parsed then return base_url
  220. -- elseif relative_parsed.scheme then return relative_url
  221. -- else
  222. -- relative_parsed.scheme = base_parsed.scheme
  223. -- if not relative_parsed.authority then
  224. -- relative_parsed.authority = base_parsed.authority
  225. -- if not relative_parsed.path then
  226. -- relative_parsed.path = base_parsed.path
  227. -- if not relative_parsed.params then
  228. -- relative_parsed.params = base_parsed.params
  229. -- if not relative_parsed.query then
  230. -- relative_parsed.query = base_parsed.query
  231. -- end
  232. -- end
  233. -- else
  234. -- relative_parsed.path = absolute_path(base_parsed.path or "",
  235. -- relative_parsed.path)
  236. -- end
  237. -- end
  238. -- return _M.build(relative_parsed)
  239. -- end
  240. -- end
  241. -- -----------------------------------------------------------------------------
  242. -- -- Breaks a path into its segments, unescaping the segments
  243. -- -- Input
  244. -- -- path
  245. -- -- Returns
  246. -- -- segment: a table with one entry per segment
  247. -- -----------------------------------------------------------------------------
  248. -- function _M.parse_path(path)
  249. -- local parsed = {}
  250. -- path = path or ""
  251. -- --path = string.gsub(path, "%s", "")
  252. -- string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
  253. -- for i = 1, #parsed do
  254. -- parsed[i] = _M.unescape(parsed[i])
  255. -- end
  256. -- if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
  257. -- if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
  258. -- return parsed
  259. -- end
  260. -- -----------------------------------------------------------------------------
  261. -- -- Builds a path component from its segments, escaping protected characters.
  262. -- -- Input
  263. -- -- parsed: path segments
  264. -- -- unsafe: if true, segments are not protected before path is built
  265. -- -- Returns
  266. -- -- path: corresponding path stringing
  267. -- -----------------------------------------------------------------------------
  268. -- function _M.build_path(parsed, unsafe)
  269. -- local path = ""
  270. -- local n = #parsed
  271. -- if unsafe then
  272. -- for i = 1, n-1 do
  273. -- path = path .. parsed[i]
  274. -- path = path .. "/"
  275. -- end
  276. -- if n > 0 then
  277. -- path = path .. parsed[n]
  278. -- if parsed.is_directory then path = path .. "/" end
  279. -- end
  280. -- else
  281. -- for i = 1, n-1 do
  282. -- path = path .. protect_segment(parsed[i])
  283. -- path = path .. "/"
  284. -- end
  285. -- if n > 0 then
  286. -- path = path .. protect_segment(parsed[n])
  287. -- if parsed.is_directory then path = path .. "/" end
  288. -- end
  289. -- end
  290. -- if parsed.is_absolute then path = "/" .. path end
  291. -- return path
  292. -- end
  293. -- return _M