Cgi Utils

lua-users home
Wiki

CGI 標頭

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

剖析 POST 變數

-- 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

此實作在不同面向來說都有危險性

以下是比較好的範例,但仍然無法處理「搜尋」案例。您必須提供一個新構造,包含合法 key 的表格;如果一個 key 可以有多個值,您將一個表格提供為關聯值(填入內容),否則提供預設值(或 false)。不合法 key 將會被略過或拋出錯誤。沒有 = 的區段將會拋出錯誤。錯誤會被拋出是因為無效的查詢或張貼文字串極有可能是攻擊嘗試,而且(在我看來)應該予以拒絕;結果,您應該將 CGI 處理程式包裝在 pcall 中,並傳回 403404 錯誤給瀏覽器。

這個函式故意不會嘗試對 key 進行 %-解碼,基礎在於有效的 key 永不應該需要 %-編碼,因此該表格的 URL 很可能是要攻擊伺服器的不明企圖。

可能的加強方式包括:在初始表格將數字設為預設值時,也檢查提供的數值是否為數字。

-- 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

剖析 GET 變數

str = os.getenv("QUERY_STRING")
...

處理 SCGI 要求

-- 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

httpd.conf(Apache 2)中的下列幾行將允許這個 SCGI 範例運作 - 雖然 127.0.0.1 需要改為更適當的 IP 位址。

LoadModule scgi_module modules/mod_scgi.so
SCGIMount /dynamic 127.0.0.1:4000

RecentChanges · 偏好設定
編輯 · 歷程
最後編輯時間:2007 年 11 月 13 日上午 12:13 GMT (diff)