libs/web: Set Expires-Header
[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 --- LuCI Web Framework high-level HTTP functions.
28 module("luci.http", package.seeall)
29 local ltn12 = require("luci.ltn12")
30 require("luci.http.protocol")
31 require("luci.util")
32
33 context = luci.util.threadlocal()
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, noparse)
55 if not noparse and not self.parsed_input then
56 self:_parse_input()
57 end
58
59 if name then
60 return self.message.params[name]
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 = c: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 --- Close the HTTP-Connection.
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 --- 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)
131 end
132
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)
138 end
139
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)
145 end
146
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)
153 end
154
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)
159 end
160
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
166 context.headers = {}
167 end
168 context.headers[key:lower()] = value
169 coroutine.yield(2, key, value)
170 end
171
172 --- Set the mime type of following content data.
173 -- @param mime Mimetype of following content
174 function prepare_content(mime)
175 header("Content-Type", mime)
176 end
177
178 --- Set the HTTP status code and status message.
179 -- @param code Status code
180 -- @param message Status message
181 function status(code, message)
182 code = code or 200
183 message = message or "OK"
184 context.status = code
185 coroutine.yield(1, code, message)
186 end
187
188 --- Send a chunk of content data to the client.
189 -- This function is as a valid LTN12 sink.
190 -- If the content chunk is nil this function will automatically invoke close.
191 -- @param content Content chunk
192 -- @param src_err Error object from source (optional)
193 -- @see close
194 function write(content, src_err)
195 if not content then
196 if src_err then
197 error(src_err)
198 else
199 close()
200 end
201 return true
202 elseif #content == 0 then
203 return true
204 else
205 if not context.eoh then
206 if not context.status then
207 status()
208 end
209 if not context.headers or not context.headers["content-type"] then
210 header("Content-Type", "text/html; charset=utf-8")
211 end
212 if not context.headers["cache-control"] then
213 header("Cache-Control", "no-cache")
214 header("Expires", "0")
215 end
216
217
218 context.eoh = true
219 coroutine.yield(3)
220 end
221 coroutine.yield(4, content)
222 return true
223 end
224 end
225
226 --- Redirects the client to a new URL and closes the connection.
227 -- @param url Target URL
228 function redirect(url)
229 status(302, "Found")
230 header("Location", url)
231 close()
232 end
233
234 --- Create a querystring out of a table of key - value pairs.
235 -- @param table Query string source table
236 -- @return Encoded HTTP query string
237 function build_querystring(table)
238 local s="?"
239
240 for k, v in pairs(table) do
241 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
242 end
243
244 return s
245 end
246
247 --- Return the URL-decoded equivalent of a string.
248 -- @param str URL-encoded string
249 -- @param no_plus Don't decode + to " "
250 -- @return URL-decoded string
251 -- @see urlencode
252 urldecode = luci.http.protocol.urldecode
253
254 --- Return the URL-encoded equivalent of a string.
255 -- @param str Source string
256 -- @return URL-encoded string
257 -- @see urldecode
258 urlencode = luci.http.protocol.urlencode