spirit
Version:
extensible web library for building applications & frameworks
280 lines (248 loc) • 8.86 kB
JavaScript
"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
};