UNPKG

spirit

Version:

extensible web library for building applications & frameworks

280 lines (248 loc) 8.86 kB
"use strict"; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var mime = require("mime"); mime.default_type = undefined; var utils = require("../http/utils"); var is_Response = function is_Response(obj) { if (obj !== null && (typeof obj === "undefined" ? "undefined" : _typeof(obj)) === "object") { return obj instanceof Response; } return false; }; /* * Response is for making response maps * with chainable helper functions */ var Response = function () { function Response(body) { _classCallCheck(this, Response); this.status = 200; this.headers = {}; this.body = body; } /** * Looks up `k` from `response`'s headers * * Where `response` is a response map or Response * `k` is a case insensitive look up * * Returns back the header field matching `k` in it's original case * * @param {response} response - a response map or object that conforms to one * @param {string} k - the header field to look up (case insensitive) * @return {string|undefined} the header field that matches `k` or undefined if it doesn't exist */ _createClass(Response, [{ key: "set", value: function set(k, v) { Response.set(this, k, v); return this; } }, { key: "get", value: function get(k) { return Response.get(this, k); } }, { key: "status_", value: function status_(n) { this.status = parseInt(n); return this; } }, { key: "body_", value: function body_(body) { this.body = body; this.len(undefined); // clear any previous Content-Length return this; } }, { key: "type", value: function type(content_type) { var t = mime.lookup(content_type); if (!t) t = content_type; // auto convert body to JSON as a convienance if (t === "application/json") { var typ_body = utils.type_of(this.body); if (typ_body !== "string" && typ_body !== "stream" && typ_body !== "buffer" && typ_body !== "file-stream") { this.body = JSON.stringify(this.body); } } var charset = ""; if (mime.charsets.lookup(t)) charset = "; charset=utf-8"; return this.set("Content-Type", t + charset); } }, { key: "_clear_cookie", value: function _clear_cookie(cookies, name, path) { path = path || "/"; return cookies.filter(function (ck) { // get cookie name var _name = ck.slice(0, ck.indexOf("=")); var _path = "/"; if (_name === name) { // if name matches, check path var ck_lower = ck.toLowerCase(); var _begin = ck_lower.indexOf("path="); if (_begin !== -1) { ck = ck.slice(_begin + 5); var _end = ck.indexOf(";"); if (_end === -1) { _path = ck; } else { _path = ck.slice(0, _end); } } return _path !== path; } return true; }); } /** * Sets a cookie to headers, if the header already exists * It will append to the array (and be converted to one, if * it isn't already one) * * encodeURIComponent() is used to encode the value by default * * If value is undefined, then the cookie will not be set * And if it already exists, then all instances of it * will be removed * * Possible duplicate cookies of the same name & path * are not handled * NOTE: cookies are considered unique to it's name & path * * Options: { * path {string} * domain {string} * httponly {boolean} * maxage {string} * secure {boolean} * expires {Date} * encode {function} defaults to encodeURIComponent * } * * @param {string} name - cookie name * @param {string} value - cookie value * @param {object} opts - an object of options * @return {this} */ }, { key: "cookie", value: function cookie(name, value, opts) { // get current cookies (as an array) var curr_cookies = this.get("Set-Cookie"); if (curr_cookies === undefined) { curr_cookies = []; } else { if (Array.isArray(curr_cookies) === false) { curr_cookies = [curr_cookies]; } } // optional arguments & default values if ((typeof value === "undefined" ? "undefined" : _typeof(value)) === "object") { opts = value; value = undefined; } else if (opts === undefined) { opts = {}; } if (typeof opts.encode !== "function") opts.encode = encodeURIComponent; // is this for deletion? if (value === undefined) { var _filtered_cookies = this._clear_cookie(curr_cookies, name, opts.path); return this.set("Set-Cookie", _filtered_cookies); } // begin constructing cookie string value = [opts.encode(value)]; // * set optional values * if (opts.path !== undefined) value.push("Path=" + opts.path); if (opts.domain !== undefined) value.push("Domain=" + opts.domain); if (opts.maxage !== undefined) value.push("Max-Age=" + opts.maxage); if (opts.secure === true) value.push("Secure"); if (opts.expires !== undefined) { if (typeof opts.expires.toUTCString === "function") { value.push("Expires=" + opts.expires.toUTCString()); } else { value.push("Expires=" + opts.expires); } } if (opts.httponly === true) value.push("HttpOnly"); curr_cookies.push(name + "=" + value.join(";")); return this.set("Set-Cookie", curr_cookies); } }, { key: "len", value: function len(size) { var typ_size = typeof size === "undefined" ? "undefined" : _typeof(size); if (typ_size !== "undefined" && typ_size !== "number") { throw new TypeError("Expected number for Response len() instead got: " + typ_size); } if (size === 0) size = undefined; return this.set("Content-Length", size); } }, { key: "attachment", value: function attachment(filename) { var v = void 0; if (typeof filename === "string") { v = "attachment"; if (filename !== "") v = v + "; filename=" + filename; } return this.set("Content-Disposition", v); } }], [{ key: "field", value: function field(response, k) { // if k exists, then just return if (response[k] !== undefined) { return k; } k = k.toLowerCase(); var keys = Object.keys(response.headers); for (var i = 0; i < keys.length; i++) { if (keys[i].toLowerCase() === k) { return keys[i]; } } } }, { key: "get", value: function get(response, k) { return response.headers[Response.field(response, k)]; } }, { key: "set", value: function set(response, k, v) { var existk = Response.field(response, k); if (existk !== undefined) { // if the header already exists, and does not match // in case, resolve the duplicate headers by correcting // the case if (existk !== k) { k = k.split("-").map(function (p) { var c = p[0].toUpperCase() + p.substr(1).toLowerCase(); if (c === "Etag") return "ETag"; // special handling for ETag return c; }).join("-"); // if existk is not the correct case compared to k // then delete existk and use k instead if (existk !== k) delete response.headers[existk]; } } else { // if header doesnt exist & the value is empty // then there is nothing to do if (v === undefined) return response; } response.headers[k] = v; return response; } }]); return Response; }(); module.exports = { Response: Response, is_Response: is_Response };