Cgi Utils

lua-users home
wiki

CGI Header

print"Content-type: text/html; charset=iso-8859-1\r\n\r\n"

Parse POST variables

-- Written by RiciLake.

-- The author places the code into the public domain, renouncing all rights and responsibilities.

-- Don't use this in a real application, see notes below.

function parsecgi(str)

  local rv = {}

  for pair in str:gmatch"[^&]+" do

    local key, val = pair:match"([^=]*)=(.*)"

    if key then rv[key] = val end

  end

  return rv

end

This implementation is dangerous in various ways:

So here's a slightly better one, which still doesn't handle the "search" case. You have to give it a freshly constructed table of legal keys; if a key can have multiple values, you provide a table as the associated value (which is filled in), and otherwise you provide the default value (or false). Illegal keys are either ignored or throw errors. Segments without an = throw an error. Errors are thrown because invalid query/post strings are most likely to be attack attempts, and ought (in my opinion) to be rejected; consequently, you should wrap your CGI handler in a pcall and return a 403 or 404 error to the browser.

The function deliberately does not attempt to %-decode keys, on the basis that a valid key should never need to be %-encoded and consequently a URL of that form is likely to be an obscure attempt to attack the server.

A possible enhancement would be to also check that the supplied value is numeric in the case that the initial table has a number as the default value.

-- Written by RiciLake.

-- The author places the code into the public domain, renouncing all rights and responsibilities.

-- Replace + with space and %xx with the corresponding character.

local function cgidecode(str)

  return (str:gsub('+', ' '):gsub("%%(%x%x)", function(xx) return string.char(tonumber(xx, 16)) end))

end



-- Main function

-- Sample invocation:  cgivals = parsecgi(str, {count = 10, start = 1, names = {}})

function parsecgi(str, keys, ignore_invalid)

  local keyfound = {}

  for pair in str:gmatch"[^&]+" do

    local key, val = pair:match"([^=]*)=(.*)"

    if not key then error"Invalid query string" end

    local default = keys[key]

    if default == nil then

      if not ignore_invalid then error"Invalid query string" end

    else

      if type(default) == "table" then default[#default+1] = cgidecode(val)

      elseif keyfound[key] then error"Invalid query string"

      else

        keyfound[key] = true

        keys[key] = cgidecode(val)

      end

    end

  end

  return keys

end

Parse GET variables

str = os.getenv("QUERY_STRING")

...

Handle SCGI Requests

-- Assigns header information to variable "l", and returns "Hello!" back as the webpage content.

-- This could use some cleaning up - error checking, removal of repetition, improved scoping.



-- The SCGI protocol has the HTTP requests forwarded to a specified port (default 4000), with

-- headers passed directly through TCP (and an ASCII string length prefix followed by a ":", 

-- with the key-value pairs of the header seperated by null characters "\0")



-- With no parsing, this code handles about 950 requests per second on a 2 year old laptop.



local socket = require("socket")

local host = host or "*"

local port = port or 4000

local s = assert(socket.bind(host, port))

local i, p   = s:getsockname()

assert(i, p)

print("Waiting on " .. i .. ":" .. p .. "...")

while 1 do

  c = assert(s:accept())

  print("Connection requested.")

  len = ""

  l, e = c:receive(1)

  while not e do

    if l == ":" then header_len = tonumber(len) ; break end

    len = len .. l

    l, e = c:receive(1)

  end

  l,e = c:receive(header_len)

  c:send("Status: 200 OK\r\n")

  c:send("Content-Type: text/plain\r\n")

  c:send("\r\n")

  c:send("Hello!")

  c:close()

end

The following lines in httpd.conf (Apache 2) will allow this SCGI example to function - although 127.0.0.1 will need to be changed to a more suitable IP address.

LoadModule scgi_module modules/mod_scgi.so

SCGIMount /dynamic 127.0.0.1:4000


RecentChanges · preferences
edit · history
Last edited November 12, 2007 11:13 pm GMT (diff)