* Rewrote Luci to be coroutine-safe allowing the use of non-forking webservers
[project/luci.git] / libs / web / luasrc / http.lua
1 --[[
2 LuCI - HTTP-Interaction
3
4 Description:
5 HTTP-Header manipulator and form variable preprocessor
6
7 FileId:
8 $Id$
9
10 ToDo:
11 - Cookie handling
12
13 License:
14 Copyright 2008 Steven Barth <steven@midlink.org>
15
16 Licensed under the Apache License, Version 2.0 (the "License");
17 you may not use this file except in compliance with the License.
18 You may obtain a copy of the License at
19
20 http://www.apache.org/licenses/LICENSE-2.0
21
22 Unless required by applicable law or agreed to in writing, software
23 distributed under the License is distributed on an "AS IS" BASIS,
24 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 See the License for the specific language governing permissions and
26 limitations under the License.
27
28 ]]--
29
30 module("luci.http", package.seeall)
31 require("luci.util")
32 context = luci.util.threadlocal()
33
34
35 Request = luci.util.class()
36 function Request.__init__(self)
37 self.headers = {}
38 self.request = {}
39 self.uploads = {}
40 self.env = {}
41 self.data = ""
42 end
43
44 function Request.formvalue(self, name, default)
45 return self.request[name] or default
46 end
47
48 function Request.formvalues(self)
49 return self.request
50 end
51
52 function Request.formvaluetable(self, prefix)
53 local vals = {}
54 prefix = prefix and prefix .. "." or "."
55
56 for k, v in pairs(self.request) do
57 if k:find(prefix, 1, true) == 1 then
58 vals[k:sub(#prefix + 1)] = v
59 end
60 end
61
62 return vals
63 end
64
65 function Request.getenv(self, name)
66 return self.env[name]
67 end
68
69 function Request.upload(self, name)
70 return self.uploads[name]
71 end
72
73
74 function close()
75 if not context.eoh then
76 context.eoh = true
77 coroutine.yield(3)
78 end
79
80 if not context.closed then
81 context.closed = true
82 coroutine.yield(5)
83 end
84 end
85
86 function formvalue(...)
87 return context.request:formvalue(...)
88 end
89
90 function formvalues(...)
91 return context.request:formvalues(...)
92 end
93
94 function formvaluetable(...)
95 return context.request:formvaluetable(...)
96 end
97
98 function getenv(...)
99 return context.request:getenv(...)
100 end
101
102 function header(key, value)
103 if not context.status then
104 status()
105 end
106 if not context.headers then
107 context.headers = {}
108 end
109 context.headers[key:lower()] = value
110 coroutine.yield(2, key, value)
111 end
112
113 function prepare_content(mime)
114 header("Content-Type", mime)
115 end
116
117 function status(code, message)
118 code = code or 200
119 message = message or "OK"
120 context.status = code
121 coroutine.yield(1, code, message)
122 end
123
124 function write(content)
125 if not content or #content == 0 then
126 return
127 end
128 if not context.eoh then
129 if not context.status then
130 status()
131 end
132 if not context.headers or not context.headers["content-type"] then
133 header("Content-Type", "text/html; charset=utf-8")
134 end
135
136 context.eoh = true
137 coroutine.yield(3)
138 end
139 coroutine.yield(4, content)
140 end
141
142
143 function basic_auth(realm, errorpage)
144 header("Status", "401 Unauthorized")
145 header("WWW-Authenticate", string.format('Basic realm="%s"', realm or ""))
146
147 if errorpage then
148 errorpage()
149 end
150
151 close()
152 end
153
154 function redirect(url)
155 header("Status", "302 Found")
156 header("Location", url)
157 close()
158 end
159
160 function upload(...)
161 return context.request:upload(...)
162 end
163
164
165
166 function build_querystring(table)
167 local s="?"
168
169 for k, v in pairs(table) do
170 s = s .. k .. "=" .. v .. "&"
171 end
172
173 return s
174 end
175
176 function urldecode(str)
177 str = str:gsub("+", " ")
178 str = str:gsub("%%(%x%x)",
179 function(h) return string.char(tonumber(h,16)) end)
180 str = str:gsub("\r\n", "\n")
181 return str
182 end
183
184 function urlencode(str)
185 str = str:gsub("\n", "\r\n")
186 str = str:gsub("([^%w ])",
187 function (c) return string.format ("%%%02X", string.byte(c)) end)
188 str = str:gsub(" ", "+")
189 return str
190 end