jsboost
Version:
A tiny library that extends the capability of javascript
169 lines (143 loc) • 4.11 kB
JavaScript
/**
* Author: JCloudYu
* Create: 2019/03/22
**/
/**
* Cookie attributes
* @typedef {Object} CookieAttribute
* @property {String} [domain=null]
* @property {String} [path=/]
* @property {Number} [duration=0]
* @property {Boolean} [sslOnly=false]
* @property {Boolean} [httpOnly=true]
* @property {String} [sameSite=strict]
**/
export const CastHTTPStringSymbol = Symbol( 'Cast-To-Http-SetCookie-Header' );
export class HTTPCookieItem {
constructor(name, value) {
this.name = name;
this.value = value;
this.domain = null;
this.path = '/';
this.duration = null;
this.ssl_only = false;
this.http_only = true;
this.same_site_policy = 'Strict';
}
get [CastHTTPStringSymbol]() {
const _key = `${this.name}`.trim();
if ( _key === "" ) {
throw new TypeError("Cookie name cannot be empty!");
}
const key = _key;
const val = `${this.value}`.trim();
const attr = [ `${key}=${val}` ];
if ( this.domain !== null ) {
attr.push( `Domain=${this.domain}` );
}
if ( this.path !== null ) {
attr.push( `Path=${this.path}` );
}
if ( this.duration !== null ) {
if ( typeof this.duration !== "number" ) {
throw new TypeError( "Cookie duration must be an number!" );
}
const expire = new Date(Date.now() + this.duration * 1000);
attr.push( `Max-Age=${this.duration}` );
attr.push( `Expires=${expire.toUTCString()}` );
}
if ( this.ssl_only ) {
attr.push( 'Secure' );
}
if ( this.http_only ) {
attr.push( 'HttpOnly' );
}
if ( this.same_site_policy !== null ) {
attr.push( `SameSite=${this.same_site_policy}` );
}
return `${attr.join('; ')}`;
}
get [Symbol.toStringTag]() {
return 'HTTPCookie';
}
}
export class HTTPCookies {
constructor() {
this._cookies = Object.create(null);
}
/**
* Add a HTTPCookie info
* @param {HTTPCookieItem} cookie
**/
add(cookie) {
if ( !(cookie instanceof HTTPCookieItem) ) {
throw new TypeError( "Incoming cookie must be an HTTPCookie object!" );
}
this._cookies[cookie.name] = cookie;
return cookie;
}
/**
* Creat a cookie
* @param {String} name
* @param {String} value
* @param {CookieAttribute} options
* @returns {HTTPCookieItem}
**/
set(name, value, options={domain:null, path:'/', duration:null, sslOnly:false, httpOnly:true, sameSite:'strict'}) {
const cookie = new HTTPCookieItem(name, value);
cookie.domain = (options.domain === undefined) ? null : options.domain;
cookie.path = (options.path === undefined) ? null : options.path;
cookie.duration = (options.duration === undefined) ? null : options.duration;
cookie.ssl_only = (options.sslOnly === undefined) ? false : !!options.sslOnly;
cookie.http_only = (options.httpOnly === undefined) ? true : !!options.httpOnly;
cookie.same_site_policy = (options.sameSite === undefined) ? null : options.sameSite;
this._cookies[cookie.name] = cookie;
return cookie;
}
/**
* Retrieve a cookie
* @param {String} name
* @returns {HTTPCookieItem|null}
**/
get(name) {
return this._cookies[name]||null;
}
/**
* Retrieve the array of cookie values that can be used in http header
* @return {String[]}
**/
getHttpCookies() {
return this[CastHTTPStringSymbol];
}
/**
* @private
**/
get [CastHTTPStringSymbol]() {
const Header = [];
for( let _ in this._cookies ) {
const cookie = this._cookies[_];
if ( !(cookie instanceof HTTPCookieItem) ) continue;
Header.push(cookie[CastHTTPStringSymbol]);
}
return Header;
}
/**
* @param {String} rawCookies
* @returns {HTTPCookies}
**/
static FromRawCookies(rawCookies) {
rawCookies = rawCookies.trim();
const CookieList = new HTTPCookies();
const cookies = rawCookies.split(';');
for( const raw_cookie of cookies ) {
let cookie = raw_cookie.trim();
if ( !cookie ) continue;
const _splitter = cookie.indexOf( '=' );
if ( _splitter < 0 ) continue;
const name = cookie.substring(0, _splitter);
const value = cookie.substring(_splitter+1);
CookieList.add(new HTTPCookieItem(name, value));
}
return CookieList;
}
}