raspberryGPIOhtmlserver/node_modules/express/lib/response.js
node_modules/express/lib/response.jsRaw
1/**
2 * Module dependencies.
3 */
4
5var http = require('http')
6 , path = require('path')
7 , connect = require('connect')
8 , utils = connect.utils
9 , sign = require('cookie-signature').sign
10 , normalizeType = require('./utils').normalizeType
11 , normalizeTypes = require('./utils').normalizeTypes
12 , etag = require('./utils').etag
13 , statusCodes = http.STATUS_CODES
14 , cookie = require('cookie')
15 , send = require('send')
16 , mime = connect.mime
17 , basename = path.basename
18 , extname = path.extname
19 , join = path.join;
20
21/**
22 * Response prototype.
23 */
24
25var res = module.exports = {
26 __proto__: http.ServerResponse.prototype
27};
28
29/**
30 * Set status `code`.
31 *
32 * @param {Number} code
33 * @return {ServerResponse}
34 * @api public
35 */
36
37res.status = function(code){
38 this.statusCode = code;
39 return this;
40};
41
42/**
43 * Set Link header field with the given `links`.
44 *
45 * Examples:
46 *
47 * res.links({
48 * next: 'http://api.example.com/users?page=2',
49 * last: 'http://api.example.com/users?page=5'
50 * });
51 *
52 * @param {Object} links
53 * @return {ServerResponse}
54 * @api public
55 */
56
57res.links = function(links){
58 return this.set('Link', Object.keys(links).map(function(rel){
59 return '<' + links[rel] + '>; rel="' + rel + '"';
60 }).join(', '));
61};
62
63/**
64 * Send a response.
65 *
66 * Examples:
67 *
68 * res.send(new Buffer('wahoo'));
69 * res.send({ some: 'json' });
70 * res.send('<p>some html</p>');
71 * res.send(404, 'Sorry, cant find that');
72 * res.send(404);
73 *
74 * @param {Mixed} body or status
75 * @param {Mixed} body
76 * @return {ServerResponse}
77 * @api public
78 */
79
80res.send = function(body){
81 var req = this.req;
82 var head = 'HEAD' == req.method;
83 var len;
84
85 // allow status / body
86 if (2 == arguments.length) {
87 // res.send(body, status) backwards compat
88 if ('number' != typeof body && 'number' == typeof arguments[1]) {
89 this.statusCode = arguments[1];
90 } else {
91 this.statusCode = body;
92 body = arguments[1];
93 }
94 }
95
96 switch (typeof body) {
97 // response status
98 case 'number':
99 this.get('Content-Type') || this.type('txt');
100 this.statusCode = body;
101 body = http.STATUS_CODES[body];
102 break;
103 // string defaulting to html
104 case 'string':
105 if (!this.get('Content-Type')) {
106 this.charset = this.charset || 'utf-8';
107 this.type('html');
108 }
109 break;
110 case 'boolean':
111 case 'object':
112 if (null == body) {
113 body = '';
114 } else if (Buffer.isBuffer(body)) {
115 this.get('Content-Type') || this.type('bin');
116 } else {
117 return this.json(body);
118 }
119 break;
120 }
121
122 // populate Content-Length
123 if (undefined !== body && !this.get('Content-Length')) {
124 this.set('Content-Length', len = Buffer.isBuffer(body)
125 ? body.length
126 : Buffer.byteLength(body));
127 }
128
129 // ETag support
130 // TODO: W/ support
131 if (len > 1024 && 'GET' == req.method) {
132 if (!this.get('ETag')) {
133 this.set('ETag', etag(body));
134 }
135 }
136
137 // freshness
138 if (req.fresh) this.statusCode = 304;
139
140 // strip irrelevant headers
141 if (204 == this.statusCode || 304 == this.statusCode) {
142 this.removeHeader('Content-Type');
143 this.removeHeader('Content-Length');
144 this.removeHeader('Transfer-Encoding');
145 body = '';
146 }
147
148 // respond
149 this.end(head ? null : body);
150 return this;
151};
152
153/**
154 * Send JSON response.
155 *
156 * Examples:
157 *
158 * res.json(null);
159 * res.json({ user: 'tj' });
160 * res.json(500, 'oh noes!');
161 * res.json(404, 'I dont have that');
162 *
163 * @param {Mixed} obj or status
164 * @param {Mixed} obj
165 * @return {ServerResponse}
166 * @api public
167 */
168
169res.json = function(obj){
170 // allow status / body
171 if (2 == arguments.length) {
172 // res.json(body, status) backwards compat
173 if ('number' == typeof arguments[1]) {
174 this.statusCode = arguments[1];
175 } else {
176 this.statusCode = obj;
177 obj = arguments[1];
178 }
179 }
180
181 // settings
182 var app = this.app;
183 var replacer = app.get('json replacer');
184 var spaces = app.get('json spaces');
185 var body = JSON.stringify(obj, replacer, spaces);
186
187 // content-type
188 this.charset = this.charset || 'utf-8';
189 this.get('Content-Type') || this.set('Content-Type', 'application/json');
190
191 return this.send(body);
192};
193
194/**
195 * Send JSON response with JSONP callback support.
196 *
197 * Examples:
198 *
199 * res.jsonp(null);
200 * res.jsonp({ user: 'tj' });
201 * res.jsonp(500, 'oh noes!');
202 * res.jsonp(404, 'I dont have that');
203 *
204 * @param {Mixed} obj or status
205 * @param {Mixed} obj
206 * @return {ServerResponse}
207 * @api public
208 */
209
210res.jsonp = function(obj){
211 // allow status / body
212 if (2 == arguments.length) {
213 // res.json(body, status) backwards compat
214 if ('number' == typeof arguments[1]) {
215 this.statusCode = arguments[1];
216 } else {
217 this.statusCode = obj;
218 obj = arguments[1];
219 }
220 }
221
222 // settings
223 var app = this.app;
224 var replacer = app.get('json replacer');
225 var spaces = app.get('json spaces');
226 var body = JSON.stringify(obj, replacer, spaces)
227 .replace(/\u2028/g, '\\u2028')
228 .replace(/\u2029/g, '\\u2029');
229 var callback = this.req.query[app.get('jsonp callback name')];
230
231 // content-type
232 this.charset = this.charset || 'utf-8';
233 this.set('Content-Type', 'application/json');
234
235 // jsonp
236 if (callback) {
237 this.set('Content-Type', 'text/javascript');
238 var cb = callback.replace(/[^\[\]\w$.]/g, '');
239 body = cb + ' && ' + cb + '(' + body + ');';
240 }
241
242 return this.send(body);
243};
244
245/**
246 * Transfer the file at the given `path`.
247 *
248 * Automatically sets the _Content-Type_ response header field.
249 * The callback `fn(err)` is invoked when the transfer is complete
250 * or when an error occurs. Be sure to check `res.sentHeader`
251 * if you wish to attempt responding, as the header and some data
252 * may have already been transferred.
253 *
254 * Options:
255 *
256 * - `maxAge` defaulting to 0
257 * - `root` root directory for relative filenames
258 *
259 * Examples:
260 *
261 * The following example illustrates how `res.sendfile()` may
262 * be used as an alternative for the `static()` middleware for
263 * dynamic situations. The code backing `res.sendfile()` is actually
264 * the same code, so HTTP cache support etc is identical.
265 *
266 * app.get('/user/:uid/photos/:file', function(req, res){
267 * var uid = req.params.uid
268 * , file = req.params.file;
269 *
270 * req.user.mayViewFilesFrom(uid, function(yes){
271 * if (yes) {
272 * res.sendfile('/uploads/' + uid + '/' + file);
273 * } else {
274 * res.send(403, 'Sorry! you cant see that.');
275 * }
276 * });
277 * });
278 *
279 * @param {String} path
280 * @param {Object|Function} options or fn
281 * @param {Function} fn
282 * @api public
283 */
284
285res.sendfile = function(path, options, fn){
286 var self = this
287 , req = self.req
288 , next = this.req.next
289 , options = options || {}
290 , done;
291
292 // support function as second arg
293 if ('function' == typeof options) {
294 fn = options;
295 options = {};
296 }
297
298 // socket errors
299 req.socket.on('error', error);
300
301 // errors
302 function error(err) {
303 if (done) return;
304 done = true;
305
306 // clean up
307 cleanup();
308 if (!self.headerSent) self.removeHeader('Content-Disposition');
309
310 // callback available
311 if (fn) return fn(err);
312
313 // list in limbo if there's no callback
314 if (self.headerSent) return;
315
316 // delegate
317 next(err);
318 }
319
320 // streaming
321 function stream() {
322 if (done) return;
323 cleanup();
324 if (fn) self.on('finish', fn);
325 }
326
327 // cleanup
328 function cleanup() {
329 req.socket.removeListener('error', error);
330 }
331
332 // transfer
333 var file = send(req, path);
334 if (options.root) file.root(options.root);
335 file.maxage(options.maxAge || 0);
336 file.on('error', error);
337 file.on('directory', next);
338 file.on('stream', stream);
339 file.pipe(this);
340 this.on('finish', cleanup);
341};
342
343/**
344 * Transfer the file at the given `path` as an attachment.
345 *
346 * Optionally providing an alternate attachment `filename`,
347 * and optional callback `fn(err)`. The callback is invoked
348 * when the data transfer is complete, or when an error has
349 * ocurred. Be sure to check `res.headerSent` if you plan to respond.
350 *
351 * This method uses `res.sendfile()`.
352 *
353 * @param {String} path
354 * @param {String|Function} filename or fn
355 * @param {Function} fn
356 * @api public
357 */
358
359res.download = function(path, filename, fn){
360 // support function as second arg
361 if ('function' == typeof filename) {
362 fn = filename;
363 filename = null;
364 }
365
366 filename = filename || path;
367 this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
368 return this.sendfile(path, fn);
369};
370
371/**
372 * Set _Content-Type_ response header with `type` through `mime.lookup()`
373 * when it does not contain "/", or set the Content-Type to `type` otherwise.
374 *
375 * Examples:
376 *
377 * res.type('.html');
378 * res.type('html');
379 * res.type('json');
380 * res.type('application/json');
381 * res.type('png');
382 *
383 * @param {String} type
384 * @return {ServerResponse} for chaining
385 * @api public
386 */
387
388res.contentType =
389res.type = function(type){
390 return this.set('Content-Type', ~type.indexOf('/')
391 ? type
392 : mime.lookup(type));
393};
394
395/**
396 * Respond to the Acceptable formats using an `obj`
397 * of mime-type callbacks.
398 *
399 * This method uses `req.accepted`, an array of
400 * acceptable types ordered by their quality values.
401 * When "Accept" is not present the _first_ callback
402 * is invoked, otherwise the first match is used. When
403 * no match is performed the server responds with
404 * 406 "Not Acceptable".
405 *
406 * Content-Type is set for you, however if you choose
407 * you may alter this within the callback using `res.type()`
408 * or `res.set('Content-Type', ...)`.
409 *
410 * res.format({
411 * 'text/plain': function(){
412 * res.send('hey');
413 * },
414 *
415 * 'text/html': function(){
416 * res.send('<p>hey</p>');
417 * },
418 *
419 * 'appliation/json': function(){
420 * res.send({ message: 'hey' });
421 * }
422 * });
423 *
424 * In addition to canonicalized MIME types you may
425 * also use extnames mapped to these types:
426 *
427 * res.format({
428 * text: function(){
429 * res.send('hey');
430 * },
431 *
432 * html: function(){
433 * res.send('<p>hey</p>');
434 * },
435 *
436 * json: function(){
437 * res.send({ message: 'hey' });
438 * }
439 * });
440 *
441 * By default Express passes an `Error`
442 * with a `.status` of 406 to `next(err)`
443 * if a match is not made. If you provide
444 * a `.default` callback it will be invoked
445 * instead.
446 *
447 * @param {Object} obj
448 * @return {ServerResponse} for chaining
449 * @api public
450 */
451
452res.format = function(obj){
453 var req = this.req
454 , next = req.next;
455
456 var fn = obj.default;
457 if (fn) delete obj.default;
458 var keys = Object.keys(obj);
459
460 var key = req.accepts(keys);
461
462 this.set('Vary', 'Accept');
463
464 if (key) {
465 this.set('Content-Type', normalizeType(key).value);
466 obj[key](req, this, next);
467 } else if (fn) {
468 fn();
469 } else {
470 var err = new Error('Not Acceptable');
471 err.status = 406;
472 err.types = normalizeTypes(keys).map(function(o){ return o.value });
473 next(err);
474 }
475
476 return this;
477};
478
479/**
480 * Set _Content-Disposition_ header to _attachment_ with optional `filename`.
481 *
482 * @param {String} filename
483 * @return {ServerResponse}
484 * @api public
485 */
486
487res.attachment = function(filename){
488 if (filename) this.type(extname(filename));
489 this.set('Content-Disposition', filename
490 ? 'attachment; filename="' + basename(filename) + '"'
491 : 'attachment');
492 return this;
493};
494
495/**
496 * Set header `field` to `val`, or pass
497 * an object of header fields.
498 *
499 * Examples:
500 *
501 * res.set('Foo', ['bar', 'baz']);
502 * res.set('Accept', 'application/json');
503 * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
504 *
505 * Aliased as `res.header()`.
506 *
507 * @param {String|Object|Array} field
508 * @param {String} val
509 * @return {ServerResponse} for chaining
510 * @api public
511 */
512
513res.set =
514res.header = function(field, val){
515 if (2 == arguments.length) {
516 if (Array.isArray(val)) val = val.map(String);
517 else val = String(val);
518 this.setHeader(field, val);
519 } else {
520 for (var key in field) {
521 this.set(key, field[key]);
522 }
523 }
524 return this;
525};
526
527/**
528 * Get value for header `field`.
529 *
530 * @param {String} field
531 * @return {String}
532 * @api public
533 */
534
535res.get = function(field){
536 return this.getHeader(field);
537};
538
539/**
540 * Clear cookie `name`.
541 *
542 * @param {String} name
543 * @param {Object} options
544 * @param {ServerResponse} for chaining
545 * @api public
546 */
547
548res.clearCookie = function(name, options){
549 var opts = { expires: new Date(1), path: '/' };
550 return this.cookie(name, '', options
551 ? utils.merge(opts, options)
552 : opts);
553};
554
555/**
556 * Set cookie `name` to `val`, with the given `options`.
557 *
558 * Options:
559 *
560 * - `maxAge` max-age in milliseconds, converted to `expires`
561 * - `signed` sign the cookie
562 * - `path` defaults to "/"
563 *
564 * Examples:
565 *
566 * // "Remember Me" for 15 minutes
567 * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
568 *
569 * // save as above
570 * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
571 *
572 * @param {String} name
573 * @param {String|Object} val
574 * @param {Options} options
575 * @api public
576 */
577
578res.cookie = function(name, val, options){
579 options = utils.merge({}, options);
580 var secret = this.req.secret;
581 var signed = options.signed;
582 if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
583 if ('number' == typeof val) val = val.toString();
584 if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
585 if (signed) val = 's:' + sign(val, secret);
586 if ('maxAge' in options) {
587 options.expires = new Date(Date.now() + options.maxAge);
588 options.maxAge /= 1000;
589 }
590 if (null == options.path) options.path = '/';
591 this.set('Set-Cookie', cookie.serialize(name, String(val), options));
592 return this;
593};
594
595
596/**
597 * Set the location header to `url`.
598 *
599 * The given `url` can also be the name of a mapped url, for
600 * example by default express supports "back" which redirects
601 * to the _Referrer_ or _Referer_ headers or "/".
602 *
603 * Examples:
604 *
605 * res.location('/foo/bar').;
606 * res.location('http://example.com');
607 * res.location('../login'); // /blog/post/1 -> /blog/login
608 *
609 * Mounting:
610 *
611 * When an application is mounted and `res.location()`
612 * is given a path that does _not_ lead with "/" it becomes
613 * relative to the mount-point. For example if the application
614 * is mounted at "/blog", the following would become "/blog/login".
615 *
616 * res.location('login');
617 *
618 * While the leading slash would result in a location of "/login":
619 *
620 * res.location('/login');
621 *
622 * @param {String} url
623 * @api public
624 */
625
626res.location = function(url){
627 var app = this.app
628 , req = this.req;
629
630 // setup redirect map
631 var map = { back: req.get('Referrer') || '/' };
632
633 // perform redirect
634 url = map[url] || url;
635
636 // relative
637 if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
638 var path
639
640 // relative to path
641 if ('.' == url[0]) {
642 path = req.originalUrl.split('?')[0]
643 url = path + ('/' == path[path.length - 1] ? '' : '/') + url;
644 // relative to mount-point
645 } else if ('/' != url[0]) {
646 path = app.path();
647 url = path + '/' + url;
648 }
649 }
650
651 // Respond
652 this.set('Location', url);
653 return this;
654};
655
656/**
657 * Redirect to the given `url` with optional response `status`
658 * defaulting to 302.
659 *
660 * The resulting `url` is determined by `res.location()`, so
661 * it will play nicely with mounted apps, relative paths,
662 * `"back"` etc.
663 *
664 * Examples:
665 *
666 * res.redirect('/foo/bar');
667 * res.redirect('http://example.com');
668 * res.redirect(301, 'http://example.com');
669 * res.redirect('http://example.com', 301);
670 * res.redirect('../login'); // /blog/post/1 -> /blog/login
671 *
672 * @param {String} url
673 * @param {Number} code
674 * @api public
675 */
676
677res.redirect = function(url){
678 var app = this.app
679 , head = 'HEAD' == this.req.method
680 , status = 302
681 , body;
682
683 // allow status / url
684 if (2 == arguments.length) {
685 if ('number' == typeof url) {
686 status = url;
687 url = arguments[1];
688 } else {
689 status = arguments[1];
690 }
691 }
692
693 // Set location header
694 this.location(url);
695 url = this.get('Location');
696
697 // Support text/{plain,html} by default
698 this.format({
699 text: function(){
700 body = statusCodes[status] + '. Redirecting to ' + encodeURI(url);
701 },
702
703 html: function(){
704 var u = utils.escape(url);
705 body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
706 },
707
708 default: function(){
709 body = '';
710 }
711 });
712
713 // Respond
714 this.statusCode = status;
715 this.set('Content-Length', Buffer.byteLength(body));
716 this.end(head ? null : body);
717};
718
719/**
720 * Render `view` with the given `options` and optional callback `fn`.
721 * When a callback function is given a response will _not_ be made
722 * automatically, otherwise a response of _200_ and _text/html_ is given.
723 *
724 * Options:
725 *
726 * - `cache` boolean hinting to the engine it should cache
727 * - `filename` filename of the view being rendered
728 *
729 * @param {String} view
730 * @param {Object|Function} options or callback function
731 * @param {Function} fn
732 * @api public
733 */
734
735res.render = function(view, options, fn){
736 var self = this
737 , options = options || {}
738 , req = this.req
739 , app = req.app;
740
741 // support callback function as second arg
742 if ('function' == typeof options) {
743 fn = options, options = {};
744 }
745
746 // merge res.locals
747 options._locals = self.locals;
748
749 // default callback to respond
750 fn = fn || function(err, str){
751 if (err) return req.next(err);
752 self.send(str);
753 };
754
755 // render
756 app.render(view, options, fn);
757};