You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.2 KiB

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<string | undefined> {
return this._parsed[key]
}
/**
* Get the parsed value of a cookie, if it is defined.
* @param {string} key
* @return Promise<MaybeCookie>
*/
public async get(key: string): Promise<MaybeCookie> {
// 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<void>
*/
public async set(key: string, value: any): Promise<void> {
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<boolean>
*/
public async has(key: string): Promise<boolean> {
return (await this._cache.has(key)) || key in this._parsed
}
/**
* Deletes the given cookie, if it exists.
* @param {string} key
* @return Promise<void>
*/
public async delete(key: string): Promise<void> {
await this._cache.drop(key)
deleteCookie(this.request.response, key)
}
}