webmcp

diff libraries/rocketcgi/rocketcgi.lua @ 0:9fdfb27f8e67

Version 1.0.0
author jbe/bsw
date Sun Oct 25 12:00:00 2009 +0100 (2009-10-25)
parents
children 72860d232f32
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libraries/rocketcgi/rocketcgi.lua	Sun Oct 25 12:00:00 2009 +0100
     1.3 @@ -0,0 +1,219 @@
     1.4 +#!/usr/bin/env lua
     1.5 +
     1.6 +local assert       = assert
     1.7 +local error        = error
     1.8 +local getfenv      = getfenv
     1.9 +local getmetatable = getmetatable
    1.10 +local ipairs       = ipairs
    1.11 +local next         = next
    1.12 +local pairs        = pairs
    1.13 +local pcall        = pcall
    1.14 +local print        = print
    1.15 +local rawequal     = rawequal
    1.16 +local rawget       = rawget
    1.17 +local rawset       = rawset
    1.18 +local select       = select
    1.19 +local setfenv      = setfenv
    1.20 +local setmetatable = setmetatable
    1.21 +local tonumber     = tonumber
    1.22 +local tostring     = tostring
    1.23 +local type         = type
    1.24 +local unpack       = unpack
    1.25 +local xpcall       = xpcall
    1.26 +
    1.27 +local io     = io
    1.28 +local math   = math
    1.29 +local os     = os
    1.30 +local string = string
    1.31 +local table  = table
    1.32 +
    1.33 +module(...)
    1.34 +
    1.35 +data_sent = false
    1.36 +
    1.37 +function add_header(...)
    1.38 +  if data_sent then
    1.39 +    error("Can not add header after data has been sent.", 2)
    1.40 +  end
    1.41 +  io.stdout:write(...)
    1.42 +  io.stdout:write("\r\n")
    1.43 +end
    1.44 +
    1.45 +function send_data(...)
    1.46 +  if not data_sent then
    1.47 +    io.stdout:write("\r\n")
    1.48 +    data_sent = true
    1.49 +  end
    1.50 +  io.stdout:write(...)
    1.51 +end
    1.52 +
    1.53 +function set_status(status)
    1.54 +  add_header("Status: ", status)
    1.55 +end
    1.56 +
    1.57 +function redirect(location)
    1.58 +  set_status("303 See Other")
    1.59 +  add_header("Location: ", location)
    1.60 +end
    1.61 +
    1.62 +function set_content_type(content_type)
    1.63 +  add_header("Content-Type: ", content_type)
    1.64 +end
    1.65 +
    1.66 +method = os.getenv("REQUEST_METHOD") or false
    1.67 +query = os.getenv("QUERY_STRING") or false
    1.68 +cookie_data = os.getenv("HTTP_COOKIE") or false
    1.69 +post_data = io.stdin:read("*a") or false
    1.70 +post_contenttype = os.getenv("CONTENT_TYPE") or false
    1.71 +params = {}
    1.72 +get_params = {}
    1.73 +cookies = {}
    1.74 +post_params = {}
    1.75 +post_filenames = {}
    1.76 +post_types = {}
    1.77 +
    1.78 +local urldecode
    1.79 +do
    1.80 +  local b0 = string.byte("0")
    1.81 +  local b9 = string.byte("9")
    1.82 +  local bA = string.byte("A")
    1.83 +  local bF = string.byte("F")
    1.84 +  local ba = string.byte("a")
    1.85 +  local bf = string.byte("f")
    1.86 +  function urldecode(str)
    1.87 +    return (
    1.88 +      string.gsub(
    1.89 +        string.gsub(str, "%+", " "),
    1.90 +        "%%([0-9A-Fa-f][0-9A-Fa-f])",
    1.91 +        function(hex)
    1.92 +          local n1, n2 = string.byte(hex, 1, 2)
    1.93 +          if n1 >= b0 and n1 <= b9 then n1 = n1 - b0
    1.94 +          elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10
    1.95 +          elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10
    1.96 +          else return end
    1.97 +          if n2 >= b0 and n2 <= b9 then n2 = n2 - b0
    1.98 +          elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10
    1.99 +          elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10
   1.100 +          else return end
   1.101 +          return string.char(n1 * 16 + n2)
   1.102 +        end
   1.103 +      )
   1.104 +    )
   1.105 +  end
   1.106 +end
   1.107 +
   1.108 +local function proc_param(tbl, key, value)
   1.109 +  if string.find(key, "%[%]$") then
   1.110 +    if tbl[key] then
   1.111 +      table.insert(tbl[key], value)
   1.112 +    else
   1.113 +      local list = { value }
   1.114 +      params[key] = list
   1.115 +      tbl[key] = list
   1.116 +    end
   1.117 +  else
   1.118 +    params[key] = value
   1.119 +    tbl[key] = value
   1.120 +  end
   1.121 +end
   1.122 +
   1.123 +local function read_urlencoded_form(tbl, data)
   1.124 +  for rawkey, rawvalue in string.gmatch(data, "([^=&]*)=([^=&]*)") do
   1.125 +    proc_param(tbl, urldecode(rawkey), urldecode(rawvalue))
   1.126 +  end
   1.127 +end
   1.128 +
   1.129 +if query then
   1.130 +  read_urlencoded_form(get_params, query)
   1.131 +end
   1.132 +
   1.133 +if cookie_data then
   1.134 +  for rawkey, rawvalue in string.gmatch(cookie_data, "([^=; ]*)=([^=; ]*)") do
   1.135 +    cookies[urldecode(rawkey)] = urldecode(rawvalue)
   1.136 +  end
   1.137 +end
   1.138 +
   1.139 +if post_contenttype == "application/x-www-form-urlencoded" then
   1.140 +  read_urlencoded_form(post_params, post_data)
   1.141 +elseif post_contenttype then
   1.142 +  local boundary = string.match(
   1.143 +    post_contenttype,
   1.144 +    '^multipart/form%-data[ \t]*;[ \t]*boundary="([^"]+)"'
   1.145 +  ) or string.match(
   1.146 +      post_contenttype,
   1.147 +      '^multipart/form%-data[ \t]*;[ \t]*boundary=([^"; \t]+)'
   1.148 +  )
   1.149 +  if boundary then
   1.150 +    local parts = {}
   1.151 +    do
   1.152 +      local boundary = "\r\n--" .. boundary
   1.153 +      local post_data = "\r\n" .. post_data
   1.154 +      local pos1, pos2 = string.find(post_data, boundary, 1, true)
   1.155 +      while true do
   1.156 +        local ind = string.sub(post_data, pos2 + 1, pos2 + 2)
   1.157 +        if ind == "\r\n" then
   1.158 +          local pos3, pos4 = string.find(post_data, boundary, pos2 + 1, true)
   1.159 +          if pos3 then
   1.160 +            parts[#parts + 1] = string.sub(post_data, pos2 + 3, pos3 - 1)
   1.161 +          else
   1.162 +            error("Illegal POST data.")
   1.163 +          end
   1.164 +          pos1, pos2 = pos3, pos4
   1.165 +        elseif ind == "--" then
   1.166 +          break
   1.167 +        else
   1.168 +          error("Illegal POST data.")
   1.169 +        end
   1.170 +      end
   1.171 +    end
   1.172 +    for i, part in ipairs(parts) do
   1.173 +      local pos = 1
   1.174 +      local name, filename, contenttype
   1.175 +      while true do
   1.176 +        local header
   1.177 +        do
   1.178 +          local oldpos = pos
   1.179 +          pos = string.find(part, "\r\n", oldpos, true)
   1.180 +          if not pos then
   1.181 +            error("Illegal POST data.")
   1.182 +          end
   1.183 +          if pos == oldpos then break end
   1.184 +          header = string.sub(part, oldpos, pos - 1)
   1.185 +          pos = pos + 2
   1.186 +        end
   1.187 +        if string.find(
   1.188 +          string.lower(header),
   1.189 +          "^content%-disposition:[ \t]*form%-data[ \t]*;"
   1.190 +        ) then
   1.191 +          -- TODO: handle all cases correctly
   1.192 +          name = string.match(header, ';[ \t]*name="([^"]*)"') or
   1.193 +            string.match(header, ';[ \t]*name=([^"; \t]+)')
   1.194 +          filename = string.match(header, ';[ \t]*filename="([^"]*)"') or
   1.195 +            string.match(header, ';[ \t]*filename=([^"; \t]+)')
   1.196 +        else
   1.197 +          local dummy, subpos = string.find(
   1.198 +            string.lower(header),
   1.199 +            "^content%-type:[ \t]*"
   1.200 +          )
   1.201 +          if subpos then
   1.202 +            contenttype = string.sub(header, subpos + 1, #header)
   1.203 +          end
   1.204 +        end
   1.205 +      end
   1.206 +      local content = string.sub(part, pos + 2, #part)
   1.207 +      if not name then
   1.208 +        error("Illegal POST data.")
   1.209 +      end
   1.210 +      proc_param(post_params, name, content)
   1.211 +      post_filenames[name] = filename
   1.212 +      post_types[name] = contenttype
   1.213 +    end
   1.214 +  end
   1.215 +end
   1.216 +
   1.217 +if post_data and #post_data > 262144 then
   1.218 +  post_data = nil
   1.219 +  collectgarbage("collect")
   1.220 +else
   1.221 +  post_data = nil
   1.222 +end

Impressum / About Us