aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bulkredirect.lua225
1 files changed, 96 insertions, 129 deletions
diff --git a/bulkredirect.lua b/bulkredirect.lua
index 514a63b..ac24e42 100644
--- a/bulkredirect.lua
+++ b/bulkredirect.lua
@@ -85,6 +85,39 @@ local function url_path_encode (s)
return table.concat(t)
end
+function constant(t)
+ return setmetatable({}, {
+ __index = t,
+ __newindex = function(table, key, value)
+ core.Alert("Attempt to modify read-only table")
+ end,
+ __metatable = false
+ });
+end
+
+RTFLAG = constant {
+ WWW = 0x1, -- The rules for a hostname "X" apply also to
+ -- hostname "www.X"
+ EXACT = 0x2, -- Skip prefix search: the redirection reply
+ -- is returned only if the input path is present
+ -- in the table.
+ STRIPPATH = 0x4,
+ --[[ By default the path components stripped during the look
+ up process are added back to the returned location. If
+ this flag is set, these components are dropped instead. ]]
+ STRIPQUERY = 0x8,
+ --[[ By default the query part (if any) is appended to the new
+ location when returning the redirection reply. Setting this
+ flag disables this ]]
+ TEMPORARY = 0x10, -- Return temporary (302) reply.
+ URLENCODE = 0x20,
+ --[[ Encode special characters in path parts of both source and
+ destination URLs as specified in RFC 3986 ("percent encoding").
+ By default, bulkencode assumes all URLs are already properly
+ encoded. ]]
+ DEFAULT = 0
+}
+
--
-- Module global variables:
--
@@ -105,19 +138,20 @@ rt = {}
rt[P1] is found, or P1 is reduced to an empty string. The latter means
there is no redirect for the given P?Q combination.
- The lookup process is reduced to a single look up if the global
- variable 'exact' is true (see below).
+ The search is reduced to a single look up if the EXACT flag is set
+ (see below).
If the entry rt[P1] is found and is a string, it gives the location
of the redirect. Prior to returning a 301 reply, this location is
augmented by pathname part removed from P during the look up process,
and the query part (if any). These modifications are controlled by
- the global variables 'strippath' and 'stripquery'. If 'strippath' is
- true, the removed pathname components are not added back to the
- location. Similarly, if 'stripquery' is true, the query part is not
- appended to the location. The 301 reply code is the default. If the
- 'temporary' global variable is set to true, the code 302 will be used
- instead.
+ the flags STRIPPATH and STRIPQUERY. If STRIPPATH is set, then
+ removed pathname components are not added back to the location.
+ Similarly, if STRIPQUERY is set, the query part is not appended to
+ the location.
+
+ The TEMPORARY flag controls the HTTP reply code. The code is 301
+ if it is not set (the default) and 302 otherwise.
If rt[P1] is a table, it must contain a sequence of two elements.
The element rt[P1][1] supplies the new location if Q is not present.
@@ -125,46 +159,11 @@ rt = {}
values of Q (including empty value). Both rt[P1][1] and rt[P1][2][Q]
can contain either a string or a table value. The string value
supplies the new location as described above. The table value
- supplies the new location in the element [1]. Rest of elements
- (2 up to 5) are boolean values overriding the default global variables
- for this entry. They are located in the following order:
-
- 2 - exact
- 3 - strippath
- 4 - stripquery
- 5 - temporary
+ supplies the new location in the element [1]. The element 2 gives
+ flag values for this redirect.
]]
-www = false
---[[ If set to true, the rules for a hostname "X" apply also to
- hostname "www.X"
-]]
-
-exact = false
---[[ If set to true, no path prefix search is done: the redirection reply
- is returned only if the input path is present in the table.
-]]
-
-strippath = false
---[[ By default the path components stripped during the look up process
- are added back to the returned location. If this variable is set
- to true, these components are dropped instead.
-]]
-
-stripquery = false
---[[ By default the query part (if any) is appended to the new
- location when returning the redirection reply. Setting this variable
- to true disables this
-]]
-
-temporary = false
--- Whether to return temporary (302) or permanent (301) reply.
-
-urlencode = true
---[[ Encode special characters in path parts of both source and destination
- URLs as specified in RFC 3986 ("percent encoding"). By default,
- bulkencode assumes all URLs are already properly encoded.
-]]
+rtflags = RTFLAG.DEFAULT
--
-- Redirect the request if it matches one of the entries in the RT table.
@@ -196,7 +195,7 @@ function bulkredirect.request (txn)
-- Successively strip the trailing element off the path and look up
-- the remaining part in the table.
for i in prevsegm(path) do
- local exact, strippath, stripquery, temporary = exact, strippath, stripquery, temporary
+ local rtflags = rtflags
if rthost[i] then
-- If the entry is found, it is either a table or a string
@@ -219,16 +218,7 @@ function bulkredirect.request (txn)
location = dt[1]
if dt[2] ~= nil then
- exact = dt[2]
- end
- if dt[3] ~= nil then
- strippath = dt[3]
- end
- if dt[4] ~= nil then
- stripquery = dt[4]
- end
- if dt[5] ~= nil then
- temporary = dt[5]
+ rtflags = dt[2]
end
else
location = rthost[i]
@@ -241,16 +231,16 @@ function bulkredirect.request (txn)
location = '/'..location
end
- if not exact or i == path or i..'/' == path then
- if not strippath then
+ if (rtflags & RTFLAG.EXACT) == 0 or i == path or i..'/' == path then
+ if (rtflags & RTFLAG.STRIPPATH) == 0 then
location = location .. path:sub(i:len() + 1)
end
- if not stripquery and txn.f:query() then
+ if (rtflags & RTFLAG.STRIPQUERY) == 0 and txn.f:query() then
location = location .. '?' .. txn.f:query()
end
core.Debug("REDIRECT " .. host .. txn.f:path() .. " to " .. location)
- if temporary then
+ if (rtflags & RTFLAG.TEMPORARY) ~= 0 then
reply:set_status(302, "Moved Temporarily")
else
reply:set_status(301, "Moved Permanently")
@@ -279,14 +269,14 @@ end
HOSTNAME ::= <any valid hostname>
]]
-local function parseopt (s, t, loc)
+local function parseopt (s, flags, loc)
local valid = {
- ['www'] = true,
- ['exact'] = true,
- ['strippath'] = true,
- ['stripquery'] = true,
- ['temporary'] = true,
- ['urlencode'] = true
+ ['www'] = RTFLAG.WWW,
+ ['exact'] = RTFLAG.EXACT,
+ ['strippath'] = RTFLAG.STRIPPATH,
+ ['stripquery'] = RTFLAG.STRIPQUERY,
+ ['temporary'] = RTFLAG.TEMPORARY,
+ ['urlencode'] = RTFLAG.URLENCODE
}
function options (str, loc)
@@ -309,24 +299,23 @@ local function parseopt (s, t, loc)
end
end
- if not t then
- t = _ENV
- end
-
for opt in options(s, loc) do
local neg = opt:match("^no(%w+)$")
- local val = true
if neg then
opt = neg
- val = not val
end
- if not valid[opt] then
+ if valid[opt] then
+ if neg then
+ flags = flags & ~valid[opt]
+ else
+ flags = flags | valid[opt]
+ end
+ else
error(loc .. ': invalid option ' .. opt, 0)
end
-
- t[opt] = val
end
+ return flags
end
local function set_dst (dt, src, dst)
@@ -337,7 +326,7 @@ local function set_dst (dt, src, dst)
elseif type(dt[path]) == 'string' then
dt[path] = { { dt[path] }, {} }
end
--- core.Info(require('inspect')(dt[path]))
+ core.Info(require('inspect')(dt[path]))
dt[path][2][query] = dst
elseif type(dt[src]) == 'table' then
dt[src][1] = dst
@@ -376,6 +365,7 @@ local function populate_www_complements (rt, dup)
if rt[compl] then
for k,v in pairs(t) do
-- FIXME: Error message if rt[compl][k] exists
+ if not crt[compl] then crt[compl] = {} end
crt[compl][k] = clone(v)
end
elseif dup then
@@ -392,35 +382,28 @@ end
local function load_redirect_file (f, filename)
local domain
- local ln = 1
+ local ln = 0
local rt = {}
- local domopt
+ local domain_flags = rtflags
local parsetab = {
{ '^#', function () end },
{ '^%s*$', function () end },
{ '^option%s+(.*)',
function (s)
- local t
if domain then
- t = domopt
+ domain_flags = parseopt(s, domain_flags, filename .. ':' .. ln)
else
- t = _ENV
- end
- parseopt(s, t, filename .. ':' .. ln)
+ rtflags = parseopt(s, rtflags, filename .. ':' .. ln)
+ end
end
},
{ '^%s*%[(.+)%]%s*$',
function (s)
domain = s
if not rt[domain] then rt[domain] = {} end
- domopt = {
- exact = exact,
- strippath = strippath,
- stripquery = stripquery,
- temporary = temporary
- }
+ domain_flags = rtflags
end
},
{ '^%s*([^%s]+)%s+([^%s]+)%s*(.*)$',
@@ -437,13 +420,12 @@ local function load_redirect_file (f, filename)
dst = dst:sub(2)
end
- local optab = domopt
+ local rule_flags = domain_flags
if optlist ~= '' then
- optab = clone(domopt)
- parseopt(optlist, optab, filename .. ':' .. ln)
+ rule_flags = parseopt(optlist, rule_flags, filename .. ':' .. ln)
end
- if optab['urlencode'] then
+ if (rule_flags & RTFLAG.URLENCODE) ~= 0 then
src = url_path_encode(src)
dst = url_path_encode(dst)
else
@@ -452,53 +434,38 @@ local function load_redirect_file (f, filename)
local dpath, dquery = dst:match('^(.+)?(.*)')
if dpath then
- if optab['strippath'] == false and optab['strippath'] ~= domopt['strippath'] then
+ if (rule_flags & RTFLAG.STRIPPATH) == 0 and ((rule_flags ~ domain_flags) & RTFLAG.STRIPPATH) ~= 0 then
core.Warning(filename .. ':' .. ln .. ': nostrippath ignored because of explicit query in the destination')
end
- if optab['stripquery'] == false and optab['stripquery'] ~= domopt['stripquery'] then
+ if (rule_flags & RTFLAG.STRIPQUERY) == 0 and ((rule_flags ~ domain_flags) & RTFLAG.STRIPQUERY) ~= 0 then
core.Warning(filename .. ':' .. ln .. ': nostripquery ignored because of explicit query in the destination')
end
-
- optab['strippath'] = true
- optab['stripquery'] = true
+
+ rule_flags = rule_flags | RTFLAG.STRIPPATH
+ rule_flags = rule_flags | RTFLAG.STRIPQUERY
if dquery == '' then
dst = dpath
end
end
- if optab['exact'] ~= exact then
- if type(dst) == 'string' then dst = { dst } end
- dst[2] = optab['exact']
- end
- if optab['strippath'] ~= strippath then
+ if ((rule_flags ~ rtflags) & ~RTFLAG.URLENCODE) ~= 0 then
if type(dst) == 'string' then dst = { dst } end
- dst[3] = optab['strippath']
- end
- if optab['stripquery'] ~= stripquery then
- if type(dst) == 'string' then dst = { dst } end
- dst[4] = optab['stripquery']
- end
- if optab['temporary'] ~= temporary then
- if type(dst) == 'string' then dst = { dst } end
- dst[5] = optab['temporary']
+ dst[2] = rule_flags
end
- if optab['www'] ~= nil then
- if www == optab['www'] then
- return
- elseif www then
- populate_www_complements (rt, true)
- www = nil
+ if (rule_flags & RTFLAG.WWW) ~= 0 then
+ if (rtflags & RTFLAG.WWW) == 0 then
+ local s = www_complement(domain)
+ if not rt[s] then rt[s] = {} end
+ set_dst(rt[s], src, dst)
end
- end
-
- set_dst(rt[domain], src, dst)
-
- if optab['www'] then
+ elseif (rtflags & RTFLAG.WWW) ~= 0 then
+ populate_www_complements(rt, true)
+ rtflags = rtflags & ~RTFLAG.WWW
local s = www_complement(domain)
if not rt[s] then rt[s] = {} end
- set_dst(rt[s], src, dst)
end
+ set_dst(rt[domain], src, dst)
end
}
}
@@ -517,9 +484,9 @@ local function load_redirect_file (f, filename)
::continue::
end
- if www then
+ if (rtflags & RTFLAG.WWW) ~= 0 then
populate_www_complements (rt, false)
- www = nil
+ rtflags = rtflags & ~RTFLAG.WWW
end
_ENV['rt'] = rt
@@ -531,7 +498,7 @@ local function load_redirect_table ()
name = '/etc/haproxy/bulkredirect.rt'
end
if name:match('%.lua$') then
- rt, www, exact, strippath, stripquery, temporary = dofile(name)
+ rt, rtflags = dofile(name)
else
local file, err = io.open(name,"r")
if file ~= nil then

Return to:

Send suggestions and report system problems to the System administrator.