Added permission for lua.cgi in Makefile; FastCGI class added; improved
authorTimm S. Mueller <tmueller@neoscientists.org>
Fri, 23 Nov 2007 01:46:43 +0100
changeset 201d52b05a9fe9c
parent 200 6bfb1fa24598
child 202 1a5e6ef206c0
Added permission for lua.cgi in Makefile; FastCGI class added; improved
configuration and statistics output in FastCGI runner; versionstring format
changed; inheritance is now based on tek.class - Atom class removed; Debug
library added; removed "attr" permission
Makefile
cgi-bin/loona_fastcgi.lua
cgi-bin/lua.cgi
cgi-bin/tek/app/loona.lua
cgi-bin/tek/class.lua
cgi-bin/tek/class/atom.lua
cgi-bin/tek/class/cgi.lua
cgi-bin/tek/class/cgi/post.lua
cgi-bin/tek/class/cgi/request.lua
cgi-bin/tek/class/fastcgi.lua
cgi-bin/tek/class/loona.lua
cgi-bin/tek/class/loona/buffer.lua
cgi-bin/tek/class/loona/markup.lua
cgi-bin/tek/class/loona/util.lua
cgi-bin/tek/lib.lua
cgi-bin/tek/lib/debug.lua
etc/passwd.lua.sample
htdocs/images/loona.png
htdocs/images/loona.svg
htdocs/index.lua
htdocs/loona.css
htdocs/upload.lua
     1.1 --- a/Makefile	Wed Oct 10 10:53:15 2007 +0200
     1.2 +++ b/Makefile	Fri Nov 23 01:46:43 2007 +0100
     1.3 @@ -1,6 +1,6 @@
     1.4  
     1.5  #
     1.6 -#	Loona Makefile
     1.7 +#	LOona Makefile
     1.8  #	Written by Timm S. Mueller <tmueller at neoscientists.org>
     1.9  #	See copyright notice in COPYRIGHT
    1.10  #
    1.11 @@ -68,7 +68,7 @@
    1.12  	chmod -R 664 *
    1.13  	chown -R :$(GROUP) *
    1.14  	find . -type d | xargs chmod ugo+x
    1.15 -	chmod ugo+x $(CGIDIR)/loona.cgi $(CGIDIR)/loona_fastcgi.lua
    1.16 +	chmod ugo+x $(CGIDIR)/loona.cgi $(CGIDIR)/loona_fastcgi.lua $(CGIDIR)/lua.cgi
    1.17  	chown -R $(WWWUSER) $(VARDIR)/sessions $(VARDIR)/htmlcache
    1.18  	chown -R $(WWWUSER) $(CONTENTDIR) $(HTDIR)
    1.19  	find . -name CVS -type d | xargs -r chmod g+rw
     2.1 --- a/cgi-bin/loona_fastcgi.lua	Wed Oct 10 10:53:15 2007 +0200
     2.2 +++ b/cgi-bin/loona_fastcgi.lua	Fri Nov 23 01:46:43 2007 +0100
     2.3 @@ -17,9 +17,15 @@
     2.4  --	constants and globals:
     2.5  -------------------------------------------------------------------------------
     2.6  
     2.7 --- set global debug level:
     2.8 +-- Set global debug level:
     2.9  db.level = 4
    2.10  
    2.11 +-- Address to bind server to:
    2.12 +local SERVERADDR = "127.0.0.1"
    2.13 +
    2.14 +-- Port to bind server to:
    2.15 +local SERVERPORT = 20000
    2.16 +
    2.17  -- The script name we enforce:
    2.18  local SCRIPTNAME = "/index.lua"
    2.19  
    2.20 @@ -31,7 +37,7 @@
    2.21  --	FCGI Buffer class:
    2.22  -------------------------------------------------------------------------------
    2.23  
    2.24 -local FCGIBuffer = Buffer:newclass()
    2.25 +local FCGIBuffer = Buffer:newClass()
    2.26  
    2.27  function FCGIBuffer:flush()
    2.28  	local fcgi = self.fcgi
    2.29 @@ -49,7 +55,7 @@
    2.30  --	FCGI Server class:
    2.31  -------------------------------------------------------------------------------
    2.32  
    2.33 -local FCGIServer = FCGI:newclass()
    2.34 +local FCGIServer = FCGI:newClass()
    2.35  
    2.36  function FCGIServer:runapp(req)
    2.37  	loona.main(self.buffer, self.request, self.document, self.userdata)
    2.38 @@ -109,13 +115,15 @@
    2.39  --	main:
    2.40  -------------------------------------------------------------------------------
    2.41  
    2.42 +db.info("Binding server to %s, port %d", SERVERADDR, SERVERPORT)
    2.43 +
    2.44  -- global application state:
    2.45  local app = { }
    2.46  
    2.47  -- create FastCGI listening socket:
    2.48  app.server = socket.tcp()
    2.49  app.server:setoption("reuseaddr", true)
    2.50 -app.server:bind("127.0.0.1", 20000)
    2.51 +app.server:bind(SERVERADDR, SERVERPORT)
    2.52  app.server:listen(64)
    2.53  
    2.54  -- run:
    2.55 @@ -128,8 +136,11 @@
    2.56  		client:close()
    2.57  		local mem1 = collectgarbage("count")
    2.58  		collectgarbage("collect")
    2.59 -		local t = socket.gettime() - t0
    2.60 -		db.info("Mem used: %.1fk - for request: %.1fk - elapsed: %.2fs",
    2.61 +		local t1 = socket.gettime()
    2.62 +		local t = t1 - t0
    2.63 +		local d = os.date("*t", t1)
    2.64 +		db.info("%04d-%02d-%02d %02d:%02d:%02d - Mem used: %.1fk - for request: %.1fk - elapsed: %.2fs",
    2.65 +			d.year, d.month, d.day, d.hour, d.min, d.sec,
    2.66  			mem1, mem1 - mem0, t)
    2.67  	end
    2.68  end
     3.1 --- a/cgi-bin/lua.cgi	Wed Oct 10 10:53:15 2007 +0200
     3.2 +++ b/cgi-bin/lua.cgi	Fri Nov 23 01:46:43 2007 +0100
     3.3 @@ -1,5 +1,6 @@
     3.4  #!/usr/local/bin/lua
     3.5  --
     3.6 ---	Mini CGI wrapper
     3.7 +--	Mini CGI wrapper -
     3.8 +--	Executes the addressed Lua script
     3.9  --
    3.10  dofile(os.getenv("PATH_TRANSLATED"))
     4.1 --- a/cgi-bin/tek/app/loona.lua	Wed Oct 10 10:53:15 2007 +0200
     4.2 +++ b/cgi-bin/tek/app/loona.lua	Fri Nov 23 01:46:43 2007 +0100
     4.3 @@ -13,10 +13,7 @@
     4.4  
     4.5  
     4.6  module "tek.app.loona"
     4.7 -
     4.8 -
     4.9 -_VERSION = 2
    4.10 -_REVISION = 0
    4.11 +_VERSION = "LOona main 2.0"
    4.12  
    4.13  
    4.14  function main(buf, request, document, userdata)
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/cgi-bin/tek/class.lua	Fri Nov 23 01:46:43 2007 +0100
     5.3 @@ -0,0 +1,38 @@
     5.4 +
     5.5 +--
     5.6 +--	tek.class - Implements inheritance
     5.7 +--	Written by Timm S. Mueller <tmueller at neoscientists.org>
     5.8 +--	See copyright notice in COPYRIGHT
     5.9 +--
    5.10 +
    5.11 +local tostring = tostring
    5.12 +local getmetatable = getmetatable
    5.13 +local setmetatable = setmetatable
    5.14 +
    5.15 +module "tek.class"
    5.16 +_VERSION = "TEK Class 2.0"
    5.17 +
    5.18 +__index = _M
    5.19 +
    5.20 +function new(class, self)
    5.21 +	return setmetatable(self or { }, class)
    5.22 +end
    5.23 +
    5.24 +newClass = function(baseclass, class)
    5.25 +	class = class or { }
    5.26 +	class.__index = class
    5.27 +	class.__call = newClass
    5.28 +	class._NAME = class._NAME or baseclass._NAME ..
    5.29 +		tostring(class):gsub("^table: 0x(.*)$", ".%1")
    5.30 +	return setmetatable(class, baseclass)
    5.31 +end
    5.32 +
    5.33 +__call = newClass
    5.34 +
    5.35 +getClass = getmetatable
    5.36 +
    5.37 +function getClassName(self)
    5.38 +	return self._NAME
    5.39 +end
    5.40 +
    5.41 +setmetatable(_M, { __call = newClass })
     6.1 --- a/cgi-bin/tek/class/atom.lua	Wed Oct 10 10:53:15 2007 +0200
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,43 +0,0 @@
     6.4 -
     6.5 ---
     6.6 ---	tek.class.atom
     6.7 ---	Copyright (C) 2007, Schulze & Mueller GbR
     6.8 ---	Written by Timm S. Mueller <tmueller@schulze-mueller.de>
     6.9 ---
    6.10 -
    6.11 -local tostring = tostring
    6.12 -local setmetatable, getmetatable = setmetatable, getmetatable
    6.13 -
    6.14 -module "tek.class.atom"
    6.15 -
    6.16 -_VERSION = 1
    6.17 -_REVISION = 0
    6.18 -
    6.19 --------------------------------------------------------------------------------
    6.20 ---	Class implementation:
    6.21 --------------------------------------------------------------------------------
    6.22 -
    6.23 -local atom = _M
    6.24 -
    6.25 -__index = atom
    6.26 -
    6.27 -function atom.new(class, self)
    6.28 -	return setmetatable(self or { }, class)
    6.29 -end
    6.30 -
    6.31 -function atom.newclass(baseclass, class)
    6.32 -	class = class or { }
    6.33 -	class.__index = class
    6.34 -	class._BASECLASS = baseclass
    6.35 -	class._NAME = class._NAME or baseclass._NAME ..
    6.36 -		tostring(class):gsub("^table: 0x(.*)$", ".%1")
    6.37 -	return setmetatable(class, baseclass)
    6.38 -end
    6.39 -
    6.40 -function atom:getclass()
    6.41 -	return getmetatable(self)
    6.42 -end
    6.43 -
    6.44 -function atom:getclassname()
    6.45 -	return self._NAME
    6.46 -end
     7.1 --- a/cgi-bin/tek/class/cgi.lua	Wed Oct 10 10:53:15 2007 +0200
     7.2 +++ b/cgi-bin/tek/class/cgi.lua	Fri Nov 23 01:46:43 2007 +0100
     7.3 @@ -10,14 +10,9 @@
     7.4  
     7.5  
     7.6  module "tek.class.cgi"
     7.7 +_VERSION = "CGI 1.2"
     7.8  
     7.9  
    7.10 -_VERSION = 1
    7.11 -_REVISION = 1
    7.12 -
    7.13 -
    7.14 --------------------------------------------------------------------------------
    7.15 -
    7.16  --	Encode string to URL. Optionally specify a set of characters
    7.17  --	which are left unmodified. Possible characters that may be excluded
    7.18  --	from conversion are $&+,/:;=?@ .
    7.19 @@ -25,7 +20,7 @@
    7.20  function encodeurl(s, excl)
    7.21  	local matchset = "$&+,/:;=?@" -- reserved chars with special meaning
    7.22  	if excl == true then
    7.23 -		matchset = "" 
    7.24 +		matchset = ""
    7.25  	elseif excl and type(excl) == "string" then
    7.26  		matchset = matchset:gsub("[" .. keep:gsub(".", "%%%1") .. "]", "")
    7.27  	end
     8.1 --- a/cgi-bin/tek/class/cgi/post.lua	Wed Oct 10 10:53:15 2007 +0200
     8.2 +++ b/cgi-bin/tek/class/cgi/post.lua	Fri Nov 23 01:46:43 2007 +0100
     8.3 @@ -6,21 +6,15 @@
     8.4  --
     8.5  
     8.6  
     8.7 -local Atom = require "tek.class.atom"
     8.8 -local getfenv, setmetatable = getfenv, setmetatable
     8.9 +local Class = require "tek.class"
    8.10  local char = string.char
    8.11  local assert, error, tonumber, type = assert, error, tonumber, type
    8.12  local insert, pairs = table.insert, pairs
    8.13  local tmpfile = io.tmpfile
    8.14  local min = math.min
    8.15  
    8.16 -
    8.17 -module "tek.class.cgi.post"
    8.18 -
    8.19 -
    8.20 -_VERSION = 1
    8.21 -_REVISION = 1
    8.22 -
    8.23 +module("tek.class.cgi.post", Class)
    8.24 +_VERSION = "TEK CGI Post Class 1.2"
    8.25  
    8.26  -------------------------------------------------------------------------------
    8.27  -- Decode an URL-encoded string (see RFC 2396)
    8.28 @@ -110,9 +104,7 @@
    8.29  
    8.30  --	POST parser
    8.31  
    8.32 -
    8.33 -local Post = Atom:newclass(getfenv())
    8.34 -
    8.35 +local Post = _M
    8.36  
    8.37  -------------------------------------------------------------------------------
    8.38  -- Read the headers of the next multipart/form-data field
     9.1 --- a/cgi-bin/tek/class/cgi/request.lua	Wed Oct 10 10:53:15 2007 +0200
     9.2 +++ b/cgi-bin/tek/class/cgi/request.lua	Fri Nov 23 01:46:43 2007 +0100
     9.3 @@ -8,31 +8,28 @@
     9.4  --	is read from a stream
     9.5  --
     9.6  
     9.7 -local Atom = require "tek.class.atom"
     9.8 +local Class = require "tek.class"
     9.9  local cgi = require "tek.class.cgi"
    9.10  local post = require "tek.class.cgi.post"
    9.11  
    9.12 -local getfenv, setmetatable = getfenv, setmetatable
    9.13  local getenv, tonumber = os.getenv, tonumber
    9.14  local open, read = io.open, io.read
    9.15  local pairs = pairs
    9.16  local tostring = tostring
    9.17  local io = io
    9.18  
    9.19 -module "tek.class.cgi.request"
    9.20 -
    9.21 -_VERSION = 5
    9.22 -_REVISION = 2
    9.23 +module("tek.class.cgi.request", Class)
    9.24 +_VERSION = "TEK CGI Request Class 5.3"
    9.25  
    9.26  -------------------------------------------------------------------------------
    9.27  --	Request class:
    9.28  -------------------------------------------------------------------------------
    9.29  
    9.30 -local Request = Atom:newclass(getfenv())
    9.31 +local Request = _M
    9.32  
    9.33  function Request.new(class, self)
    9.34  
    9.35 -	self = Atom.new(class, self or { })
    9.36 +	self = Class.new(class, self or { })
    9.37  
    9.38  	self.maxinput = self.maxinput or 1048575
    9.39  	self.maxfilesize = self.maxfilesize or 524288
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/cgi-bin/tek/class/fastcgi.lua	Fri Nov 23 01:46:43 2007 +0100
    10.3 @@ -0,0 +1,373 @@
    10.4 +
    10.5 +--
    10.6 +--	tek.class.fastcgi
    10.7 +--	Written by Timm S. Mueller <tmueller@neoscientists.org>
    10.8 +--
    10.9 +--	Lua FastCGI protocol implementation - specifically written for
   10.10 +--	the "external" server configurations (via IP socket)
   10.11 +--
   10.12 +--	Methods that must be overwritten by the user:
   10.13 +--		fcgi:have_params(req, params) -- all parameters transferred
   10.14 +--
   10.15 +--	Methods that can be overwritten by the user:
   10.16 +--		fcgi:abort(req) -- request aborted by webserver
   10.17 +--		fcgi:update_stream(req, type, stream) -- stream created/updated
   10.18 +--		fcgi:have_stream(req, type, stream) -- stream completed
   10.19 +--
   10.20 +
   10.21 +local Class = require "tek.class"
   10.22 +local socket = require "socket"
   10.23 +local bit = require "bit"
   10.24 +
   10.25 +local insert, remove, concat, pairs, ipairs, error, assert =
   10.26 +	table.insert, table.remove, table.concat, pairs, ipairs, error, assert
   10.27 +local tonumber, setmetatable, unpack, type =
   10.28 +	tonumber, setmetatable, unpack, type
   10.29 +local char = string.char
   10.30 +local math = math
   10.31 +
   10.32 +module("tek.class.fastcgi", Class)
   10.33 +_VERSION = "FastCGI 0.2"
   10.34 +
   10.35 +-------------------------------------------------------------------------------
   10.36 +-- local FIFO class:
   10.37 +-------------------------------------------------------------------------------
   10.38 +
   10.39 +local FIFO = Class:newClass()
   10.40 +
   10.41 +function FIFO.new(class, self)
   10.42 +	self = Class.new(class, self or { })
   10.43 +	self.buf = self.buf or { }
   10.44 +	return self
   10.45 +end
   10.46 +
   10.47 +function FIFO:write(s)
   10.48 +	if s and s ~= -1 then
   10.49 +		insert(self.buf, s)
   10.50 +	elseif self.buf[#self.buf] ~= -1 then
   10.51 +		insert(self.buf, -1) -- EOF
   10.52 +	end
   10.53 +end
   10.54 +
   10.55 +function FIFO:readn(len)
   10.56 +	local t, p, l = { }
   10.57 +	while len > 0 do
   10.58 +		p = remove(self.buf, 1)
   10.59 +		if not p then
   10.60 +			break -- no more data
   10.61 +		end
   10.62 +		if p == -1 then
   10.63 +			insert(self.buf, -1) -- push back EOF
   10.64 +			break -- end of stream, EOF in next turn
   10.65 +		end
   10.66 +		l = p:len()
   10.67 +		if l > len then -- break buffer fragment in two
   10.68 +			insert(t, p:sub(1, len))
   10.69 +			insert(self.buf, 1, p:sub(len + 1))
   10.70 +			break
   10.71 +		end
   10.72 +		insert(t, p)
   10.73 +		len = len - l
   10.74 +	end
   10.75 +	return concat(t)
   10.76 +end
   10.77 +
   10.78 +function FIFO:reada()
   10.79 +	local last = remove(self.buf)
   10.80 +	if last ~= -1 then -- not EOF
   10.81 +		insert(self.buf, last) -- push back
   10.82 +		last = nil
   10.83 +	end
   10.84 +	local s = concat(self.buf)
   10.85 +	self.buf = { last }
   10.86 +	return s
   10.87 +end
   10.88 +
   10.89 +function FIFO:read(...)
   10.90 +	if self.buf[1] == -1 then
   10.91 +		return -- EOF
   10.92 +	end
   10.93 +	local t, s = { }
   10.94 +	for _, what in ipairs(arg) do
   10.95 +		if what == "*a" then
   10.96 +			s = self:reada()
   10.97 +		elseif type(what) == "number" then
   10.98 +			s = self:readn(tonumber(what))
   10.99 +		else
  10.100 +			error("unknwon format")
  10.101 +		end
  10.102 +		insert(t, s)
  10.103 +	end
  10.104 +	return unpack(t)
  10.105 +end
  10.106 +
  10.107 +--	FCGI encoded lengths and key/value pairs:
  10.108 +
  10.109 +function FIFO:readlen()
  10.110 +	local l = self:read(1)
  10.111 +	if not l then return end
  10.112 +	l = l:byte()
  10.113 +	if l < 128 then
  10.114 +		return l
  10.115 +	end
  10.116 +	local t = self:read(3)
  10.117 +	if not t then return end
  10.118 +	return (l % 128) * 16777216 + t:byte(1) * 65536 +
  10.119 +		t:byte(2) * 256 + t:byte(3)
  10.120 +end
  10.121 +
  10.122 +function FIFO:readkeyvals()
  10.123 +	local t = { }
  10.124 +	local l1, l2, key, val
  10.125 +	while true do
  10.126 +		l1 = self:readlen()
  10.127 +		if not l1 then break end
  10.128 +		l2 = self:readlen()
  10.129 +		if not l2 then break end
  10.130 + 		key = self:read(l1)
  10.131 + 		val = self:read(l2)
  10.132 +		t[key] = val
  10.133 +	end
  10.134 +	return t
  10.135 +end
  10.136 +
  10.137 +-------------------------------------------------------------------------------
  10.138 +-- FCGI class:
  10.139 +-------------------------------------------------------------------------------
  10.140 +
  10.141 +FCGI_BEGIN_REQUEST = 1
  10.142 +FCGI_ABORT_REQUEST = 2
  10.143 +FCGI_END_REQUEST = 3
  10.144 +FCGI_PARAMS = 4
  10.145 +FCGI_STDIN = 5
  10.146 +FCGI_STDOUT = 6
  10.147 +FCGI_STDERR = 7
  10.148 +FCGI_DATA = 8
  10.149 +FCGI_GET_VALUES = 9
  10.150 +FCGI_GET_VALUES_RESULT = 10
  10.151 +FCGI_UNKNOWN_TYPE = 11
  10.152 +
  10.153 +local FCGI_RESPONDER = 1
  10.154 +local FCGI_REQUEST_COMPLETE = 0
  10.155 +local FCGI_UNKNOWN_ROLE = 3
  10.156 +
  10.157 +local function encodelen(buf, l)
  10.158 +	if l > 127 then
  10.159 +		insert(buf, char(bit.rshift(bit.band(l, 0x7f000000), 24) + 128))
  10.160 +		insert(buf, char(bit.rshift(bit.band(l, 0x00ff0000), 16)))
  10.161 +		insert(buf, char(bit.rshift(bit.band(l, 0x0000ff00), 8)))
  10.162 +	end
  10.163 +	insert(buf, char(bit.band(l, 0xff)))
  10.164 +end
  10.165 +
  10.166 +local function encodekeyvals(t)
  10.167 +	local buf = { }
  10.168 +	for key, val in pairs(t) do
  10.169 +		encodelen(buf, key:len())
  10.170 +		encodelen(buf, val:len())
  10.171 +		insert(buf, key)
  10.172 +		insert(buf, val)
  10.173 +	end
  10.174 +	return concat(buf)
  10.175 +end
  10.176 +
  10.177 +-- local FCGI = Class:newClass(_M)
  10.178 +local FCGI = _M
  10.179 +
  10.180 +function FCGI.new(class, self)
  10.181 +	self = Class.new(class, self or { })
  10.182 +	self.requests = { }
  10.183 +	return self
  10.184 +end
  10.185 +
  10.186 +function FCGI:readrecord()
  10.187 +	local t, err = self.socket:receive(8)
  10.188 +	if not t then return end
  10.189 +	if err then error(err) end
  10.190 +	local r = {
  10.191 +		ver = t:byte(1),
  10.192 +		type = t:byte(2),
  10.193 +		id = t:byte(3) * 256 + t:byte(4),
  10.194 +		len = t:byte(5) * 256 + t:byte(6)
  10.195 +	}
  10.196 +	if r.len == 0 then
  10.197 +		r.content = ""
  10.198 +	else
  10.199 +		r.content, err = self.socket:receive(r.len)
  10.200 +		if not r.content then return end
  10.201 +		if err then error(err) end
  10.202 +	end
  10.203 +	local pad = t:byte(7)
  10.204 +	if pad > 0 then
  10.205 +		t, err = self.socket:receive(pad)
  10.206 +		if not t then return end
  10.207 +		if err then error(err) end
  10.208 +	end
  10.209 +	return r
  10.210 +end
  10.211 +
  10.212 +function FCGI:write(type, id, s)
  10.213 +	local totlen = s:len()
  10.214 +	local totpos = 1
  10.215 +	while totlen > 0 do
  10.216 +		local len = math.min(totlen, 65535)
  10.217 +		local buf = concat {
  10.218 +			char(1), -- version
  10.219 +			char(type), -- type
  10.220 +			char(bit.rshift(id, 8)), -- id1
  10.221 +			char(id % 256), -- id0
  10.222 +			char(bit.rshift(len, 8)), -- len1
  10.223 +			char(len % 256), -- len0
  10.224 +			char(0), -- pad = 0
  10.225 +			char(0), -- reserved
  10.226 +			s:sub(totpos, totpos + len - 1) -- content
  10.227 +		}
  10.228 +		totpos = totpos + len
  10.229 +		totlen = totlen - len
  10.230 +
  10.231 +		len = buf:len()
  10.232 +		local pos, res, err = 1
  10.233 +		while pos <= len do
  10.234 +			res, err = self.socket:send(buf, pos)
  10.235 +			if not res then
  10.236 +				return nil, err
  10.237 +			end
  10.238 +			pos = res + 1
  10.239 +		end
  10.240 +	end
  10.241 +	return true
  10.242 +end
  10.243 +
  10.244 +function FCGI:write_stdout(id, s)
  10.245 +	return self:write(FCGI_STDOUT, id, s)
  10.246 +end
  10.247 +
  10.248 +function FCGI:collectstream(r)
  10.249 +	local req = self.requests[r.id]
  10.250 +	local s = req.streams[r.type]
  10.251 +	if not s then
  10.252 +		s = FIFO:new()
  10.253 +		req.streams[r.type] = s
  10.254 +	end
  10.255 +	if r.len == 0 then
  10.256 +		s:write() -- append EOF
  10.257 +		return s, true -- finished
  10.258 +	end
  10.259 +	s:write(r.content)
  10.260 +	return s
  10.261 +end
  10.262 +
  10.263 +function FCGI:endrequest(req, protstatus, appstatus)
  10.264 +	protstatus = protstatus or req.protstatus or FCGI_REQUEST_COMPLETE
  10.265 +	appstatus = appstatus or req.appstatus or 0
  10.266 +	self.requests[req.id] = nil -- delete request
  10.267 +	return self:write(FCGI_END_REQUEST, req.id, concat {
  10.268 +		char(bit.rshift(bit.band(appstatus, 0x7f000000), 24)),
  10.269 +		char(bit.rshift(bit.band(appstatus, 0x00ff0000), 16)),
  10.270 +		char(bit.rshift(bit.band(appstatus, 0x0000ff00), 8)),
  10.271 +		char(bit.band(appstatus, 0xff)),
  10.272 +		char(protstatus),
  10.273 +		char(0), char(0), char(0)
  10.274 +	})
  10.275 +end
  10.276 +
  10.277 +function FCGI:newrequest(id, role, flags)
  10.278 +	assert(not self.requests[id])
  10.279 +	local req = { id = id, role = role, flags = flags, streams = { } }
  10.280 +	self.requests[id] = req
  10.281 +	return req
  10.282 +end
  10.283 +
  10.284 +function FCGI:processrecord(r)
  10.285 +
  10.286 +	local c = r.content
  10.287 +	local req = self.requests[r.id]
  10.288 +
  10.289 +	if r.type == FCGI_BEGIN_REQUEST then
  10.290 +		assert(not req)
  10.291 +		local role = c:byte(1) * 256 + c:byte(2)
  10.292 +		if role == FCGI_RESPONDER then
  10.293 +			-- new request
  10.294 +			local flags = c:byte(3)
  10.295 +			req = self:newrequest(r.id, role, flags)
  10.296 +			return true -- continue
  10.297 +		end
  10.298 +		-- unknown role
  10.299 +		return self:endrequest(req, FCGI_UNKNOWN_ROLE)
  10.300 +	end
  10.301 +
  10.302 +	if not req then -- request already closed
  10.303 +		return true -- continue
  10.304 +	end
  10.305 +
  10.306 +	if r.type == FCGI_ABORT_REQUEST then
  10.307 +		return self:abortrequest(req)
  10.308 +
  10.309 +	elseif r.type == FCGI_GET_VALUES then
  10.310 +		local s, fin = self:collectstream(r)
  10.311 +		if s and fin then
  10.312 +			local res = { }
  10.313 +			for k in pairs(s:readkeyvals()) do
  10.314 +				if k == "FCGI_MAX_CONNS" then
  10.315 +					res.FCGI_MAX_CONNS = "16"
  10.316 +				elseif k == "FCGI_MAX_REQS" then
  10.317 +					res.FCGI_MAX_CONNS = "32"
  10.318 +				elseif k == "FCGI_MAX_REQS" then
  10.319 +					res.FCGI_MAX_CONNS = "1"
  10.320 +				end
  10.321 +			end
  10.322 +			res = encodekeyvals(res)
  10.323 +			return self:write(FCGI_GET_VALUES_RESULT, 0, res)
  10.324 +		end
  10.325 +
  10.326 +	elseif r.type == FCGI_PARAMS then
  10.327 +		local s, fin = self:collectstream(r)
  10.328 +		if s and fin then
  10.329 +			req.params = s:readkeyvals()
  10.330 +			return self:have_params(req, req.params)
  10.331 +		end
  10.332 +
  10.333 +	elseif r.type == self.FCGI_STDIN or r.type == self.FCGI_DATA then
  10.334 +		local s, fin = self:collectstream(r)
  10.335 +		if fin then
  10.336 +			if self.have_stream then
  10.337 +				return self:have_stream(req, r.type, s)
  10.338 +			end
  10.339 +		else
  10.340 +			if self.update_stream then
  10.341 +				return self:update_stream(req, r.type, s)
  10.342 +			end
  10.343 +		end
  10.344 +
  10.345 +	else
  10.346 +		-- unknown record
  10.347 +		local buf = char(r.type) .. char(0):rep(7)
  10.348 +		return self:write(FCGI_UNKNOWN_TYPE, 0, buf)
  10.349 +	end
  10.350 +
  10.351 +	return true -- continue
  10.352 +end
  10.353 +
  10.354 +function FCGI:serve(socket)
  10.355 +	assert(socket)
  10.356 +	self.socket = socket
  10.357 +	self.serve = true
  10.358 +	while self.serve do
  10.359 +		local r = self:readrecord()
  10.360 +		if not r then
  10.361 +			break
  10.362 +		end
  10.363 +		if not self:processrecord(r) then
  10.364 +			break
  10.365 +		end
  10.366 +	end
  10.367 +end
  10.368 +
  10.369 +function FCGI:stop()
  10.370 +	self.serve = false
  10.371 +end
  10.372 +
  10.373 +function FCGI:abortrequest(req)
  10.374 +	-- request aborted by webserver, confirm:
  10.375 +	return self:endrequest(req)
  10.376 +end
    11.1 --- a/cgi-bin/tek/class/loona.lua	Wed Oct 10 10:53:15 2007 +0200
    11.2 +++ b/cgi-bin/tek/class/loona.lua	Fri Nov 23 01:46:43 2007 +0100
    11.3 @@ -5,7 +5,7 @@
    11.4  --	See copyright notice in COPYRIGHT
    11.5  --
    11.6  
    11.7 -local Atom = require "tek.class.atom"
    11.8 +local Class = require "tek.class"
    11.9  local lib = require "tek.lib"
   11.10  local luahtml = require "tek.lib.luahtml"
   11.11  local posix = require "tek.os.posix"
   11.12 @@ -26,30 +26,28 @@
   11.13  	xpcall = xpcall
   11.14  }
   11.15  
   11.16 -local table, string, assert, unpack, ipairs, pairs, type, require =
   11.17 -	table, string, assert, unpack, ipairs, pairs, type, require
   11.18 -local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv
   11.19 +local table, string, assert, unpack, ipairs, pairs, type, require, setfenv =
   11.20 +	table, string, assert, unpack, ipairs, pairs, type, require, setfenv
   11.21  local open, remove, rename, getenv, time, date =
   11.22  	io.open, os.remove, os.rename, os.getenv, os.time, os.date
   11.23 +local setmetatable = setmetatable
   11.24  
   11.25  -------------------------------------------------------------------------------
   11.26  --	Module setup:
   11.27  -------------------------------------------------------------------------------
   11.28  
   11.29 -module "tek.class.loona"
   11.30 -
   11.31 -_VERSION = 4
   11.32 -_REVISION = 4
   11.33 +module("tek.class.loona", Class)
   11.34 +_VERSION = "LOona Class 5.0"
   11.35  
   11.36  -------------------------------------------------------------------------------
   11.37  --	class Session:
   11.38  -------------------------------------------------------------------------------
   11.39  
   11.40 -local Session = Atom:newclass()
   11.41 +local Session = Class:newClass()
   11.42  
   11.43  function Session.new(class, self)
   11.44  
   11.45 -	self = Atom.new(class, self or { })
   11.46 +	self = Class.new(class, self or { })
   11.47  
   11.48  	assert(self.id, "No session Id")
   11.49   	assert(self.sessiondir, "No session directory")
   11.50 @@ -83,7 +81,7 @@
   11.51  --	class Loona
   11.52  -------------------------------------------------------------------------------
   11.53  
   11.54 -local Loona = Atom:newclass(getfenv())
   11.55 +local Loona = _M
   11.56  
   11.57  
   11.58  function Loona:dbmsg(msg, detail)
   11.59 @@ -251,8 +249,20 @@
   11.60  
   11.61  
   11.62  function Loona:indexsections()
   11.63 +	local userperm = self.session and self.session.data.permissions
   11.64 +	userperm = userperm and userperm ~= "" and "[" .. userperm .. "]"
   11.65  	self:recursesections(self.sections, function(self, s, e)
   11.66 -		e.notvalid = (not self.secure and e.secure) or
   11.67 +		local permitted = true
   11.68 +		local sectperm = e.permissions
   11.69 +		if sectperm and sectperm ~= "" then
   11.70 +			permitted = false
   11.71 +			if userperm then
   11.72 +				local num = sectperm:len()
   11.73 +				sectperm:gsub(userperm, function() num = num - 1 end)
   11.74 +				permitted = num == 0
   11.75 +			end
   11.76 +		end
   11.77 +		e.notvalid = not permitted or (not self.secure and e.secure) or
   11.78  			(not self.authuser_visible and e.secret) or nil
   11.79  		e.notvisible = e.notvalid or not self.authuser_visible and e.hidden or nil
   11.80  		s[e.name] = e
   11.81 @@ -703,8 +713,8 @@
   11.82  	local contentdir = self.contentdir
   11.83  	local edit, show, hidden, extramsg, changed
   11.84  
   11.85 -	if self.authuser_edit or self.authuser_profile or self.authuser_modifyprofile or self_authuser_attr
   11.86 -		or self.authuser_menu then
   11.87 +	if self.authuser_edit or self.authuser_profile or
   11.88 +		self.authuser_modifyprofile or self.authuser_menu then
   11.89  
   11.90  		local hiddenvars = table.concat( {
   11.91  			self:hidden("lang", self.args.lang),
   11.92 @@ -796,6 +806,14 @@
   11.93  						</tr>
   11.94  						<tr>
   11.95  							<td align="right">
   11.96 +								]] .. self.locale.PERMISSIONS .. [[
   11.97 +							</td>
   11.98 +							<td>
   11.99 +								<input size="30" maxlength="50" name="editpermissions" />
  11.100 +							</td>
  11.101 +						</tr>
  11.102 +						<tr>
  11.103 +							<td align="right">
  11.104  								]] .. self.locale.REDIRECT .. [[
  11.105  							</td>
  11.106  							<td>
  11.107 @@ -810,7 +828,8 @@
  11.108  			<hr />
  11.109  			]])
  11.110  
  11.111 -		elseif self.args.actioneditprops and editkey == "main" and self.authuser_attr then
  11.112 +		elseif self.args.actioneditprops and editkey == "main" and
  11.113 +			self.authuser_menu then
  11.114  			hidden = true
  11.115  			if self.ispubprofile then
  11.116  				self:out([[<h2><span class="warn">]] .. self.locale.WARNING_YOU_ARE_IN_PUBLISHED_PROFILE ..[[</span></h2>]])
  11.117 @@ -864,6 +883,14 @@
  11.118  						</tr>
  11.119  						<tr>
  11.120  							<td align="right">
  11.121 +								]] .. self.locale.PERMISSIONS .. [[
  11.122 +							</td>
  11.123 +							<td>
  11.124 +								<input size="30" maxlength="50" name="editpermissions" value="]] .. (self.section.permissions or "") .. [[" />
  11.125 +							</td>
  11.126 +						</tr>
  11.127 +						<tr>
  11.128 +							<td align="right">
  11.129  								]] .. self.locale.REDIRECT .. [[
  11.130  							</td>
  11.131  							<td>
  11.132 @@ -1084,7 +1111,7 @@
  11.133  		end)
  11.134  	end
  11.135  
  11.136 -	if self.authuser_profile or self.authuser_edit or self.authuser_menu or self.authuser_attr then
  11.137 +	if self.authuser_profile or self.authuser_edit or self.authuser_menu then
  11.138  		self:out([[
  11.139  		<hr />
  11.140  		<div class="edit">]])
  11.141 @@ -1107,7 +1134,7 @@
  11.142  				if self.authuser_edit then
  11.143  					self:out('- ' .. self:uilink(self.sectionpath, "[" .. self.locale.EDIT .. "]", "actionedit=true", "editkey=" .. editkey) .. " ")
  11.144  				end
  11.145 -				if editkey == "main" and self.authuser_attr then
  11.146 +				if editkey == "main" and self.authuser_menu then
  11.147  					self:out('- ' .. self:uilink(self.sectionpath, "[" .. self.locale.PROPERTIES .. "]", "actioneditprops=true", "editkey=" .. editkey) .. " ")
  11.148  				end
  11.149  				if (fname == savename or not self.section.subs) and (self.authuser_edit and self.authuser_menu) then
  11.150 @@ -1272,6 +1299,8 @@
  11.151  						self.args.edittitle or nil,
  11.152  					redirect = self.args.editredirect ~= "" and
  11.153  						self.args.editredirect or nil,
  11.154 +					permissions = self.args.editpermissions ~= "" and
  11.155 +						self.args.editpermissions or nil,
  11.156  					hidden = self.args.editvisibility and true,
  11.157  					secret = self.args.editsecrecy and true,
  11.158  					secure = self.args.editsecure and true,
  11.159 @@ -1301,6 +1330,8 @@
  11.160  				self.args.edittitle or nil
  11.161  			self.section.redirect =
  11.162  				self.args.editredirect ~= "" and self.args.editredirect or nil
  11.163 +			self.section.permissions =
  11.164 +				self.args.editpermisisons ~= "" and self.args.editpermissions or nil
  11.165  			save = true
  11.166  
  11.167  		elseif self.args.actionup then
  11.168 @@ -1523,7 +1554,7 @@
  11.169  
  11.170  function Loona.new(class, self)
  11.171  
  11.172 -	self = Atom.new(class, self or { })
  11.173 +	self = Class.new(class, self or { })
  11.174  
  11.175  	local parsed, msg
  11.176  
  11.177 @@ -1625,22 +1656,24 @@
  11.178  	else
  11.179  		self.authuser_edit = self.session.data.permissions:find("e") and true
  11.180  		self.authuser_menu = self.session.data.permissions:find("m") and true
  11.181 -		self.authuser_attr = self.session.data.permissions:find("a") and true
  11.182  		self.authuser_profile = self.session.data.permissions:find("p") and true
  11.183  		self.authuser_modifyprofile = self.session.data.permissions:find("c") and true
  11.184  		self.authuser_visible = self.session.data.permissions:find("v") and true
  11.185  		self.authuser_debug = self.session.data.permissions:find("d") and true
  11.186  	end
  11.187  
  11.188 +
  11.189  	-- Get lang, locale, profile, section
  11.190  
  11.191  	self:init()
  11.192 +
  11.193  	if self.authuser then -- TODO?
  11.194  		self:handlechanges()
  11.195  	else
  11.196  		self.args.profile = nil
  11.197  	end
  11.198  
  11.199 +
  11.200  	-- Current document
  11.201  
  11.202  	self.document = self.requestdocument .. "/" .. self.sectionpath
    12.1 --- a/cgi-bin/tek/class/loona/buffer.lua	Wed Oct 10 10:53:15 2007 +0200
    12.2 +++ b/cgi-bin/tek/class/loona/buffer.lua	Fri Nov 23 01:46:43 2007 +0100
    12.3 @@ -5,24 +5,21 @@
    12.4  --	See copyright notice in COPYRIGHT
    12.5  --
    12.6  
    12.7 -local Atom = require "tek.class.atom"
    12.8 +local Class = require "tek.class"
    12.9  
   12.10 -local getfenv, setmetatable, unpack, insert, stdout =
   12.11 -	getfenv, setmetatable, unpack, table.insert, io.stdout
   12.12 +local unpack, insert, stdout = unpack, table.insert, io.stdout
   12.13  
   12.14 -module "tek.class.loona.buffer"
   12.15 -
   12.16 -_VERSION = 2
   12.17 -_REVISION = 0
   12.18 +module("tek.class.loona.buffer", Class)
   12.19 +_VERSION = "LOona Buffer Class 2.1"
   12.20  
   12.21  -------------------------------------------------------------------------------
   12.22  --	Buffer class:
   12.23  -------------------------------------------------------------------------------
   12.24  
   12.25 -local Buffer = Atom:newclass(getfenv())
   12.26 +local Buffer = _M
   12.27  
   12.28  function Buffer.new(class, self)
   12.29 -	self = Atom.new(class, self or { })
   12.30 +	self = Class.new(class, self or { })
   12.31  	self.outbuf = self.outbuf or { }
   12.32  	self.headerbuf = self.headerbuf or { }
   12.33  	return self
    13.1 --- a/cgi-bin/tek/class/loona/markup.lua	Wed Oct 10 10:53:15 2007 +0200
    13.2 +++ b/cgi-bin/tek/class/loona/markup.lua	Fri Nov 23 01:46:43 2007 +0100
    13.3 @@ -14,10 +14,7 @@
    13.4  
    13.5  
    13.6  module "tek.class.loona.markup"
    13.7 -
    13.8 -
    13.9 -_VERSION = 2
   13.10 -_REVISION = 0
   13.11 +_VERSION = "LOona markup parser 2.1"
   13.12  
   13.13  
   13.14  --	iterate over lines in a string
    14.1 --- a/cgi-bin/tek/class/loona/util.lua	Wed Oct 10 10:53:15 2007 +0200
    14.2 +++ b/cgi-bin/tek/class/loona/util.lua	Fri Nov 23 01:46:43 2007 +0100
    14.3 @@ -13,10 +13,7 @@
    14.4  
    14.5  
    14.6  module "tek.class.loona.util"
    14.7 -
    14.8 -
    14.9 -_VERSION = 4
   14.10 -_REVISION = 0
   14.11 +_VERSION = "LOona utilities 4.1"
   14.12  
   14.13  
   14.14  --	Directory iterator
    15.1 --- a/cgi-bin/tek/lib.lua	Wed Oct 10 10:53:15 2007 +0200
    15.2 +++ b/cgi-bin/tek/lib.lua	Fri Nov 23 01:46:43 2007 +0100
    15.3 @@ -12,10 +12,7 @@
    15.4  
    15.5  
    15.6  module "tek.lib"
    15.7 -
    15.8 -
    15.9 -_VERSION = 1
   15.10 -_REVISION = 1
   15.11 +_VERSION = "TEK library 1.2"
   15.12  
   15.13  
   15.14  -------------------------------------------------------------------------------
   15.15 @@ -135,7 +132,7 @@
   15.16  				serialize(val, sorted, indent + 1, outfunc, saved)
   15.17  				outfunc(is .. '},\n')
   15.18  			elseif t == "string" then
   15.19 -				outfunc('"' .. val:gsub('([%z\001-\031"])', function(c)
   15.20 +				outfunc('"' .. val:gsub('([%z\001-\031\092"])', function(c)
   15.21  					return ("\\%03d"):format(c:byte())
   15.22  				end) .. '",\n')
   15.23  			elseif t == "number" or t == "boolean" then
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/cgi-bin/tek/lib/debug.lua	Fri Nov 23 01:46:43 2007 +0100
    16.3 @@ -0,0 +1,54 @@
    16.4 +
    16.5 +--
    16.6 +--	tek.lib.debug
    16.7 +--	Written by Timm S. Mueller <tmueller at neoscientists.org>
    16.8 +--	See copyright notice in COPYRIGHT
    16.9 +--
   16.10 +
   16.11 +local getinfo = require "debug".getinfo
   16.12 +local date = require "os".date
   16.13 +local stderr = require "io".stderr
   16.14 +local tostring = tostring
   16.15 +local ipairs = ipairs
   16.16 +local type = type
   16.17 +local unpack = unpack
   16.18 +
   16.19 +module "tek.lib.debug"
   16.20 +
   16.21 +level = 10 -- global default
   16.22 +
   16.23 +function print(lvl, msg, ...)
   16.24 +	if level and lvl >= level then
   16.25 +		local t = getinfo(3, "lS")
   16.26 +		local arg = { }
   16.27 +		for i, v in ipairs { ... } do
   16.28 +			arg[i] = type(v) == "table" and tostring(v) or v
   16.29 +		end
   16.30 +		stderr:write(("(%02d %s:%d) %s\n"):format(lvl,
   16.31 +			t.short_src, t.currentline, msg:format(unpack(arg))))
   16.32 +	end
   16.33 +end
   16.34 +
   16.35 +function debug(msg, ...)
   16.36 +	print(1, msg, ...)
   16.37 +end
   16.38 +
   16.39 +function trace(msg, ...)
   16.40 +	print(2, msg, ...)
   16.41 +end
   16.42 +
   16.43 +function info(msg, ...)
   16.44 +	print(4, msg, ...)
   16.45 +end
   16.46 +
   16.47 +function warn(msg, ...)
   16.48 +	print(5, msg, ...)
   16.49 +end
   16.50 +
   16.51 +function error(msg, ...)
   16.52 +	print(10, msg, ...)
   16.53 +end
   16.54 +
   16.55 +function fail(msg, ...)
   16.56 +	print(20, msg, ...)
   16.57 +end
    17.1 --- a/etc/passwd.lua.sample	Wed Oct 10 10:53:15 2007 +0200
    17.2 +++ b/etc/passwd.lua.sample	Fri Nov 23 01:46:43 2007 +0100
    17.3 @@ -14,6 +14,6 @@
    17.4  --
    17.5  -------------------------------------------------------------------------------
    17.6  
    17.7 ---	admin = { username = "admin", password = "blafasel", permissions = "emapcvd" }
    17.8 ---	foo = { username = "foo", password = "bar", permisisons = "vd" },
    17.9 +--	admin = { username = "admin", password = "blafasel", permissions = "emapcvd" };
   17.10 +--	foo = { username = "foo", password = "bar", permisisons = "vd" };
   17.11  
    18.1 --- a/htdocs/index.lua	Wed Oct 10 10:53:15 2007 +0200
    18.2 +++ b/htdocs/index.lua	Fri Nov 23 01:46:43 2007 +0100
    18.3 @@ -56,7 +56,6 @@
    18.4  		</div>
    18.5  		<%if loona.authuser then%>
    18.6  			<div id="debug">
    18.7 -				Page took <%=os.clock()%>s to generate<br />
    18.8  				<a href="http://validator.w3.org/check?uri=referer"><img
    18.9  					src="http://www.w3.org/Icons/valid-xhtml10"
   18.10  					alt="Valid XHTML 1.0 Strict" height="31" width="88" /></a>