webmcp
view framework/env/auth/openid/_normalize_url.lua @ 26:9ef0c71fb827
Added tag v1.1.1 for changeset a02c25eb3517
| author | jbe | 
|---|---|
| date | Thu Jul 08 20:24:14 2010 +0200 (2010-07-08) | 
| parents | 47ddf0f86009 | 
| children | e3e2a03f75b2 | 
 line source
     1 --[[--
     2 url,                         -- normalized URL or nil
     3 auth.openid._normalize_url(
     4   url                        -- unnormalized URL
     5 )
     7 This function normalizes an URL, and returns nil if the given URL is not a
     8 valid absolute URL. For security reasons only a restricted set of URLs is
     9 valid.
    11 --]]--
    13 function auth.openid._normalize_url(url)
    14   local url = string.match(url, "^(.-)??$")  -- remove "?" at end
    15   local proto, host, path = string.match(
    16     url,
    17     "([A-Za-z]+)://([0-9A-Za-z.:_-]+)/?([0-9A-Za-z%%/._~-]*)$"
    18   )
    19   if not proto then
    20     return nil
    21   end
    22   proto = string.lower(proto)
    23   host  = string.lower(host)
    24   local port = string.match(host, ":(.*)")
    25   if port then
    26     if string.find(port, "^[0-9]+$") then
    27       port = tonumber(port)
    28       host = string.match(host, "^(.-):")
    29       if port < 1 or port > 65535 then
    30         return nil
    31       end
    32     else
    33       return nil
    34     end
    35   end
    36   if proto == "http" then
    37     if port == 80 then port = nil end
    38   elseif proto == "https" then
    39     if port == 443 then port = nil end
    40   else
    41     return nil
    42   end
    43   if
    44     string.find(host, "^%.") or
    45     string.find(host, "%.$") or
    46     string.find(host, "%.%.")
    47   then
    48     return nil
    49   end
    50   for part in string.gmatch(host, "[^.]+") do
    51     if not string.find(part, "[A-Za-z]") then
    52       return nil
    53     end
    54   end
    55   local path_parts = {}
    56   for part in string.gmatch(path, "[^/]+") do
    57     if part == "." then
    58       -- do nothing
    59     elseif part == ".." then
    60       path_parts[#path_parts] = nil
    61     else
    62       local fail = false
    63       local part = string.gsub(
    64         part,
    65         "%%([0-9A-Fa-f]?[0-9A-Fa-f]?)",
    66         function (hex)
    67           if #hex ~= 2 then
    68             fail = true
    69             return
    70           end
    71           local char = string.char(tonumber("0x" .. hex))
    72           if string.find(char, "[0-9A-Za-z._~-]") then
    73             return char
    74           else
    75             return "%" .. string.upper(hex)
    76           end
    77         end
    78       )
    79       if fail then
    80         return nil
    81       end
    82       path_parts[#path_parts+1] = part
    83     end
    84   end
    85   if string.find(path, "/$") then
    86     path_parts[#path_parts+1] = ""
    87   end
    88   path = table.concat(path_parts, "/")
    89   if port then
    90     host = host .. ":" .. tostring(port)
    91   end
    92   return proto .. "://" .. host .. "/" .. path
    93 end
