154f51ac403a368dd1af22b42f0e56812c504494
[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 local ltn12 = require("luci.ltn12")
29 require("luci.http.protocol")
30 require("luci.util")
31
32 context = luci.util.threadlocal()
33
34 Request = luci.util.class()
35 function Request.__init__(self, env, sourcein, sinkerr)
36         self.input = sourcein
37         self.error = sinkerr
38
39
40         -- File handler
41         self.filehandler = function() end
42         
43         -- HTTP-Message table
44         self.message = {
45                 env = env,
46                 headers = {},
47                 params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""),
48         }
49         
50         self.parsed_input = false
51 end
52
53 function Request.formvalue(self, name, noparse)
54         if not noparse and not self.parsed_input then
55                 self:_parse_input()
56         end
57         
58         if name then
59                 return self.message.params[name]
60         else
61                 return self.message.params
62         end
63 end
64
65 function Request.formvaluetable(self, prefix)
66         local vals = {}
67         prefix = prefix and prefix .. "." or "."
68         
69         if not self.parsed_input then
70                 self:_parse_input()
71         end
72         
73         local void = self.message.params[nil]
74         for k, v in pairs(self.message.params) do
75                 if k:find(prefix, 1, true) == 1 then
76                         vals[k:sub(#prefix + 1)] = tostring(v)
77                 end
78         end
79         
80         return vals
81 end
82
83 function Request.getcookie(self, name)
84   local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
85   local p = ";" .. name .. "=(.-);"
86   local i, j, value = c:find(p)
87   return value and urldecode(value)
88 end
89
90 function Request.getenv(self, name)
91         if name then
92                 return self.message.env[name]
93         else
94                 return self.message.env
95         end
96 end
97
98 function Request.setfilehandler(self, callback)
99         self.filehandler = callback
100 end
101
102 function Request._parse_input(self)
103         luci.http.protocol.parse_message_body(
104                  self.input,
105                  self.message,
106                  self.filehandler
107         )
108         self.parsed_input = true
109 end
110
111 --- Close the HTTP-Connection.
112 function close()
113         if not context.eoh then
114                 context.eoh = true
115                 coroutine.yield(3)
116         end
117         
118         if not context.closed then
119                 context.closed = true
120                 coroutine.yield(5)
121         end
122 end
123
124 --- Get a certain HTTP input value or a table of all input values.
125 -- @param name          Name of the GET or POST variable to fetch
126 -- @param noparse       Don't parse POST data before getting the value
127 -- @return                      HTTP input value or table of all input value
128 function formvalue(name, noparse)
129         return context.request:formvalue(name, noparse)
130 end
131
132 --- Get a table of all HTTP input values with a certain prefix.
133 -- @param prefix        Prefix
134 -- @return                      Table of all HTTP input values with given prefix
135 function formvaluetable(prefix)
136         return context.request:formvaluetable(prefix)
137 end
138
139 --- Get the value of a certain HTTP-Cookie.
140 -- @param name          Cookie Name
141 -- @return                      String containing cookie data
142 function getcookie(name)
143         return context.request:getcookie(name)
144 end
145
146 --- Get the value of a certain HTTP environment variable 
147 -- or the environment table itself.
148 -- @param name          Environment variable
149 -- @return                      HTTP environment value or environment table
150 function getenv(name)
151         return context.request:getenv(name)
152 end
153
154 --- Set a handler function for incoming user file uploads.
155 -- @param callback      Handler function
156 function setfilehandler(callback)
157         return context.request:setfilehandler(callback)
158 end
159
160 --- Send a HTTP-Header.
161 -- @param key   Header key
162 -- @param value Header value
163 function header(key, value)
164         if not context.headers then
165                 context.headers = {}
166         end
167         context.headers[key:lower()] = value
168         coroutine.yield(2, key, value)
169 end
170
171 --- Set the mime type of following content data.
172 -- @param mime  Mimetype of following content
173 function prepare_content(mime)
174         header("Content-Type", mime)
175 end
176
177 --- Set the HTTP status code and status message.
178 -- @param code          Status code
179 -- @param message       Status message
180 function status(code, message)
181         code = code or 200
182         message = message or "OK"
183         context.status = code
184         coroutine.yield(1, code, message)
185 end
186
187 --- Send a chunk of content data to the client.
188 -- This function is as a valid LTN12 sink.
189 -- If the content chunk is nil this function will automatically invoke close.
190 -- @param content       Content chunk
191 -- @param src_err       Error object from source (optional)
192 -- @see close
193 function write(content, src_err)
194         if not content then
195                 if src_err then
196                         error(src_err)
197                 else
198                         close()
199                 end
200                 return true
201         elseif #content == 0 then
202                 return true
203         else
204                 if not context.eoh then
205                         if not context.status then
206                                 status()
207                         end
208                         if not context.headers or not context.headers["content-type"] then
209                                 header("Content-Type", "text/html; charset=utf-8")
210                         end
211                         if not context.headers["cache-control"] then
212                                 header("Cache-Control", "no-cache")
213                         end
214                         
215                         
216                         context.eoh = true
217                         coroutine.yield(3)
218                 end
219                 coroutine.yield(4, content)
220                 return true
221         end
222 end
223
224 --- Redirects the client to a new URL and closes the connection.
225 -- @param url   Target URL
226 function redirect(url)
227         status(302, "Found")
228         header("Location", url)
229         close()
230 end
231
232 --- Create a querystring out of a table of key - value pairs.
233 -- @param table         Query string source table
234 -- @return                      Encoded HTTP query string
235 function build_querystring(table)
236         local s="?"
237         
238         for k, v in pairs(table) do
239                 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
240         end
241         
242         return s
243 end
244
245 --- Return the URL-decoded equivalent of a string.
246 -- @param str           URL-encoded string
247 -- @param no_plus       Don't decode + to " "
248 -- @return                      URL-decoded string
249 -- @see urlencode
250 urldecode = luci.http.protocol.urldecode
251
252 --- Return the URL-encoded equivalent of a string.
253 -- @param str           Source string
254 -- @return                      URL-encoded string
255 -- @see urldecode
256 urlencode = luci.http.protocol.urlencode