aboutsummaryrefslogtreecommitdiff
path: root/src/url.lua
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-19 05:41:30 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-19 05:41:30 +0000
commit5b8d7dec541a618b4ca7f2205470a28cde2e3e25 (patch)
tree209ad0c80c9a938068401fc5b8fa51942972418f /src/url.lua
parent6ac82d50eecdf9bf55f4234ed3a5449afd7a2992 (diff)
downloadluasocket-5b8d7dec541a618b4ca7f2205470a28cde2e3e25.tar.gz
luasocket-5b8d7dec541a618b4ca7f2205470a28cde2e3e25.tar.bz2
luasocket-5b8d7dec541a618b4ca7f2205470a28cde2e3e25.zip
Updated some of the callbacks in callback.lua.
Update get.lua to use the new callbacks. The old "code" module is now the "mime" module. Updated all modules that depended on it. Updated url.lua to use the new namespace scheme, and moved the escape and unescape functions that used to be in the code.lua module to it, since these are specific to urls. Updated the callback entries in the manual.
Diffstat (limited to 'src/url.lua')
-rw-r--r--src/url.lua179
1 files changed, 110 insertions, 69 deletions
diff --git a/src/url.lua b/src/url.lua
index 27e7928..ab3a922 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -6,9 +6,102 @@
6-- RCS ID: $Id$ 6-- RCS ID: $Id$
7---------------------------------------------------------------------------- 7----------------------------------------------------------------------------
8 8
9local Public, Private = {}, {} 9-- make sure LuaSocket is loaded
10local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace 10if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end
11socket.url = Public 11-- get LuaSocket namespace
12local socket = _G[LUASOCKET_LIBNAME]
13if not socket then error('module requires LuaSocket') end
14-- create smtp namespace inside LuaSocket namespace
15local url = {}
16socket.url = url
17-- make all module globals fall into smtp namespace
18setmetatable(url, { __index = _G })
19setfenv(1, url)
20
21-----------------------------------------------------------------------------
22-- Encodes a string into its escaped hexadecimal representation
23-- Input
24-- s: binary string to be encoded
25-- Returns
26-- escaped representation of string binary
27-----------------------------------------------------------------------------
28function escape(s)
29 return string.gsub(s, "(.)", function(c)
30 return string.format("%%%02x", string.byte(c))
31 end)
32end
33
34-----------------------------------------------------------------------------
35-- Protects a path segment, to prevent it from interfering with the
36-- url parsing.
37-- Input
38-- s: binary string to be encoded
39-- Returns
40-- escaped representation of string binary
41-----------------------------------------------------------------------------
42local function make_set(t)
43 local s = {}
44 for i = 1, table.getn(t) do
45 s[t[i]] = 1
46 end
47 return s
48end
49
50-- these are allowed withing a path segment, along with alphanum
51-- other characters must be escaped
52local segment_set = make_set {
53 "-", "_", ".", "!", "~", "*", "'", "(",
54 ")", ":", "@", "&", "=", "+", "$", ",",
55}
56
57local function protect_segment(s)
58 return string.gsub(s, "(%W)", function (c)
59 if segment_set[c] then return c
60 else return escape(c) end
61 end)
62end
63
64-----------------------------------------------------------------------------
65-- Encodes a string into its escaped hexadecimal representation
66-- Input
67-- s: binary string to be encoded
68-- Returns
69-- escaped representation of string binary
70-----------------------------------------------------------------------------
71function unescape(s)
72 return string.gsub(s, "%%(%x%x)", function(hex)
73 return string.char(tonumber(hex, 16))
74 end)
75end
76
77-----------------------------------------------------------------------------
78-- Builds a path from a base path and a relative path
79-- Input
80-- base_path
81-- relative_path
82-- Returns
83-- corresponding absolute path
84-----------------------------------------------------------------------------
85local function absolute_path(base_path, relative_path)
86 if string.sub(relative_path, 1, 1) == "/" then return relative_path end
87 local path = string.gsub(base_path, "[^/]*$", "")
88 path = path .. relative_path
89 path = string.gsub(path, "([^/]*%./)", function (s)
90 if s ~= "./" then return s else return "" end
91 end)
92 path = string.gsub(path, "/%.$", "/")
93 local reduced
94 while reduced ~= path do
95 reduced = path
96 path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
97 if s ~= "../../" then return "" else return s end
98 end)
99 end
100 path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
101 if s ~= "../.." then return "" else return s end
102 end)
103 return path
104end
12 105
13----------------------------------------------------------------------------- 106-----------------------------------------------------------------------------
14-- Parses a url and returns a table with all its parts according to RFC 2396 107-- Parses a url and returns a table with all its parts according to RFC 2396
@@ -28,7 +121,7 @@ socket.url = Public
28-- Obs: 121-- Obs:
29-- the leading '/' in {/<path>} is considered part of <path> 122-- the leading '/' in {/<path>} is considered part of <path>
30----------------------------------------------------------------------------- 123-----------------------------------------------------------------------------
31function Public.parse(url, default) 124function parse(url, default)
32 -- initialize default parameters 125 -- initialize default parameters
33 local parsed = default or {} 126 local parsed = default or {}
34 -- empty url is parsed to nil 127 -- empty url is parsed to nil
@@ -66,11 +159,11 @@ end
66-- Rebuilds a parsed URL from its components. 159-- Rebuilds a parsed URL from its components.
67-- Components are protected if any reserved or unallowed characters are found 160-- Components are protected if any reserved or unallowed characters are found
68-- Input 161-- Input
69-- parsed: parsed URL, as returned by Public.parse 162-- parsed: parsed URL, as returned by parse
70-- Returns 163-- Returns
71-- a stringing with the corresponding URL 164-- a stringing with the corresponding URL
72----------------------------------------------------------------------------- 165-----------------------------------------------------------------------------
73function Public.build(parsed) 166function build(parsed)
74 local url = parsed.path or "" 167 local url = parsed.path or ""
75 if parsed.params then url = url .. ";" .. parsed.params end 168 if parsed.params then url = url .. ";" .. parsed.params end
76 if parsed.query then url = url .. "?" .. parsed.query end 169 if parsed.query then url = url .. "?" .. parsed.query end
@@ -102,9 +195,9 @@ end
102-- Returns 195-- Returns
103-- corresponding absolute url 196-- corresponding absolute url
104----------------------------------------------------------------------------- 197-----------------------------------------------------------------------------
105function Public.absolute(base_url, relative_url) 198function absolute(base_url, relative_url)
106 local base = Public.parse(base_url) 199 local base = parse(base_url)
107 local relative = Public.parse(relative_url) 200 local relative = parse(relative_url)
108 if not base then return relative_url 201 if not base then return relative_url
109 elseif not relative then return base_url 202 elseif not relative then return base_url
110 elseif relative.scheme then return relative_url 203 elseif relative.scheme then return relative_url
@@ -121,10 +214,10 @@ function Public.absolute(base_url, relative_url)
121 end 214 end
122 end 215 end
123 else 216 else
124 relative.path = Private.absolute_path(base.path,relative.path) 217 relative.path = absolute_path(base.path,relative.path)
125 end 218 end
126 end 219 end
127 return Public.build(relative) 220 return build(relative)
128 end 221 end
129end 222end
130 223
@@ -135,13 +228,13 @@ end
135-- Returns 228-- Returns
136-- segment: a table with one entry per segment 229-- segment: a table with one entry per segment
137----------------------------------------------------------------------------- 230-----------------------------------------------------------------------------
138function Public.parse_path(path) 231function parse_path(path)
139 local parsed = {} 232 local parsed = {}
140 path = path or "" 233 path = path or ""
141 path = string.gsub(path, "%s", "") 234 path = string.gsub(path, "%s", "")
142 string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) 235 string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
143 for i = 1, table.getn(parsed) do 236 for i = 1, table.getn(parsed) do
144 parsed[i] = socket.code.unescape(parsed[i]) 237 parsed[i] = unescape(parsed[i])
145 end 238 end
146 if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end 239 if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
147 if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end 240 if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
@@ -154,9 +247,9 @@ end
154-- parsed: path segments 247-- parsed: path segments
155-- unsafe: if true, segments are not protected before path is built 248-- unsafe: if true, segments are not protected before path is built
156-- Returns 249-- Returns
157-- path: correspondin path stringing 250-- path: corresponding path stringing
158----------------------------------------------------------------------------- 251-----------------------------------------------------------------------------
159function Public.build_path(parsed, unsafe) 252function build_path(parsed, unsafe)
160 local path = "" 253 local path = ""
161 local n = table.getn(parsed) 254 local n = table.getn(parsed)
162 if unsafe then 255 if unsafe then
@@ -170,66 +263,14 @@ function Public.build_path(parsed, unsafe)
170 end 263 end
171 else 264 else
172 for i = 1, n-1 do 265 for i = 1, n-1 do
173 path = path .. Private.protect_segment(parsed[i]) 266 path = path .. protect_segment(parsed[i])
174 path = path .. "/" 267 path = path .. "/"
175 end 268 end
176 if n > 0 then 269 if n > 0 then
177 path = path .. Private.protect_segment(parsed[n]) 270 path = path .. protect_segment(parsed[n])
178 if parsed.is_directory then path = path .. "/" end 271 if parsed.is_directory then path = path .. "/" end
179 end 272 end
180 end 273 end
181 if parsed.is_absolute then path = "/" .. path end 274 if parsed.is_absolute then path = "/" .. path end
182 return path 275 return path
183end 276end
184
185function Private.make_set(t)
186 local s = {}
187 for i = 1, table.getn(t) do
188 s[t[i]] = 1
189 end
190 return s
191end
192
193-- these are allowed withing a path segment, along with alphanum
194-- other characters must be escaped
195Private.segment_set = Private.make_set {
196 "-", "_", ".", "!", "~", "*", "'", "(",
197 ")", ":", "@", "&", "=", "+", "$", ",",
198}
199
200function Private.protect_segment(s)
201 local segment_set = Private.segment_set
202 return string.gsub(s, "(%W)", function (c)
203 if segment_set[c] then return c
204 else return socket.code.escape(c) end
205 end)
206end
207
208-----------------------------------------------------------------------------
209-- Builds a path from a base path and a relative path
210-- Input
211-- base_path
212-- relative_path
213-- Returns
214-- corresponding absolute path
215-----------------------------------------------------------------------------
216function Private.absolute_path(base_path, relative_path)
217 if string.sub(relative_path, 1, 1) == "/" then return relative_path end
218 local path = string.gsub(base_path, "[^/]*$", "")
219 path = path .. relative_path
220 path = string.gsub(path, "([^/]*%./)", function (s)
221 if s ~= "./" then return s else return "" end
222 end)
223 path = string.gsub(path, "/%.$", "/")
224 local reduced
225 while reduced ~= path do
226 reduced = path
227 path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
228 if s ~= "../../" then return "" else return s end
229 end)
230 end
231 path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
232 if s ~= "../.." then return "" else return s end
233 end)
234 return path
235end