import { Injectable } from '../../../di/src/decorator/Injection.ts' import { getCookies, setCookie, deleteCookie, ServerRequest } from '../external/http.ts' import { InMemCache } from '../support/InMemCache.ts' import { HTTPRequest } from './type/HTTPRequest.ts' /** * Base type representing a parsed cookie. */ export interface Cookie { key: string, original_value: string, value: any, } /** * Type representing what might be a cookie, or might be undefined. */ export type MaybeCookie = Cookie | undefined // TODO cookie options (http only, expires, &c.) /** * Base class for managing cookies. */ @Injectable() export class CookieJar { /** * Cache of parsed cookie values. * @type object */ protected _parsed: { [key: string]: string } = {} /** * Cache of cookie values. * @type InMemCache */ protected _cache = new InMemCache() constructor( /** * The associated request. * @type HTTPRequest */ protected request: HTTPRequest, ) { this._parsed = getCookies(this.request.to_native) } /** * Get the raw value of a cookie string, if it is defined. * @param {string} key * @return string | undefined */ public async get_raw(key: string): Promise { return this._parsed[key] } /** * Get the parsed value of a cookie, if it is defined. * @param {string} key * @return Promise */ public async get(key: string): Promise { // Try the cache if ( await this._cache.has(key) ) { return JSON.parse((await this._cache.fetch(key)) || '""') as Cookie } // If the cache missed, try to parse it and load in cache if ( key in this._parsed ) { let value = this._parsed[key] try { value = JSON.parse(atob(this._parsed[key])) } catch(e) {} const cookie = { key, value, original_value: this._parsed[key], } await this._cache.put(key, JSON.stringify(cookie)) return cookie } } /** * Set the cookie for the given key to the serialized value. * @param {string} key * @param value * @return Promise */ public async set(key: string, value: any): Promise { const original_value = btoa(JSON.stringify(value)) const cookie = { key, value, original_value, } await this._cache.put(key, JSON.stringify(cookie)) setCookie(this.request.response, { name: key, value: original_value }) } /** * Returns true if the given cookie exists. * @param {string} key * @return Promise */ public async has(key: string): Promise { return (await this._cache.has(key)) || key in this._parsed } /** * Deletes the given cookie, if it exists. * @param {string} key * @return Promise */ public async delete(key: string): Promise { await this._cache.drop(key) deleteCookie(this.request.response, key) } }