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 --- LuCI Web Framework high-level HTTP functions.
28 module("luci.http", package.seeall)
29 local ltn12 = require("luci.ltn12")
30 require("luci.http.protocol")
33 context = luci.util.threadlocal()
35 Request = luci.util.class()
36 function Request.__init__(self, env, sourcein, sinkerr)
42 self.filehandler = function() end
48 params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""),
51 self.parsed_input = false
54 function Request.formvalue(self, name, noparse)
55 if not noparse and not self.parsed_input then
60 return self.message.params[name]
62 return self.message.params
66 function Request.formvaluetable(self, prefix)
68 prefix = prefix and prefix .. "." or "."
70 if not self.parsed_input then
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)
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 = c:find(p)
88 return value and urldecode(value)
91 function Request.getenv(self, name)
93 return self.message.env[name]
95 return self.message.env
99 function Request.setfilehandler(self, callback)
100 self.filehandler = callback
103 function Request._parse_input(self)
104 luci.http.protocol.parse_message_body(
109 self.parsed_input = true
112 --- Close the HTTP-Connection.
114 if not context.eoh then
119 if not context.closed then
120 context.closed = true
125 --- Get a certain HTTP input value or a table of all input values.
126 -- @param name Name of the GET or POST variable to fetch
127 -- @param noparse Don't parse POST data before getting the value
128 -- @return HTTP input value or table of all input value
129 function formvalue(name, noparse)
130 return context.request:formvalue(name, noparse)
133 --- Get a table of all HTTP input values with a certain prefix.
134 -- @param prefix Prefix
135 -- @return Table of all HTTP input values with given prefix
136 function formvaluetable(prefix)
137 return context.request:formvaluetable(prefix)
140 --- Get the value of a certain HTTP-Cookie.
141 -- @param name Cookie Name
142 -- @return String containing cookie data
143 function getcookie(name)
144 return context.request:getcookie(name)
147 --- Get the value of a certain HTTP environment variable
148 -- or the environment table itself.
149 -- @param name Environment variable
150 -- @return HTTP environment value or environment table
151 function getenv(name)
152 return context.request:getenv(name)
155 --- Set a handler function for incoming user file uploads.
156 -- @param callback Handler function
157 function setfilehandler(callback)
158 return context.request:setfilehandler(callback)
161 --- Send a HTTP-Header.
162 -- @param key Header key
163 -- @param value Header value
164 function header(key, value)
165 if not context.headers then
168 context.headers[key:lower()] = value
169 coroutine.yield(2, key, value)
172 --- Set the mime type of following content data.
173 -- @param mime Mimetype of following content
174 function prepare_content(mime)
175 if mime == "application/xhtml+xml" then
176 if not getenv("HTTP_ACCEPT") or
177 not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
178 mime = "text/html; charset=UTF-8"
180 header("Vary", "Accept")
182 header("Content-Type", mime)
185 --- Set the HTTP status code and status message.
186 -- @param code Status code
187 -- @param message Status message
188 function status(code, message)
190 message = message or "OK"
191 context.status = code
192 coroutine.yield(1, code, message)
195 --- Send a chunk of content data to the client.
196 -- This function is as a valid LTN12 sink.
197 -- If the content chunk is nil this function will automatically invoke close.
198 -- @param content Content chunk
199 -- @param src_err Error object from source (optional)
201 function write(content, src_err)
209 elseif #content == 0 then
212 if not context.eoh then
213 if not context.status then
216 if not context.headers or not context.headers["content-type"] then
217 header("Content-Type", "text/html; charset=utf-8")
219 if not context.headers["cache-control"] then
220 header("Cache-Control", "no-cache")
221 header("Expires", "0")
228 coroutine.yield(4, content)
233 --- Redirects the client to a new URL and closes the connection.
234 -- @param url Target URL
235 function redirect(url)
237 header("Location", url)
241 --- Create a querystring out of a table of key - value pairs.
242 -- @param table Query string source table
243 -- @return Encoded HTTP query string
244 function build_querystring(table)
247 for k, v in pairs(table) do
248 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
254 --- Return the URL-decoded equivalent of a string.
255 -- @param str URL-encoded string
256 -- @param no_plus Don't decode + to " "
257 -- @return URL-decoded string
259 urldecode = luci.http.protocol.urldecode
261 --- Return the URL-encoded equivalent of a string.
262 -- @param str Source string
263 -- @return URL-encoded string
265 urlencode = luci.http.protocol.urlencode