Skip to content
This repository has been archived by the owner on Dec 30, 2023. It is now read-only.

Commit

Permalink
Merge pull request #2 from Seia-Soto/fix/add-caching-for-image-proxy
Browse files Browse the repository at this point in the history
Add etag support for static attachment of post
  • Loading branch information
seia-soto authored Mar 5, 2021
2 parents 1ce478a + 9d3acbd commit 1605bfe
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"gray-matter": "^4.0.2",
"js-yaml": "^4.0.0",
"js-yaml-loader": "^1.2.2",
"mime-types": "^2.1.29",
"next": "^10.0.7",
"next-compose-plugins": "^2.2.1",
"next-images": "^1.7.0",
Expand Down
50 changes: 47 additions & 3 deletions pages/api/assets/[slug]/[filename].js
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as path from 'path'
import * as mime from 'mime-types'

import * as post from '../../../../fns/post'

const postsRoot = path.resolve(process.cwd(), 'contents', 'posts')
const postList = post.getList()

const etags = {}

const readBytes = (location, bytes) => {
return new Promise((resolve, reject) => {
fs.open(location, 'r', (status, fd) => {
if (status) {
reject(new Error('file is busy or unavailable:', status.message))
}

const buffer = Buffer.alloc(bytes)

fs.read(fd, buffer, 0, bytes, 0, (error, x) => {
if (error) {
reject(new Error('cannot read bytes from file:', error))
}

resolve(buffer.toString('utf8', 0, x))
})
})
})
}

export default async (req, res) => {
const [slug, filename] = req.url
.split('?')[0]
Expand All @@ -16,11 +40,31 @@ export default async (req, res) => {
if (!fs.existsSync(assetPath)) {
res.status(404)
res.end()

return
}

fs
.createReadStream(assetPath)
.pipe(res)
if (!etags[assetPath]) {
const firstBytes = await readBytes(assetPath, 256)

etags[assetPath] = crypto.createHash('md5').update(firstBytes).digest('hex')
}

const hash = req.headers['if-none-match']

if (hash && hash === etags[assetPath]) {
res.status(304)
res.end()

return
}

const stream = fs.createReadStream(assetPath)

res.setHeader('Content-Type', mime.contentType(path.extname(assetPath)))
res.setHeader('ETag', etags[assetPath])

stream.pipe(res)
}

export const config = {
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4873,7 +4873,7 @@ fsevents@~2.3.1:
languageName: node
linkType: hard

"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24":
"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.29, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24":
version: 2.1.29
resolution: "mime-types@npm:2.1.29"
dependencies:
Expand Down Expand Up @@ -7332,6 +7332,7 @@ fsevents@~2.3.1:
gray-matter: ^4.0.2
js-yaml: ^4.0.0
js-yaml-loader: ^1.2.2
mime-types: ^2.1.29
next: ^10.0.7
next-compose-plugins: ^2.2.1
next-images: ^1.7.0
Expand Down

2 comments on commit 1605bfe

@github-actions
Copy link

@github-actions github-actions bot commented on 1605bfe Mar 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for typed-sh ready!

✅ Preview
https://typed-sh-dyhnth7m5-seia.vercel.app

Built with commit 1605bfe.
This pull request is being automatically deployed with vercel-action

@vercel
Copy link

@vercel vercel bot commented on 1605bfe Mar 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.