2 LuCI - HTTP-Interaction
5 HTTP-Header manipulator and form variable preprocessor
11 Copyright 2008 Steven Barth <steven@midlink.org>
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
17 http://www.apache.org/licenses/LICENSE-2.0
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.
27 local ltn12 = require "luci.ltn12"
28 local protocol = require "luci.http.protocol"
29 local util = require "luci.util"
30 local string = require "string"
31 local coroutine = require "coroutine"
33 local pairs, tostring, error = pairs, tostring, error
35 --- LuCI Web Framework high-level HTTP functions.
38 context = util.threadlocal()
40 Request = util.class()
41 function Request.__init__(self, env, sourcein, sinkerr)
47 self.filehandler = function() end
53 params = protocol.urldecode_params(env.QUERY_STRING or ""),
56 self.parsed_input = false
59 function Request.formvalue(self, name, noparse)
60 if not noparse and not self.parsed_input then
65 return self.message.params[name]
67 return self.message.params
71 function Request.formvaluetable(self, prefix)
73 prefix = prefix and prefix .. "." or "."
75 if not self.parsed_input then
79 local void = self.message.params[nil]
80 for k, v in pairs(self.message.params) do
81 if k:find(prefix, 1, true) == 1 then
82 vals[k:sub(#prefix + 1)] = tostring(v)
89 function Request.content(self)
90 if not self.parsed_input then
94 return self.message.content, self.message.content_length
97 function Request.getcookie(self, name)
98 local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
99 local p = ";" .. name .. "=(.-);"
100 local i, j, value = c:find(p)
101 return value and urldecode(value)
104 function Request.getenv(self, name)
106 return self.message.env[name]
108 return self.message.env
112 function Request.setfilehandler(self, callback)
113 self.filehandler = callback
116 function Request._parse_input(self)
117 protocol.parse_message_body(
122 self.parsed_input = true
125 --- Close the HTTP-Connection.
127 if not context.eoh then
132 if not context.closed then
133 context.closed = true
138 --- Return the request content if the request was of unknown type.
139 -- @return HTTP request body
140 -- @return HTTP request body length
142 return context.request:content()
145 --- Get a certain HTTP input value or a table of all input values.
146 -- @param name Name of the GET or POST variable to fetch
147 -- @param noparse Don't parse POST data before getting the value
148 -- @return HTTP input value or table of all input value
149 function formvalue(name, noparse)
150 return context.request:formvalue(name, noparse)
153 --- Get a table of all HTTP input values with a certain prefix.
154 -- @param prefix Prefix
155 -- @return Table of all HTTP input values with given prefix
156 function formvaluetable(prefix)
157 return context.request:formvaluetable(prefix)
160 --- Get the value of a certain HTTP-Cookie.
161 -- @param name Cookie Name
162 -- @return String containing cookie data
163 function getcookie(name)
164 return context.request:getcookie(name)
167 --- Get the value of a certain HTTP environment variable
168 -- or the environment table itself.
169 -- @param name Environment variable
170 -- @return HTTP environment value or environment table
171 function getenv(name)
172 return context.request:getenv(name)
175 --- Set a handler function for incoming user file uploads.
176 -- @param callback Handler function
177 function setfilehandler(callback)
178 return context.request:setfilehandler(callback)
181 --- Send a HTTP-Header.
182 -- @param key Header key
183 -- @param value Header value
184 function header(key, value)
185 if not context.headers then
188 context.headers[key:lower()] = value
189 coroutine.yield(2, key, value)
192 --- Set the mime type of following content data.
193 -- @param mime Mimetype of following content
194 function prepare_content(mime)
195 if not context.headers or not context.headers["content-type"] then
196 if mime == "application/xhtml+xml" then
197 if not getenv("HTTP_ACCEPT") or
198 not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
199 mime = "text/html; charset=UTF-8"
201 header("Vary", "Accept")
203 header("Content-Type", mime)
207 --- Get the RAW HTTP input source
208 -- @return HTTP LTN12 source
210 return context.request.input
213 --- Set the HTTP status code and status message.
214 -- @param code Status code
215 -- @param message Status message
216 function status(code, message)
218 message = message or "OK"
219 context.status = code
220 coroutine.yield(1, code, message)
223 --- Send a chunk of content data to the client.
224 -- This function is as a valid LTN12 sink.
225 -- If the content chunk is nil this function will automatically invoke close.
226 -- @param content Content chunk
227 -- @param src_err Error object from source (optional)
229 function write(content, src_err)
237 elseif #content == 0 then
240 if not context.eoh then
241 if not context.status then
244 if not context.headers or not context.headers["content-type"] then
245 header("Content-Type", "text/html; charset=utf-8")
247 if not context.headers["cache-control"] then
248 header("Cache-Control", "no-cache")
249 header("Expires", "0")
256 coroutine.yield(4, content)
261 --- Redirects the client to a new URL and closes the connection.
262 -- @param url Target URL
263 function redirect(url)
265 header("Location", url)
269 --- Create a querystring out of a table of key - value pairs.
270 -- @param table Query string source table
271 -- @return Encoded HTTP query string
272 function build_querystring(table)
275 for k, v in pairs(table) do
276 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
282 --- Return the URL-decoded equivalent of a string.
283 -- @param str URL-encoded string
284 -- @param no_plus Don't decode + to " "
285 -- @return URL-decoded string
287 urldecode = protocol.urldecode
289 --- Return the URL-encoded equivalent of a string.
290 -- @param str Source string
291 -- @return URL-encoded string
293 urlencode = protocol.urlencode