forked from pmb0/express-sharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
118 lines (103 loc) · 3.5 KB
/
index.js
File metadata and controls
118 lines (103 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
'use strict'
const cors = require('cors')
const debug = require('debug')('express-sharp')
const etag = require('etag')
const express = require('express')
const expressValidator = require('express-validator')
const request = require('request-promise')
const sharp = require('sharp')
const transform = require('./lib/transform')
const url = require('url')
const getImageUrl = function(baseHost, inputUrl) {
let imageUrl = url.parse(inputUrl)
imageUrl.host = baseHost.replace('https://', '').replace('http://', '')
imageUrl.protocol = baseHost.startsWith('https') ? 'https' : 'http'
return url.format(imageUrl)
}
module.exports = function(options) {
const router = express.Router()
router.use(expressValidator({
customValidators: {
isSharpFormat: function(value) {
return sharp.format.hasOwnProperty(value)
},
isGravity: function(value) {
return sharp.gravity.hasOwnProperty(value)
},
isQuality: function(value) {
return value >= 0 && value <= 100
},
isUrlPathQuery: function(value) {
if (!value) {
return false
}
const u = url.parse(value)
if (u.protocol || u.host || !u.path) {
return false
}
return true
},
},
}))
const _cors = cors(options.cors || {})
const cropMaxSize = options.cropMaxSize || 2000
router.get('/resize/:width/:height?', _cors, async (req, res, next) => {
let format = req.query.format
if (req.headers.accept && req.headers.accept.indexOf('image/webp') !== -1) {
format = format || 'webp'
}
const quality = parseInt(req.query.quality || 75, 10)
req.checkParams('height').optional().isInt()
req.checkParams('width').isInt()
req.checkQuery('format').optional().isSharpFormat()
req.checkQuery('quality').optional().isQuality()
req.checkQuery('progressive').optional().isBoolean()
req.checkQuery('crop').optional().isBoolean()
req.checkQuery('gravity').optional().isGravity()
req.checkQuery('url').isUrlPathQuery()
const errors = req.validationErrors()
if (errors) {
return res.status(400).json(errors)
}
const imageUrl = getImageUrl(options.baseHost, req.query.url)
const width = parseInt(req.params.width, 10)
const height = parseInt(req.params.height, 10) || null
const crop = req.query.crop === 'true'
const gravity = req.query.gravity
try {
const etagBuffer = Buffer.from([imageUrl, width, height, format, quality])
res.setHeader('ETag', etag(etagBuffer, {weak: true}))
if (req.fresh) return res.sendStatus(304)
debug('Requesting:', imageUrl)
let response = await request({
encoding: null,
uri: imageUrl,
resolveWithFullResponse: true,
})
debug('Requested %s. Status: %s', imageUrl, response.statusCode)
if (response.statusCode >= 400) {
return res.sendStatus(response.statusCode)
}
res.status(response.statusCode)
const inputFormat = response.headers['content-type'] || ''
format = format || inputFormat.replace('image/', '')
format = sharp.format.hasOwnProperty(format) ? format : 'jpeg'
res.type(`image/${format}`)
const image = await transform(response.body, {
crop,
cropMaxSize,
gravity,
height,
quality,
width,
format
})
res.send(image)
} catch (e) {
if (e.statusCode === 404) return next()
next(e)
}
})
return router
}
module.exports.getImageUrl = getImageUrl