|
@@ -5,6 +5,9 @@ const { URL } = require('node:url')
|
|
|
const dns = require('node:dns')
|
|
|
const ipaddr = require('ipaddr.js')
|
|
|
const got = require('got').default
|
|
|
+const path = require('node:path')
|
|
|
+const { randomUUID } = require('node:crypto')
|
|
|
+const contentDisposition = require('content-disposition')
|
|
|
|
|
|
const logger = require('../logger')
|
|
|
|
|
@@ -119,7 +122,7 @@ module.exports.getProtectedGot = getProtectedGot
|
|
|
*
|
|
|
* @param {string} url
|
|
|
* @param {boolean} blockLocalIPs
|
|
|
- * @returns {Promise<{type: string, size: number}>}
|
|
|
+ * @returns {Promise<{name: string, type: string, size: number}>}
|
|
|
*/
|
|
|
exports.getURLMeta = async (url, blockLocalIPs = false) => {
|
|
|
async function requestWithMethod (method) {
|
|
@@ -131,11 +134,18 @@ exports.getURLMeta = async (url, blockLocalIPs = false) => {
|
|
|
.on('response', (response) => {
|
|
|
// Can be undefined for unknown length URLs, e.g. transfer-encoding: chunked
|
|
|
const contentLength = parseInt(response.headers['content-length'], 10)
|
|
|
+ // If Content-Disposition with file name is missing, fallback to the URL path for the name,
|
|
|
+ // but if multiple files are served via query params like foo.com?file=file-1, foo.com?file=file-2,
|
|
|
+ // we add random string to avoid duplicate files
|
|
|
+ const filename = response.headers['content-disposition']
|
|
|
+ ? contentDisposition.parse(response.headers['content-disposition']).parameters.filename
|
|
|
+ : `${path.basename(response.request.requestUrl)}-${randomUUID()}`
|
|
|
|
|
|
// No need to get the rest of the response, as we only want header (not really relevant for HEAD, but why not)
|
|
|
stream.destroy()
|
|
|
|
|
|
resolve({
|
|
|
+ name: filename,
|
|
|
type: response.headers['content-type'],
|
|
|
size: Number.isNaN(contentLength) ? null : contentLength,
|
|
|
statusCode: response.statusCode,
|
|
@@ -167,6 +177,6 @@ exports.getURLMeta = async (url, blockLocalIPs = false) => {
|
|
|
throw new Error(`URL server responded with status: ${urlMeta.statusCode}`)
|
|
|
}
|
|
|
|
|
|
- const { size, type } = urlMeta
|
|
|
- return { size, type }
|
|
|
+ const { name, size, type } = urlMeta
|
|
|
+ return { name, size, type }
|
|
|
}
|