aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2001-09-12 18:27:40 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2001-09-12 18:27:40 +0000
commit5c622071f95b833727767219cdee31b1419d6cc4 (patch)
treecaf89ceaff537d936e8a02b42d92280774291047 /src
parent480689a70217d2ec9bedf699166f05bb972e9448 (diff)
downloadluasocket-5c622071f95b833727767219cdee31b1419d6cc4.tar.gz
luasocket-5c622071f95b833727767219cdee31b1419d6cc4.tar.bz2
luasocket-5c622071f95b833727767219cdee31b1419d6cc4.zip
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/url.lua204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/url.lua b/src/url.lua
new file mode 100644
index 0000000..8cafd9b
--- /dev/null
+++ b/src/url.lua
@@ -0,0 +1,204 @@
1-----------------------------------------------------------------------------
2-- URI parsing, composition and relative URL resolution
3-- LuaSocket 1.4 toolkit.
4-- Author: Diego Nehab
5-- Date: 20/7/2001
6-- Conforming to: RFC 2396, LTN7
7-- RCS ID: $Id$
8----------------------------------------------------------------------------
9
10local Public, Private = {}, {}
11URL = Public
12
13-----------------------------------------------------------------------------
14-- Parses a url and returns a table with all its parts according to RFC 2396
15-- The following grammar describes the names given to the URL parts
16-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
17-- <authority> ::= <userinfo>@<host>:<port>
18-- <userinfo> ::= <user>[:<password>]
19-- <path> :: = {<segment>/}<segment>
20-- Input
21-- url: uniform resource locator of request
22-- default: table with default values for each field
23-- Returns
24-- table with the following fields, where RFC naming conventions have
25-- been preserved:
26-- scheme, authority, userinfo, user, password, host, port,
27-- path, params, query, fragment
28-- Obs:
29-- the leading '/' in {/<path>} is considered part of <path>
30-----------------------------------------------------------------------------
31function Public.parse_url(url, default)
32 -- initialize default parameters
33 local parsed = default or {}
34 -- empty url is parsed to nil
35 if not url or url == "" then return nil end
36 -- remove whitespace
37 url = gsub(url, "%s", "")
38 -- get fragment
39 url = gsub(url, "#(.*)$", function(f) %parsed.fragment = f end)
40 -- get scheme
41 url = gsub(url, "^([%w][%w%+%-%.]*)%:", function(s) %parsed.scheme = s end)
42 -- get authority
43 url = gsub(url, "^//([^/]*)", function(n) %parsed.authority = n end)
44 -- get query string
45 url = gsub(url, "%?(.*)", function(q) %parsed.query = q end)
46 -- get params
47 url = gsub(url, "%;(.*)", function(p) %parsed.params = p end)
48 if url ~= "" then parsed.path = url end
49 local authority = parsed.authority
50 if not authority then return parsed end
51 authority = gsub(authority,"^([^@]*)@",function(u) %parsed.userinfo = u end)
52 authority = gsub(authority, ":([^:]*)$", function(p) %parsed.port = p end)
53 if authority ~= "" then parsed.host = authority end
54 local userinfo = parsed.userinfo
55 if not userinfo then return parsed end
56 userinfo = gsub(userinfo, ":([^:]*)$", function(p) %parsed.password = p end)
57 parsed.user = userinfo
58 return parsed
59end
60
61-----------------------------------------------------------------------------
62-- Rebuilds a parsed URL from its components.
63-- Components are protected if any reserved or unallowed characters are found
64-- Input
65-- parsed: parsed URL, as returned by Public.parse
66-- Returns
67-- a string with the corresponding URL
68-----------------------------------------------------------------------------
69function Public.build_url(parsed)
70 local url = parsed.path or ""
71 if parsed.params then url = url .. ";" .. parsed.params end
72 if parsed.query then url = url .. "?" .. parsed.query end
73 if parsed.authority then url = "//" .. parsed.authority .. url end
74 if parsed.scheme then url = parsed.scheme .. ":" .. url end
75 if parsed.fragment then url = url .. "#" .. parsed.fragment end
76 return gsub(url, "%s", "")
77end
78
79-----------------------------------------------------------------------------
80-- Builds a absolute URL from a base and a relative URL according to RFC 2396
81-- Input
82-- base_url
83-- relative_url
84-- Returns
85-- corresponding absolute url
86-----------------------------------------------------------------------------
87function Public.absolute_url(base_url, relative_url)
88 local base = %Public.parse_url(base_url)
89 local relative = %Public.parse_url(relative_url)
90 if not base then return relative_url
91 elseif not relative then return base_url
92 elseif relative.scheme then return relative_url
93 else
94 relative.scheme = base.scheme
95 if not relative.authority then
96 relative.authority = base.authority
97 if not relative.path then
98 relative.path = base.path
99 if not relative.params then
100 relative.params = base.params
101 if not relative.query then
102 relative.query = base.query
103 end
104 end
105 else
106 relative.path = %Private.absolute_path(base.path,relative.path)
107 end
108 end
109 return %Public.build_url(relative)
110 end
111end
112
113-----------------------------------------------------------------------------
114-- Breaks a path into its segments, unescaping the segments
115-- Input
116-- path
117-- Returns
118-- segment: a table with one entry per segment
119-----------------------------------------------------------------------------
120function Public.parse_path(path)
121 local parsed = {}
122 path = gsub(path, "%s", "")
123 gsub(path, "([^/]+)", function (s) tinsert(%parsed, s) end)
124 for i = 1, getn(parsed) do
125 parsed[i] = Code.unescape(parsed[i])
126 end
127 if strsub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
128 if strsub(path, -1, -1) == "/" then parsed.is_directory = 1 end
129 return parsed
130end
131
132-----------------------------------------------------------------------------
133-- Builds a path component from its segments, escaping protected characters.
134-- Input
135-- parsed: path segments
136-- Returns
137-- path: correspondin path string
138-----------------------------------------------------------------------------
139function Public.build_path(parsed)
140 local path = ""
141 local n = getn(parsed)
142 for i = 1, n-1 do
143 path = path .. %Private.protect_segment(parsed[i])
144 path = path .. "/"
145 end
146 if n > 0 then
147 path = path .. %Private.protect_segment(parsed[n])
148 if parsed.is_directory then path = path .. "/" end
149 end
150 if parsed.is_absolute then path = "/" .. path end
151 return path
152end
153
154function Private.make_set(table)
155 local s = {}
156 for i = 1, getn(table) do
157 s[table[i]] = 1
158 end
159 return s
160end
161
162-- these are allowed withing a path segment, along with alphanum
163-- other characters must be escaped
164Private.segment_set = Private.make_set {
165 "-", "_", ".", "!", "~", "*", "'", "(",
166 ")", ":", "@", "&", "=", "+", "$", ",",
167}
168
169function Private.protect_segment(s)
170 local segment_set = %Private.segment_set
171 return gsub(s, "(%W)", function (c)
172 if %segment_set[c] then return c
173 else return Code.escape(c) end
174 end)
175end
176
177-----------------------------------------------------------------------------
178-- Builds a path from a base path and a relative path
179-- Input
180-- base_path
181-- relative_path
182-- Returns
183-- corresponding absolute path
184-----------------------------------------------------------------------------
185function Private.absolute_path(base_path, relative_path)
186 if strsub(relative_path, 1, 1) == "/" then return relative_path end
187 local path = gsub(base_path, "[^/]*$", "")
188 path = path .. relative_path
189 path = gsub(path, "([^/]*%./)", function (s)
190 if s ~= "./" then return s else return "" end
191 end)
192 path = gsub(path, "/%.$", "/")
193 local reduced
194 while reduced ~= path do
195 reduced = path
196 path = gsub(reduced, "([^/]*/%.%./)", function (s)
197 if s ~= "../../" then return "" else return s end
198 end)
199 end
200 path = gsub(reduced, "([^/]*/%.%.)$", function (s)
201 if s ~= "../.." then return "" else return s end
202 end)
203 return path
204end