37050e47853eb87b2ab944da108954e4420c77af
[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 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at 
16
17         http://www.apache.org/licenses/LICENSE-2.0 
18
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24
25 ]]--
26
27 module("luci.http", package.seeall)
28 require("ltn12")
29 require("luci.http.protocol")
30 require("luci.util")
31
32 context = luci.util.threadlocal()
33
34
35 Request = luci.util.class()
36 function Request.__init__(self, env, sourcein, sinkerr)
37         self.input = sourcein
38         self.error = sinkerr
39
40
41         -- File handler
42         self.filehandler = function() end
43         
44         -- HTTP-Message table
45         self.message = {
46                 env = env,
47                 headers = {},
48                 params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""),
49         }
50         
51         self.parsed_input = false
52 end
53
54 function Request.formvalue(self, name, default)
55         if not self.parsed_input then
56                 self:_parse_input()
57         end
58         
59         if name then
60                 return self.message.params[name] and tostring(self.message.params[name]) or default
61         else
62                 return self.message.params
63         end
64 end
65
66 function Request.formvaluetable(self, prefix)
67         local vals = {}
68         prefix = prefix and prefix .. "." or "."
69         
70         if not self.parsed_input then
71                 self:_parse_input()
72         end
73         
74         local void = self.message.params[nil]
75         for k, v in pairs(self.message.params) do
76                 if k:find(prefix, 1, true) == 1 then
77                         vals[k:sub(#prefix + 1)] = tostring(v)
78                 end
79         end
80         
81         return vals
82 end
83
84 function Request.getcookie(self, name)
85   local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
86   local p = ";" .. name .. "=(.-);"
87   local i, j, value = cookies:find(p)
88   return value and urldecode(value)
89 end
90
91 function Request.getenv(self, name)
92         if name then
93                 return self.message.env[name]
94         else
95                 return self.message.env
96         end
97 end
98
99 function Request.setfilehandler(self, callback)
100         self.filehandler = callback
101 end
102
103 function Request._parse_input(self)
104         luci.http.protocol.parse_message_body(
105                  self.input,
106                  self.message,
107                  self.filehandler
108         )
109         self.parsed_input = true
110 end
111
112
113 function close()
114         if not context.eoh then
115                 context.eoh = true
116                 coroutine.yield(3)
117         end
118         
119         if not context.closed then
120                 context.closed = true
121                 coroutine.yield(5)
122         end
123 end
124
125 function formvalue(...)
126         return context.request:formvalue(...)
127 end
128
129 function formvaluetable(...)
130         return context.request:formvaluetable(...)
131 end
132
133 function getvalue(...)
134         return context.request:getvalue(...)
135 end
136
137 function postvalue(...)
138         return context.request:postvalue(...)
139 end
140
141 function getenv(...)
142         return context.request:getenv(...)
143 end
144
145 function setfilehandler(...)
146         return context.request:setfilehandler(...)
147 end
148
149 function header(key, value)
150         if not context.status then
151                 status()
152         end
153         if not context.headers then
154                 context.headers = {}
155         end
156         context.headers[key:lower()] = value
157         coroutine.yield(2, key, value)
158 end
159
160 function prepare_content(mime)
161         header("Content-Type", mime)
162 end
163
164 function status(code, message)
165         code = code or 200
166         message = message or "OK"
167         context.status = code
168         coroutine.yield(1, code, message)
169 end
170
171 function write(content)
172         if not content or #content == 0 then
173                 return
174         end
175         if not context.eoh then
176                 if not context.status then
177                         status()
178                 end
179                 if not context.headers or not context.headers["content-type"] then
180                         header("Content-Type", "text/html; charset=utf-8")
181                 end
182                 
183                 context.eoh = true
184                 coroutine.yield(3)
185         end
186         coroutine.yield(4, content)
187 end
188
189 function redirect(url)
190         header("Status", "302 Found")
191         header("Location", url)
192         close()
193 end
194
195 function build_querystring(table)
196         local s="?"
197         
198         for k, v in pairs(table) do
199                 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
200         end
201         
202         return s
203 end
204
205 urldecode = luci.http.protocol.urldecode
206 urlencode = luci.http.protocol.urlencode