~mrooney/etherpad/ubuntu

« back to all changes in this revision

Viewing changes to trunk/trunk/infrastructure/framework-src/modules/global/response.js

  • Committer: Aaron Iba
  • Date: 2009-12-18 07:40:23 UTC
  • Revision ID: hg-v1:a9f8774a2e00cc15b35857471fecea17f649e3c9
initial code push

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright 2009 Google Inc.
 
3
 * 
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 * 
 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
 
9
 * 
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS-IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/**
 
18
 * @fileOverview Helpers for the HTTP response.
 
19
 */
 
20
 
 
21
/** @ignore */
 
22
function _cx() { return appjet.context };
 
23
 
 
24
/** @ignore */
 
25
function _cookiestring(c) {
 
26
  var x = '';
 
27
  if (!c.name) { throw new Error('cookie name is required'); }
 
28
  if (!c.value) { c.value = ''; }
 
29
  x += (c.name + '=' + escape(c.value));
 
30
 
 
31
  // expires
 
32
  if (c.expires instanceof Date) {
 
33
    x += ('; expires='+_cookiedate(c.expires));
 
34
  }
 
35
  if (typeof(c.expires) == 'number') {
 
36
    var today = (new Date()).valueOf();
 
37
    var d = new Date(today + 86400000*c.expires);
 
38
    x += ('; expires='+_cookiedate(d));
 
39
  }
 
40
 
 
41
  // domain
 
42
  if (c.domain) { x += ('; domain='+c.domain); }
 
43
 
 
44
  // path
 
45
  if (c.path) { x += ('; path='+c.path); }
 
46
 
 
47
  // secure
 
48
  if (c.secure == true) { x += '; secure'; }
 
49
 
 
50
  return x;
 
51
};
 
52
 
 
53
/** @ignore */
 
54
function _cookiedate(d) {
 
55
  var x = d.toGMTString();
 
56
  var p = x.split(' ');
 
57
  return [p[0], [p[1], p[2], p[3]].join('-'), p[4], p[5]].join(' ');
 
58
};
 
59
 
 
60
var response = {
 
61
 
 
62
get isDefined() {
 
63
  return _cx().response() != null;
 
64
}
 
65
 
 
66
};
 
67
 
 
68
/**
 
69
 * Halts the program immediately and returns 403 Forbidden error to the user.
 
70
 */
 
71
response.forbid = function() {
 
72
  _cx().response().error(403, "Forbidden");
 
73
};
 
74
 
 
75
/**
 
76
 * Halts the program immediately.
 
77
 *
 
78
 * @param {boolean} renderCurrentPage if false, an empty page will be rendered,
 
79
 *   otherwise calls to print() so far will be displayed.  Either way, no more
 
80
 *   code will be executed.
 
81
 */
 
82
response.stop = function(renderCurrentPage) {
 
83
  _cx().response().stop();
 
84
};
 
85
 
 
86
/**
 
87
 * Halts the program immediately and returns a 404 not found error to the user.
 
88
 */
 
89
response.notFound = function() {
 
90
  _cx().response().error(404, "404: Not found");
 
91
};
 
92
 
 
93
/**
 
94
 * Halts the program immediately and sends an HTTP redirect response (302),
 
95
 * redirecting to the given path (relative or absolute).
 
96
 *
 
97
 * @param {string} path The new path
 
98
 */
 
99
response.redirect = function(path) {
 
100
  if ((! path) && path != "") {
 
101
    throw new Error("Invalid redirect: "+path);
 
102
  }
 
103
  if (path.indexOf('/') == 0) {
 
104
    // make sure absolute URL has proper host/port
 
105
    path = request.scheme+"://"+request.host+path;
 
106
  }
 
107
  _cx().response().redirect(path);
 
108
};
 
109
 
 
110
/**
 
111
 * Sets the status code in the HTTP response.
 
112
 *
 
113
 * @param {number} newCode
 
114
 */
 
115
response.setStatusCode = function(newCode) {
 
116
  _cx().response().setStatusCode(newCode);
 
117
};
 
118
response.getStatusCode = function() {
 
119
  return _cx().response().getStatusCode();
 
120
};
 
121
 
 
122
response.sendError = function(errorCode, errorHtml) {
 
123
  _cx().response().error(errorCode, errorHtml);
 
124
};
 
125
 
 
126
response.reset = function() {
 
127
  _cx().response().reset();
 
128
};
 
129
 
 
130
/**
 
131
 * Sets any header of the HTTP response.
 
132
 *
 
133
 * @example
 
134
response.setHeader('Cache-Control', 'no-cache');
 
135
 *
 
136
 * @param {string} name
 
137
 * @param {string} value
 
138
 */
 
139
response.setHeader = function(name, value) {
 
140
  _cx().response().setHeader(name, value);
 
141
};
 
142
 
 
143
/**
 
144
 * Adds the name,value pair to the headers.  Useful for headers that are
 
145
 * allowed to repeat, such as Set-Cookie.
 
146
 *
 
147
 * @param {string} name
 
148
 * @param {string} value
 
149
 */
 
150
response.addHeader = function(name, value) {
 
151
  _cx().response().addHeader(name, value);
 
152
};
 
153
 
 
154
/**
 
155
 * Returns the value of a previously-set header. Useful in the
 
156
 * postRequestHandler to see values of headers set during normal
 
157
 * request processing.
 
158
 *
 
159
 * @param {string} name
 
160
 * @return {array} An array of header values. Empty array if none set.
 
161
 */
 
162
response.getHeader = function(name) {
 
163
  if (! this.isDefined) {
 
164
    return [];
 
165
  } else {
 
166
    return _cx().response().getHeader(name);
 
167
  }
 
168
};
 
169
 
 
170
/**
 
171
 * Removes all instances of a header of the HTTP response.
 
172
 *
 
173
 * @param {string} name
 
174
 */
 
175
response.removeHeader = function(name) {
 
176
  _cx().response().removeHeader(name);
 
177
};
 
178
 
 
179
/**
 
180
 * Low-level hook for writing raw data to the response.
 
181
 * @param {string} data will be written, verbatim, to the HTTP resonse.
 
182
 */
 
183
response.write = function(data) {
 
184
  _cx().response().write(data);
 
185
};
 
186
 
 
187
/**
 
188
 * Low-level hook for writing raw byte data to the response. Especially
 
189
 * useful for writing the result of a <code>wget</code> of image data,
 
190
 * or writing an uploaded file.
 
191
 * @param {string} data will be written, verbatim, to the HTTP resonse.
 
192
 */
 
193
response.writeBytes = function(data) {
 
194
  _cx().response().writeBytes(data);
 
195
};
 
196
 
 
197
//----------------------------------------------------------------
 
198
// Cookies!
 
199
//----------------------------------------------------------------
 
200
 
 
201
/**
 
202
 * Set a cookie in the response.
 
203
 *
 
204
 * @example
 
205
response.setCookie({
 
206
  name: "SessionID",
 
207
  value: "25",
 
208
  secure: true,
 
209
  expires: 14 // 14 days
 
210
});
 
211
 *
 
212
 * @param {object} cookieObject This may contain any of the following:
 
213
<ul>
 
214
  <li>name (required): The name of the cookie</li>
 
215
  <li>value (required): The value of the cookie.  (Note: this value will be escaped).
 
216
  <li>expires (optional): If an integer, means number of days until it expires;
 
217
        if a Date object, means exact date on which to expire.</li>
 
218
  <li>domain (optional): The cookie domain</li>
 
219
  <li>path (optional): To restrict the cookie to a specific path.</li>
 
220
  <li>secure (optional): Whether this cookie should only be sent securely.</li>
 
221
</ul>
 
222
 */
 
223
response.setCookie = function(cookieObject) {
 
224
  this.addHeader('Set-Cookie', _cookiestring(cookieObject));
 
225
 
 
226
  var p3pHeader = this.getHeader("P3P");
 
227
  if ((! p3pHeader) || p3pHeader.length == 0) {
 
228
    // The existence of this "privacy policy" header allows cookies set on
 
229
    // pages inside iframes to be accepted by IE.  (This is some kind of
 
230
    // default policy copied from an example online. -- dgreensp)
 
231
    this.setHeader('P3P', 'CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"');
 
232
  }
 
233
};
 
234
 
 
235
/**
 
236
 * Tells the client to delete the cookie of the given name (by setting
 
237
 * its expiration time to zero).
 
238
 * @param {string} name The name of the cookie to delete.
 
239
 */
 
240
response.deleteCookie = function(name) {
 
241
  this.setCookie({name: name, value: '', expires: 0});
 
242
};
 
243
 
 
244
function _trim(s) {
 
245
  return String((new java.lang.String(s)).trim());
 
246
}
 
247
 
 
248
response.getCookie = function(name) {
 
249
  var cookieHeaders = this.getHeader('Set-Cookie');
 
250
  if (! cookieHeaders) { return; }
 
251
  for (var i = 0; i < cookieHeaders.length; ++i) {
 
252
    if (_trim(cookieHeaders[i].split("=")[0]) == name)
 
253
      return _trim(cookieHeaders[i].split(";")[0].split("=")[1]);
 
254
  }
 
255
};
 
256
 
 
257
/**
 
258
 * Sets the Content-Type header of the response.  If the content-type includes
 
259
 * a charset, that charset is used to send the response.
 
260
 * @param {string} contentType the new content-type
 
261
 */
 
262
response.setContentType = function(contentType) {
 
263
  _cx().response().setContentType(contentType);
 
264
};
 
265
 
 
266
response.getCharacterEncoding = function() {
 
267
  return _cx().response().getCharacterEncoding();
 
268
}
 
269
 
 
270
response.neverCache = function() {
 
271
  // be aggressive about not letting the response be cached.
 
272
  var that = this;
 
273
  function sh(k,v) { that.setHeader(k,v); }
 
274
  sh('Expires', 'Sat, 18 Jun 1983 07:07:07 GMT');
 
275
  sh('Last-Modified', (new Date()).toGMTString());
 
276
  sh('Cache-Control', ('no-store, no-cache, must-revalidate, '+
 
277
                       'post-check=0, pre-check=0'));
 
278
  sh('Pragma', 'no-cache');
 
279
};
 
280
 
 
281
response.alwaysCache = function() {
 
282
  var that = this;
 
283
  function sh(k,v) { that.setHeader(k,v); }
 
284
  that.removeHeader('Last-Modified');
 
285
  that.removeHeader('Pragma');
 
286
  var futureDate = new Date();
 
287
  futureDate.setTime(Date.now() + 315360000000);
 
288
  sh('Expires', futureDate.toGMTString());
 
289
  sh('Cache-Control', 'max-age=315360000');
 
290
};
 
291
 
 
292
response.setGzip = function(gzip) {
 
293
  _cx().response().setGzip(gzip);
 
294
}