Skip to content
This repository has been archived by the owner on Jun 27, 2024. It is now read-only.

Commit

Permalink
refactor(ext/compress): make extension lighter
Browse files Browse the repository at this point in the history
  • Loading branch information
boywithkeyboard committed Aug 31, 2023
1 parent 1d4c267 commit 27dbcbb
Showing 1 changed file with 57 additions and 32 deletions.
89 changes: 57 additions & 32 deletions ext/compress.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,82 @@
// Copyright 2023 Samuel Kopp. All rights reserved. Apache-2.0 license.
import * as brotli from 'https://deno.land/x/brotli@0.1.7/mod.ts'
import { deflate, gzip } from 'https://deno.land/x/foras@2.0.8/src/deno/mod.ts'
import { compress as brotli } from 'https://deno.land/x/brotli@0.1.7/mod.ts'
import {
deflate,
gzip,
initBundledOnce,
InitOutput,
} from 'https://deno.land/x/foras@2.0.8/src/deno/mod.ts'
import { createExtension } from '../mod.ts'

type CompressionAlgorithm = {
format: 'br' | 'deflate' | 'gzip'
compress: (input: Uint8Array) => Uint8Array | Promise<Uint8Array>
}

let FORAS: InitOutput | undefined

export const BROTLI: CompressionAlgorithm = {
format: 'br',
compress: brotli,
}

export const DEFLATE: CompressionAlgorithm = {
format: 'deflate',
async compress(input) {
if (!FORAS) {
FORAS = await initBundledOnce()
}

return deflate(input)
},
}

export const GZIP: CompressionAlgorithm = {
format: 'gzip',
async compress(input) {
if (!FORAS) {
FORAS = await initBundledOnce()
}

return gzip(input)
},
}

/**
* An extension to compress the body of the response with [Brotli](https://github.com/google/brotli), [gzip](https://www.gzip.org), or [deflate](https://www.ietf.org/rfc/rfc1951.txt), based on the `Accept-Encoding` header of the incoming request.
* An extension to compress the body of the response with [brotli](https://github.com/google/brotli), [gzip](https://www.gzip.org), or [deflate](https://www.ietf.org/rfc/rfc1951.txt), based on the `Accept-Encoding` header of the incoming request.
*
* @since v1.0
*/
export const compress = createExtension({
onResponse({ c }) {
export const compress = createExtension<{
algorithm: CompressionAlgorithm | CompressionAlgorithm[]
}>({
async onResponse({ c, _ }) {
const alg = _.algorithm instanceof Array ? _.algorithm : [_.algorithm]

const header = c.req.headers['accept-encoding']

if (c.res.body === null || !header || header === 'identity') {
return
}

if (header.includes('br')) {
c.res.body = c.res.body instanceof Uint8Array
? brotli.compress(c.res.body)
: c.res.body instanceof ArrayBuffer
? brotli.compress(new Uint8Array(c.res.body))
: typeof c.res.body === 'string'
? brotli.compress(new TextEncoder().encode(c.res.body))
: c.res.body

if (c.res.body instanceof Uint8Array) {
c.res.header('content-encoding', 'br')
for (let i = 0; i < alg.length; ++i) {
if (!header.includes(alg[i].format)) {
continue
}
} else if (header.includes('gzip')) {
c.res.body = c.res.body instanceof Uint8Array
? gzip(c.res.body)
: c.res.body instanceof ArrayBuffer
? gzip(new Uint8Array(c.res.body))
: typeof c.res.body === 'string'
? gzip(new TextEncoder().encode(c.res.body))
: c.res.body

if (c.res.body instanceof Uint8Array) {
c.res.header('content-encoding', 'gzip')
}
} else if (header.includes('deflate')) {
c.res.body = c.res.body instanceof Uint8Array
? deflate(c.res.body)
? await alg[i].compress(c.res.body)
: c.res.body instanceof ArrayBuffer
? deflate(new Uint8Array(c.res.body))
? await alg[i].compress(new Uint8Array(c.res.body))
: typeof c.res.body === 'string'
? deflate(new TextEncoder().encode(c.res.body))
? await alg[i].compress(new TextEncoder().encode(c.res.body))
: c.res.body

if (c.res.body instanceof Uint8Array) {
c.res.header('content-encoding', 'deflate')
c.res.header('content-encoding', alg[i].format)
}

break
}
},
})

0 comments on commit 27dbcbb

Please sign in to comment.