webmcp

annotate 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
rev   line source
jbe/bsw@0 1 #!/usr/bin/env lua
jbe/bsw@0 2
jbe/bsw@0 3 local assert = assert
jbe/bsw@0 4 local error = error
jbe/bsw@0 5 local getfenv = getfenv
jbe/bsw@0 6 local getmetatable = getmetatable
jbe/bsw@0 7 local ipairs = ipairs
jbe/bsw@0 8 local next = next
jbe/bsw@0 9 local pairs = pairs
jbe/bsw@0 10 local pcall = pcall
jbe/bsw@0 11 local print = print
jbe/bsw@0 12 local rawequal = rawequal
jbe/bsw@0 13 local rawget = rawget
jbe/bsw@0 14 local rawset = rawset
jbe/bsw@0 15 local select = select
jbe/bsw@0 16 local setfenv = setfenv
jbe/bsw@0 17 local setmetatable = setmetatable
jbe/bsw@0 18 local tonumber = tonumber
jbe/bsw@0 19 local tostring = tostring
jbe/bsw@0 20 local type = type
jbe/bsw@0 21 local unpack = unpack
jbe/bsw@0 22 local xpcall = xpcall
jbe/bsw@0 23
jbe/bsw@0 24 local io = io
jbe/bsw@0 25 local math = math
jbe/bsw@0 26 local os = os
jbe/bsw@0 27 local string = string
jbe/bsw@0 28 local table = table
jbe/bsw@0 29
jbe/bsw@0 30 module(...)
jbe/bsw@0 31
jbe/bsw@0 32 data_sent = false
jbe/bsw@0 33
jbe/bsw@0 34 function add_header(...)
jbe/bsw@0 35 if data_sent then
jbe/bsw@0 36 error("Can not add header after data has been sent.", 2)
jbe/bsw@0 37 end
jbe/bsw@0 38 io.stdout:write(...)
jbe/bsw@0 39 io.stdout:write("\r\n")
jbe/bsw@0 40 end
jbe/bsw@0 41
jbe/bsw@0 42 function send_data(...)
jbe/bsw@0 43 if not data_sent then
jbe/bsw@0 44 io.stdout:write("\r\n")
jbe/bsw@0 45 data_sent = true
jbe/bsw@0 46 end
jbe/bsw@0 47 io.stdout:write(...)
jbe/bsw@0 48 end
jbe/bsw@0 49
jbe/bsw@0 50 function set_status(status)
jbe/bsw@0 51 add_header("Status: ", status)
jbe/bsw@0 52 end
jbe/bsw@0 53
jbe/bsw@0 54 function redirect(location)
jbe/bsw@0 55 set_status("303 See Other")
jbe/bsw@0 56 add_header("Location: ", location)
jbe/bsw@0 57 end
jbe/bsw@0 58
jbe/bsw@0 59 function set_content_type(content_type)
jbe/bsw@0 60 add_header("Content-Type: ", content_type)
jbe/bsw@0 61 end
jbe/bsw@0 62
jbe/bsw@0 63 method = os.getenv("REQUEST_METHOD") or false
jbe/bsw@0 64 query = os.getenv("QUERY_STRING") or false
jbe/bsw@0 65 cookie_data = os.getenv("HTTP_COOKIE") or false
jbe/bsw@0 66 post_data = io.stdin:read("*a") or false
jbe/bsw@0 67 post_contenttype = os.getenv("CONTENT_TYPE") or false
jbe/bsw@0 68 params = {}
jbe/bsw@0 69 get_params = {}
jbe/bsw@0 70 cookies = {}
jbe/bsw@0 71 post_params = {}
jbe/bsw@0 72 post_filenames = {}
jbe/bsw@0 73 post_types = {}
jbe/bsw@0 74
jbe/bsw@0 75 local urldecode
jbe/bsw@0 76 do
jbe/bsw@0 77 local b0 = string.byte("0")
jbe/bsw@0 78 local b9 = string.byte("9")
jbe/bsw@0 79 local bA = string.byte("A")
jbe/bsw@0 80 local bF = string.byte("F")
jbe/bsw@0 81 local ba = string.byte("a")
jbe/bsw@0 82 local bf = string.byte("f")
jbe/bsw@0 83 function urldecode(str)
jbe/bsw@0 84 return (
jbe/bsw@0 85 string.gsub(
jbe/bsw@0 86 string.gsub(str, "%+", " "),
jbe/bsw@0 87 "%%([0-9A-Fa-f][0-9A-Fa-f])",
jbe/bsw@0 88 function(hex)
jbe/bsw@0 89 local n1, n2 = string.byte(hex, 1, 2)
jbe/bsw@0 90 if n1 >= b0 and n1 <= b9 then n1 = n1 - b0
jbe/bsw@0 91 elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10
jbe/bsw@0 92 elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10
jbe/bsw@0 93 else return end
jbe/bsw@0 94 if n2 >= b0 and n2 <= b9 then n2 = n2 - b0
jbe/bsw@0 95 elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10
jbe/bsw@0 96 elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10
jbe/bsw@0 97 else return end
jbe/bsw@0 98 return string.char(n1 * 16 + n2)
jbe/bsw@0 99 end
jbe/bsw@0 100 )
jbe/bsw@0 101 )
jbe/bsw@0 102 end
jbe/bsw@0 103 end
jbe/bsw@0 104
jbe/bsw@0 105 local function proc_param(tbl, key, value)
jbe/bsw@0 106 if string.find(key, "%[%]$") then
jbe/bsw@0 107 if tbl[key] then
jbe/bsw@0 108 table.insert(tbl[key], value)
jbe/bsw@0 109 else
jbe/bsw@0 110 local list = { value }
jbe/bsw@0 111 params[key] = list
jbe/bsw@0 112 tbl[key] = list
jbe/bsw@0 113 end
jbe/bsw@0 114 else
jbe/bsw@0 115 params[key] = value
jbe/bsw@0 116 tbl[key] = value
jbe/bsw@0 117 end
jbe/bsw@0 118 end
jbe/bsw@0 119
jbe/bsw@0 120 local function read_urlencoded_form(tbl, data)
jbe/bsw@0 121 for rawkey, rawvalue in string.gmatch(data, "([^=&]*)=([^=&]*)") do
jbe/bsw@0 122 proc_param(tbl, urldecode(rawkey), urldecode(rawvalue))
jbe/bsw@0 123 end
jbe/bsw@0 124 end
jbe/bsw@0 125
jbe/bsw@0 126 if query then
jbe/bsw@0 127 read_urlencoded_form(get_params, query)
jbe/bsw@0 128 end
jbe/bsw@0 129
jbe/bsw@0 130 if cookie_data then
jbe/bsw@0 131 for rawkey, rawvalue in string.gmatch(cookie_data, "([^=; ]*)=([^=; ]*)") do
jbe/bsw@0 132 cookies[urldecode(rawkey)] = urldecode(rawvalue)
jbe/bsw@0 133 end
jbe/bsw@0 134 end
jbe/bsw@0 135
jbe/bsw@0 136 if post_contenttype == "application/x-www-form-urlencoded" then
jbe/bsw@0 137 read_urlencoded_form(post_params, post_data)
jbe/bsw@0 138 elseif post_contenttype then
jbe/bsw@0 139 local boundary = string.match(
jbe/bsw@0 140 post_contenttype,
jbe/bsw@0 141 '^multipart/form%-data[ \t]*;[ \t]*boundary="([^"]+)"'
jbe/bsw@0 142 ) or string.match(
jbe/bsw@0 143 post_contenttype,
jbe/bsw@0 144 '^multipart/form%-data[ \t]*;[ \t]*boundary=([^"; \t]+)'
jbe/bsw@0 145 )
jbe/bsw@0 146 if boundary then
jbe/bsw@0 147 local parts = {}
jbe/bsw@0 148 do
jbe/bsw@0 149 local boundary = "\r\n--" .. boundary
jbe/bsw@0 150 local post_data = "\r\n" .. post_data
jbe/bsw@0 151 local pos1, pos2 = string.find(post_data, boundary, 1, true)
jbe/bsw@0 152 while true do
jbe/bsw@0 153 local ind = string.sub(post_data, pos2 + 1, pos2 + 2)
jbe/bsw@0 154 if ind == "\r\n" then
jbe/bsw@0 155 local pos3, pos4 = string.find(post_data, boundary, pos2 + 1, true)
jbe/bsw@0 156 if pos3 then
jbe/bsw@0 157 parts[#parts + 1] = string.sub(post_data, pos2 + 3, pos3 - 1)
jbe/bsw@0 158 else
jbe/bsw@0 159 error("Illegal POST data.")
jbe/bsw@0 160 end
jbe/bsw@0 161 pos1, pos2 = pos3, pos4
jbe/bsw@0 162 elseif ind == "--" then
jbe/bsw@0 163 break
jbe/bsw@0 164 else
jbe/bsw@0 165 error("Illegal POST data.")
jbe/bsw@0 166 end
jbe/bsw@0 167 end
jbe/bsw@0 168 end
jbe/bsw@0 169 for i, part in ipairs(parts) do
jbe/bsw@0 170 local pos = 1
jbe/bsw@0 171 local name, filename, contenttype
jbe/bsw@0 172 while true do
jbe/bsw@0 173 local header
jbe/bsw@0 174 do
jbe/bsw@0 175 local oldpos = pos
jbe/bsw@0 176 pos = string.find(part, "\r\n", oldpos, true)
jbe/bsw@0 177 if not pos then
jbe/bsw@0 178 error("Illegal POST data.")
jbe/bsw@0 179 end
jbe/bsw@0 180 if pos == oldpos then break end
jbe/bsw@0 181 header = string.sub(part, oldpos, pos - 1)
jbe/bsw@0 182 pos = pos + 2
jbe/bsw@0 183 end
jbe/bsw@0 184 if string.find(
jbe/bsw@0 185 string.lower(header),
jbe/bsw@0 186 "^content%-disposition:[ \t]*form%-data[ \t]*;"
jbe/bsw@0 187 ) then
jbe/bsw@0 188 -- TODO: handle all cases correctly
jbe/bsw@0 189 name = string.match(header, ';[ \t]*name="([^"]*)"') or
jbe/bsw@0 190 string.match(header, ';[ \t]*name=([^"; \t]+)')
jbe/bsw@0 191 filename = string.match(header, ';[ \t]*filename="([^"]*)"') or
jbe/bsw@0 192 string.match(header, ';[ \t]*filename=([^"; \t]+)')
jbe/bsw@0 193 else
jbe/bsw@0 194 local dummy, subpos = string.find(
jbe/bsw@0 195 string.lower(header),
jbe/bsw@0 196 "^content%-type:[ \t]*"
jbe/bsw@0 197 )
jbe/bsw@0 198 if subpos then
jbe/bsw@0 199 contenttype = string.sub(header, subpos + 1, #header)
jbe/bsw@0 200 end
jbe/bsw@0 201 end
jbe/bsw@0 202 end
jbe/bsw@0 203 local content = string.sub(part, pos + 2, #part)
jbe/bsw@0 204 if not name then
jbe/bsw@0 205 error("Illegal POST data.")
jbe/bsw@0 206 end
jbe/bsw@0 207 proc_param(post_params, name, content)
jbe/bsw@0 208 post_filenames[name] = filename
jbe/bsw@0 209 post_types[name] = contenttype
jbe/bsw@0 210 end
jbe/bsw@0 211 end
jbe/bsw@0 212 end
jbe/bsw@0 213
jbe/bsw@0 214 if post_data and #post_data > 262144 then
jbe/bsw@0 215 post_data = nil
jbe/bsw@0 216 collectgarbage("collect")
jbe/bsw@0 217 else
jbe/bsw@0 218 post_data = nil
jbe/bsw@0 219 end

Impressum / About Us