-- windmill.mearie.org multiview emulation script -- last updated on 2009-06-22 -- -- written by Kang Seonghoon -- adapted (and heavily modified) from Svilen Spasov's: -- http://blog.svilen.com/2009/04/using-modnegotiation-with-lighttpd.html -- only implements Accept-Language detection, which is best used so far. local EXTENSIONS = {'.php', '.html', '.js', '.css', '.xhtml', '.xml'} local LANGUAGES = {'.en', '.ko', '.ja', ''} function parse_acceptlang(spec) --print('Accept-Language was ' .. spec) spec = spec .. ',' local exts = {} while spec ~= '' do -- extract first specification from the string. local lang, q, tail = spec:match('^%s*([%w%-]+)%s*;%s*q%s*=%s*([%d%.]+)%s*,%s*(.*)$') if not lang then lang, tail = spec:match('^%s*([%w%-]+)%s*,%s*(.*)$') if not lang then return false end -- invalid specification: stop parsing. q = 1.0 -- assume q=1.0 else q = tonumber(q) if not q then return false end -- invalid q-value end -- for sake of simplicity, we assume implicit * at the end of specification. -- (so we don't have to return 406 Not Acceptable, but it is not complying) if lang ~= '*' then table.insert(exts, {'.' .. lang, q, #exts}) end spec = tail end -- sort the list by q-value and relative order. table.sort(exts, function(lhs, rhs) return (lhs[2] > rhs[2] or (lhs[2] == rhs[2] and lhs[3] > rhs[3])) end) -- now replace LANGUAGES by new list. local newlangs = {} local used = {} for _, entry in ipairs(exts) do local ext = entry[1] if not used[ext] then table.insert(newlangs, ext) used[ext] = true end end for _, ext in ipairs(LANGUAGES) do if not used[ext] then table.insert(newlangs, ext) end end LANGUAGES = newlangs --print('replacing LANGUAGES with ' .. table.concat(newlangs, '/')) end function apply_constraint(filename, exts) for _, ext in ipairs(exts) do if ext ~= '' and filename:sub(-ext:len()) == ext then return filename:sub(1, -1-ext:len()), ext end end return filename, nil end if not lighty.stat(lighty.env['physical.path']) then local path = lighty.env['physical.rel-path'] local origpath = path local uri = lighty.env['request.uri'] local docroot = lighty.env['physical.doc-root'] while uri ~= '' do -- remove last directory/URI element from uri and path until URI is empty. uri = uri:match('^(.-)[/\\]+[^/\\]*$') local prevpath = path local part path, part = path:match('^(.-)[/\\]+([^/\\]*)$') local stat = lighty.stat(docroot .. path) if stat then -- if it is just a file, we may continue as is since lighty will -- split the original path correctly. if stat.is_dir then -- we now have to parse Accept-Language header if exists. if lighty.request['Accept-Language'] then parse_acceptlang(lighty.request['Accept-Language']) end -- apply possible constraints from the requested file name. local part, langext = apply_constraint(part, LANGUAGES) local part, typeext = apply_constraint(part, EXTENSIONS) if langext then LANGUAGES = {langext} end if typeext then EXTENSIONS = {typeext} end --print('final LANGUAGES: ' .. table.concat(LANGUAGES, '/')) --print('final EXTENSIONS: ' .. table.concat(EXTENSIONS, '/')) -- search for appropriate alternative path. ("path/part" didn't exist!) local newpath = path .. '/' .. part local rewritten = false for i, ext in ipairs(LANGUAGES) do local newpath = newpath .. ext for i, ext in ipairs(EXTENSIONS) do local newpath = newpath .. ext if lighty.stat(docroot .. newpath) then -- re-append stripped path elements. (lighty will split this -- correctly and treat it as PATH_INFO.) newpath = newpath .. origpath:sub(prevpath:len() + 1) lighty.env['physical.rel-path'] = newpath lighty.env['physical.path'] = docroot .. newpath rewritten = true break end end if rewritten then break end end end -- if the search has been failed, lighty will issue 404 correctly. break end end end -- vim: ts=4 sw=4