diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-19 05:41:30 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-19 05:41:30 +0000 |
commit | 5b8d7dec541a618b4ca7f2205470a28cde2e3e25 (patch) | |
tree | 209ad0c80c9a938068401fc5b8fa51942972418f /src/url.lua | |
parent | 6ac82d50eecdf9bf55f4234ed3a5449afd7a2992 (diff) | |
download | luasocket-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.lua | 179 |
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 | ||
9 | local Public, Private = {}, {} | 9 | -- make sure LuaSocket is loaded |
10 | local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace | 10 | if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end |
11 | socket.url = Public | 11 | -- get LuaSocket namespace |
12 | local socket = _G[LUASOCKET_LIBNAME] | ||
13 | if not socket then error('module requires LuaSocket') end | ||
14 | -- create smtp namespace inside LuaSocket namespace | ||
15 | local url = {} | ||
16 | socket.url = url | ||
17 | -- make all module globals fall into smtp namespace | ||
18 | setmetatable(url, { __index = _G }) | ||
19 | setfenv(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 | ----------------------------------------------------------------------------- | ||
28 | function escape(s) | ||
29 | return string.gsub(s, "(.)", function(c) | ||
30 | return string.format("%%%02x", string.byte(c)) | ||
31 | end) | ||
32 | end | ||
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 | ----------------------------------------------------------------------------- | ||
42 | local 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 | ||
48 | end | ||
49 | |||
50 | -- these are allowed withing a path segment, along with alphanum | ||
51 | -- other characters must be escaped | ||
52 | local segment_set = make_set { | ||
53 | "-", "_", ".", "!", "~", "*", "'", "(", | ||
54 | ")", ":", "@", "&", "=", "+", "$", ",", | ||
55 | } | ||
56 | |||
57 | local 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) | ||
62 | end | ||
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 | ----------------------------------------------------------------------------- | ||
71 | function unescape(s) | ||
72 | return string.gsub(s, "%%(%x%x)", function(hex) | ||
73 | return string.char(tonumber(hex, 16)) | ||
74 | end) | ||
75 | end | ||
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 | ----------------------------------------------------------------------------- | ||
85 | local 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 | ||
104 | end | ||
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 | ----------------------------------------------------------------------------- |
31 | function Public.parse(url, default) | 124 | function 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 | ----------------------------------------------------------------------------- |
73 | function Public.build(parsed) | 166 | function 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 | ----------------------------------------------------------------------------- |
105 | function Public.absolute(base_url, relative_url) | 198 | function 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 |
129 | end | 222 | end |
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 | ----------------------------------------------------------------------------- |
138 | function Public.parse_path(path) | 231 | function 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 | ----------------------------------------------------------------------------- |
159 | function Public.build_path(parsed, unsafe) | 252 | function 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 |
183 | end | 276 | end |
184 | |||
185 | function 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 | ||
191 | end | ||
192 | |||
193 | -- these are allowed withing a path segment, along with alphanum | ||
194 | -- other characters must be escaped | ||
195 | Private.segment_set = Private.make_set { | ||
196 | "-", "_", ".", "!", "~", "*", "'", "(", | ||
197 | ")", ":", "@", "&", "=", "+", "$", ",", | ||
198 | } | ||
199 | |||
200 | function 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) | ||
206 | end | ||
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 | ----------------------------------------------------------------------------- | ||
216 | function 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 | ||
235 | end | ||