1 /* 2 * Geddy JavaScript Web development framework 3 * Copyright 2112 Matthew Eernisse (mde@fleegix.org) 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 var fs = require('fs') 20 , errors = require('./errors'); 21 22 var response = new function () { 23 24 this.formats = { 25 txt: 'text/plain', 26 html: 'text/html', 27 json: 'application/json|text/json', 28 js: 'application/javascript|text/javascript', 29 xml: 'application/xml|text/xml' 30 }; 31 32 this.formatsReverseMap = {}; 33 this.formatPatterns = {}; 34 this.formatsPreferred = {}; 35 var formatTypes; 36 for (var p in this.formats) { 37 formatTypes = this.formats[p].split('|'); 38 this.formatsPreferred[p] = formatTypes[0]; 39 for (var i = 0; i < formatTypes.length; i++) { 40 this.formatsReverseMap[formatTypes[i]] = p; 41 } 42 this.formatPatterns[p] = new RegExp( 43 this.formats[p].replace(/(\/)/g, "\\$1")); 44 } 45 46 // From Paperboy, http://github.com/felixge/node-paperboy 47 this.contentTypes = JSON.parse(fs.readFileSync(__dirname + 48 '/content_types.json').toString()); 49 50 this.charsets = { 51 'text/javascript': 'UTF-8', 52 'text/html': 'UTF-8' 53 }; 54 55 }(); 56 57 var Response = function (resp) { 58 this.resp = resp; 59 }; 60 61 Response.prototype = new function () { 62 this.send = function (content, statusCode, headers) { 63 var success = !errors.errorTypes[statusCode]; 64 var s = statusCode || 200; 65 var h = headers || {}; 66 this.setHeaders(s, h); 67 this.finalize(content); 68 }; 69 70 this.finalize = function (content) { 71 this.writeBody(content); 72 this.finish(); 73 }; 74 75 this.sendFile = function (filepath) { 76 var _this = this; 77 var ext = geddy.uri.getFileExtension(filepath); 78 var contentType = response.contentTypes[ext] || 'application/octet-stream'; 79 var encoding = 'binary'; 80 81 this.setHeaders(200, {'Content-Type': contentType}); 82 83 // From Paperboy, http://github.com/felixge/node-paperboy 84 fs.open(filepath, 'r', 0666, function (err, fd) { 85 var pos = 0; 86 var streamChunk = function () { 87 fs.read(fd, 16 * 1024, pos, encoding, 88 function (err, chunk, bytesRead) { 89 if (!chunk) { 90 fs.close(fd); 91 _this.resp.end(); 92 /* 93 log.debug('FILE: sent static file ' + filepath + '\nFinished handling request in ' + 94 ((new Date().getTime()) - _this.resp.startTime) + ' ms').flush(); 95 */ 96 return; 97 } 98 99 _this.resp.write(chunk, encoding); 100 pos += bytesRead; 101 102 streamChunk(); 103 }); 104 } 105 streamChunk(); 106 }); 107 108 }; 109 110 this.setHeaders = function (statusCode, headers) { 111 var contentType = headers['Content-Type']; 112 var charset = response.charsets[contentType]; 113 if (charset) { 114 contentType += '; charset: ' + charset; 115 headers['Content-Type'] = contentType; 116 } 117 this.resp.statusCode = statusCode; 118 for (var p in headers) { 119 this.resp.setHeader(p, headers[p]); 120 } 121 }; 122 123 this.writeBody = function (content) { 124 this.resp.write(content); 125 }; 126 127 this.finish = function (success) { 128 this.resp.end(); 129 if (success) { 130 /* 131 log.debug('Finished handling request in ' + 132 ((new Date().getTime()) - this.resp.startTime) + ' ms').flush(); 133 */ 134 } 135 }; 136 137 }(); 138 139 for (var p in response) { exports[p] = response[p]; } 140 exports.Response = Response; 141 142