1 /**
  2  * @fileOverview Helpers for the HTTP response.
  3  */
  4 
  5 /** @ignore */
  6 var _ajn = appjet._native;
  7 
  8 /**
  9  * @type object
 10  */
 11 var response = {};
 12 
 13 /**
 14  * Halts the program immediately and returns 403 Forbidden error to the user.
 15  */
 16 response.forbid = function() {
 17   _ajn.response_error(403, "Forbidden");
 18 };
 19 
 20 /**
 21  * Halts the program immediately, optionally printing the page so far.
 22  *
 23  * @param {boolean} renderCurrentPage if false, an empty page will be rendered,
 24  *   otherwise calls to print() so far will be displayed.  Either way, no more
 25  *   code will be executed.
 26  */
 27 response.stop = function(renderCurrentPage) {
 28   if (renderCurrentPage !== false) {
 29     var p = page.render();
 30     if (p.length > 0)
 31       _ajn.write(p.join(''));
 32   }
 33   _ajn.response_stop();
 34 };
 35 
 36 /**
 37  * Halts the program immediately and returns a 404 not found error to the user.
 38  */
 39 response.notFound = function() {
 40   _ajn.response_error(404, "Not found");
 41 };
 42 
 43 /**
 44  * Halts the program immediately and sends an HTTP redirect response (302),
 45  * redirecting to the given path (relative or absolute).
 46  *
 47  * @param {string} path The new path
 48  */
 49 response.redirect = function(path) {
 50   if ((! path) && path != "")
 51     throw new Error("Invalid redirect: "+path)
 52   _ajn.response_redirect(path);
 53 };
 54 
 55 /**
 56  * Sets the status code in the HTTP response.
 57  *
 58  * @param {number} newCode
 59  */
 60 response.setStatusCode = function(newCode) {
 61   _ajn.response_setStatusCode(newCode);
 62 };
 63 
 64 /**
 65  * Sets any header of the HTTP response.
 66  *
 67  * @example
 68 response.setHeader('Cache-Control', 'no-cache');
 69  *
 70  * @param {string} name
 71  * @param {string} value
 72  */
 73 response.setHeader = function(name, value) {
 74   _ajn.response_setHeader(name, value);
 75 };
 76 
 77 /**
 78  * Adds the name,value pair to the headers.  Useful for headers that are
 79  * allowed to repeat, such as Set-Cookie.
 80  *
 81  * @param {string} name
 82  * @param {string} value
 83  */
 84 response.addHeader = function(name, value) {
 85   _ajn.response_addHeader(name, value);
 86 };
 87 
 88 /**
 89  * Low-level hook for writing raw data to the response.
 90  * @param {string} data will be written, verbatim, to the HTTP resonse.
 91  */
 92 response.write = function(data) {
 93   _ajn.write(data);
 94 };
 95 
 96 /**
 97  * Low-level hook for writing raw byte data to the response. Especially
 98  * useful for writing the result of a <code>wget</code> of image data,
 99  * or writing an uploaded file.
100  * @param {string} data will be written, verbatim, to the HTTP resonse.
101  */
102 response.writeBytes = function(data) {
103   _ajn.writeBytes(data);
104 };
105 
106 //----------------------------------------------------------------
107 // Cookies!
108 //----------------------------------------------------------------
109 
110 /**
111  * Set a cookie in the response.
112  *
113  * @example
114 response.setCookie({
115   name: "SessionID",
116   value: "25",
117   secure: true,
118   expires: 14 // 14 days
119 });
120  *
121  * @param {object} cookieObject This may contain any of the following:
122 <ul>
123   <li>name (required): The name of the cookie</li>
124   <li>value (required): The value of the cookie.  (Note: this value will be escaped).
125   <li>expires (optional): If an integer, means number of days until it expires;
126         if a Date object, means exact date on which to expire.</li>
127   <li>domain (optional): The cookie domain</li>
128   <li>path (optional): To restrict the cookie to a specific path.</li>
129   <li>secure (optional): Whether this cookie should only be sent securely.</li>
130 </ul>
131  */
132 response.setCookie = function(cookieObject) {
133   response.addHeader('Set-Cookie', _cookiestring(cookieObject));
134 };
135 
136 
137 /**
138  * Tells the client to delete the cookie of the given name (by setting
139  * its expiration time to zero).
140  * @param {string} name The name of the cookie to delete.
141  */
142 response.deleteCookie = function(name) {
143   response.setCookie({name: name, value: '', expires: 0});
144 };
145 
146 /**
147  * Sets the Content-Type header of the response.  If the content-type includes
148  * a charset, that charset is used to send the response.
149  * @param {string} contentType the new content-type
150  */
151 response.setContentType = function(contentType) {
152   _ajn.response_setContentType(contentType);
153 }
154 
155 /** @ignore */
156 function _cookiestring(c) {
157   var x = '';
158   if (!c.name) { throw new Error('cookie name is required'); }
159   if (!c.value) { c.value = ''; }
160   x += (c.name + '=' + escape(c.value));
161 
162   // expires
163   if (c.expires instanceof Date) {
164     x += ('; expires='+_cookiedate(c.expires));
165   }
166   if (typeof(c.expires) == 'number') {
167     var today = (new Date()).valueOf();
168     var d = new Date(today + 86400000*c.expires);
169     x += ('; expires='+_cookiedate(d));
170   }
171 
172   // domain
173   if (c.domain) { x += ('; domain='+c.domain); }
174 
175   // path
176   if (c.path) { x += ('; path='+c.path); }
177 
178   // secure
179   if (c.secure == true) { x += '; secure'; }
180 
181   return x;
182 }
183 
184 /** @ignore */
185 function _cookiedate(d) {
186   var x = d.toGMTString();
187   var p = x.split(' ');
188   return [p[0], [p[1], p[2], p[3]].join('-'), p[4], p[5]].join(' ');
189 }
190 
191 /**
192  * Tells the client to cache the page. By default, clients are told to
193  * not never cache pages. (To send no caching-related headers at all, pass
194  * <code>undefined</code>.)
195  * @param {boolean} cacheable
196  */
197 response.setCacheable = function(cacheable) {
198   appjet._internal.cacheable = cacheable;
199 }
200 
201 /** @ignore */
202 appjet._internal.cacheable = false;
203