Skip to content

Commit

Permalink
feat: configurable responseCache headers
Browse files Browse the repository at this point in the history
The `responseCache` now supports more flexible header caching. Specify which headers you care about when you cache a response:

```javascript
import { responseCache } from "@fly/cache"

responseCache.set("key", resp, { skipCacheHeaders: ["authorization", "set-cookie"] }) // default

responseCachce.set("key", resp, { skipCacheHeaders: ["content-length"] }) // custom + default
```
  • Loading branch information
jphenow authored and mrkurt committed Sep 10, 2018
1 parent f8fff92 commit b84c513
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 24 deletions.
6 changes: 3 additions & 3 deletions v8env/src/fly/cache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
/** */
declare var bridge: any
export interface CacheSetOptions {
ttl?: number,
tags?: string[],
onlyIfEmpty?: boolean
ttl?: number;
tags?: string[];
onlyIfEmpty?: boolean;
}


Expand Down
48 changes: 30 additions & 18 deletions v8env/src/fly/cache/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ import cache, { CacheSetOptions } from "."
*/
export interface Metadata {
status: number,
headers: any,
headers: { [key: string]: string | null},
at?: number,
ttl: number,
tags?: string[]
}

export interface ResponseCacheSetOptions extends CacheSetOptions {
skipCacheHeaders?: string[]
}

/**
* A response with cache info attached
*/
Expand All @@ -57,7 +61,7 @@ export async function get(key: string) {
let age = 0;
if (meta.at) {
age = Math.round(Date.now() / 1000) - meta.at;
meta.headers.Age = age
meta.headers.Age = age.toString();
meta.headers['Fly-Age'] = meta.headers.Age;
delete meta.at;
}
Expand Down Expand Up @@ -90,15 +94,9 @@ export function setMeta(key: string, meta: Metadata, options?: CacheSetOptions |
return cache.set(key + ":meta", JSON.stringify(meta), options)
}

const goodHeaders = [
'content-type',
'content-length',
'content-encoding',
'cache-control',
'expires',
'link',
'set-cookie',
'etag'
const defaultSkipHeaders = [
'authorization',
'set-cookie'
];

/**
Expand All @@ -107,9 +105,15 @@ const goodHeaders = [
* @param resp The response to cache
* @param options Time to live
*/
export async function set(key: string, resp: Response, options?: CacheSetOptions | number) {
const ttl = typeof options === "number" ? options : (options && options.ttl)
const tags = typeof options === "object" ? options.tags : undefined
export async function set(key: string, resp: Response, options?: ResponseCacheSetOptions | number) {
const ttl = typeof options === "number" ? options : (options && options.ttl);
let tags: string[] | undefined = undefined;
let skipHeaderOption: string[] = defaultSkipHeaders;
if (typeof options === "object") {
tags = options.tags;
skipHeaderOption = [...skipHeaderOption, ...(options.skipCacheHeaders || []).map((headerKey) => headerKey.toLowerCase())];
}

const meta = {
status: resp.status,
headers: {},
Expand All @@ -126,10 +130,18 @@ export async function set(key: string, resp: Response, options?: CacheSetOptions
resp.headers.set("etag", etag)
}

for (const h of goodHeaders) {
const v = resp.headers.getAll(h);
if (v && v.length > 0) {
meta.headers[h] = v.join(', ');
const skipHeaderSet = new Set(skipHeaderOption);
for(const headerSet of resp.headers as any) {
const [name, value] = headerSet;
if (skipHeaderSet.has(name.toLowerCase())) {
continue;
}

const existingVal = meta.headers[name];
if (existingVal) {
meta.headers[name] = `${existingVal}, ${value}`;
} else {
meta.headers[name] = value;
}
}
return cacheResult([
Expand Down
48 changes: 45 additions & 3 deletions v8env/test/fly.cache.response.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { expect } from 'chai'
import cache, { responseCache } from "@fly/cache"

let counter = 0
async function makeResponse() {
async function makeResponse(initResponseOptions, setCacheOptions) {
let key = `cache-test-key-${counter++}`
const resp = new Response("hi", { status: 404 })
const setResult = await responseCache.set(key, resp)
const responseInitOptions = Object.assign({ status: 404 }, initResponseOptions)
const resp = new Response("hi", responseInitOptions)
const setResult = await responseCache.set(key, resp, setCacheOptions)

expect(setResult).to.eq(true)
return [key, resp]
Expand All @@ -24,6 +25,47 @@ describe("@fly/cache/response", () => {
expect(cachedResponse.status).to.eq(404)
})

it("sets a Response with headers", async () => {
const [key, resp] = await makeResponse({ headers: { "authorization": "foo", "content-type": "text/plain; charset=utf-8" } })
const cachedResponse = await responseCache.get(key)

expect(cachedResponse).instanceOf(Response)
const cachedBody = await cachedResponse.text()
const body = await resp.text()

expect(cachedBody).to.eq(body)
expect(cachedResponse.status).to.eq(404)

const meta = await responseCache.getMeta(key)
expect(meta.headers["authorization"]).to.eq(undefined)
expect(meta.headers["content-type"]).to.eq("text/plain; charset=utf-8")
})

it("sets a Response with headers, and custom skip-headers", async () => {
const [key, resp] = await makeResponse({
headers: {
"authorization": "foo",
"content-type": "text/plain; charset=utf-8",
"content-length": "538",
"content-encoding": "gzip"
}
}, { skipCacheHeaders: ["content-length"] })
const cachedResponse = await responseCache.get(key)

expect(cachedResponse).instanceOf(Response)
const cachedBody = await cachedResponse.text()
const body = await resp.text()

expect(cachedBody).to.eq(body)
expect(cachedResponse.status).to.eq(404)

const meta = await responseCache.getMeta(key)
expect(meta.headers["authorization"]).to.eq(undefined)
expect(meta.headers["content-length"]).to.eq(undefined)
expect(meta.headers["content-type"]).to.eq("text/plain; charset=utf-8")
expect(meta.headers["content-encoding"]).to.eq("gzip")
})

it("deletes a response", async () => {
const [key, resp] = await makeResponse()
const delResult = await responseCache.del(key)
Expand Down

0 comments on commit b84c513

Please sign in to comment.