diff --git a/client/Home.md b/client/Home.md index f4dd485..fbfada0 100644 --- a/client/Home.md +++ b/client/Home.md @@ -43,8 +43,8 @@ Append a `/` at the end of a URL to view a listing of all the files in a package `meta` - `undefined` - Return metadata about a file in a package as JSON (e.g. `/any/file?meta`) + + Return metadata about any file in a package as JSON (e.g. `/any/file?meta`) diff --git a/server/createServer.js b/server/createServer.js index cab6829..e50796d 100644 --- a/server/createServer.js +++ b/server/createServer.js @@ -11,7 +11,6 @@ const checkBlacklist = require('./middleware/checkBlacklist') const parsePackageURL = require('./middleware/parsePackageURL') const fetchFile = require('./middleware/fetchFile') const serveFile = require('./middleware/serveFile') -const serveMetadata = require('./middleware/serveMetadata') /** * A list of packages we refuse to serve. @@ -74,13 +73,6 @@ function createServer() { maxAge: '365d' })) - app.use('/_meta', - parsePackageURL, - checkBlacklist(PackageBlacklist), - fetchFile, - serveMetadata - ) - app.use('/', parsePackageURL, checkBlacklist(PackageBlacklist), diff --git a/server/middleware/parsePackageURL.js b/server/middleware/parsePackageURL.js index f0345cc..8887766 100644 --- a/server/middleware/parsePackageURL.js +++ b/server/middleware/parsePackageURL.js @@ -3,7 +3,6 @@ const validateNPMPackageName = require('validate-npm-package-name') const PackageURL = require('../PackageURL') const KnownQueryParams = { - json: true, // deprecated main: true, meta: true } @@ -16,23 +15,30 @@ function queryIsKnown(query) { return Object.keys(query).every(isKnownQueryParam) } -function sanitizeQuery(query) { - const saneQuery = {} +function createSearch(query, withMeta) { + let search = '' - Object.keys(query).forEach(function (param) { - if (isKnownQueryParam(param)) - saneQuery[param] = query[param] - }) + if (query.main) + search += `main=${encodeURIComponent(query.main)}` - return saneQuery + // Do this manually because stringify uses ?meta= for { meta: true } + if (query.meta != null || query.json != null || withMeta) + search += (search ? '&' : '') + 'meta' + + return search ? `?${search}` : '' } /** * Parse and validate the URL. */ function parsePackageURL(req, res, next) { + // Redirect /_meta/pkg to /pkg?meta. + if (req.path.match(/^\/_meta\//)) + return res.redirect(req.path.substr(6) + createSearch(req.query, true)) + const url = PackageURL.parse(req.url) + // Do not allow invalid URLs. if (url == null) return res.status(403).type('text').send(`Invalid URL: ${req.url}`) @@ -45,10 +51,8 @@ function parsePackageURL(req, res, next) { // Redirect requests with unknown query params to their equivalents // with only known params so they can be served from the cache. This // prevents people using random query params designed to bust the cache. - if (!queryIsKnown(url.query)) { - const search = qs.stringify(sanitizeQuery(url.query)) - return res.redirect(url.pathname + (search ? `?${search}` : '')) - } + if (!queryIsKnown(url.query)) + return res.redirect(url.pathname + createSearch(url.query)) req.packageName = url.packageName req.packageVersion = url.packageVersion diff --git a/server/middleware/serveFile.js b/server/middleware/serveFile.js index 0f11535..a876aa5 100644 --- a/server/middleware/serveFile.js +++ b/server/middleware/serveFile.js @@ -1,7 +1,7 @@ const fs = require('fs') const path = require('path') -const qs = require('querystring') const etag = require('etag') +const getMetadata = require('./utils/getMetadata') const getFileContentType = require('./utils/getFileContentType') const getIndexHTML = require('./utils/getIndexHTML') @@ -10,6 +10,11 @@ const getIndexHTML = require('./utils/getIndexHTML') */ const AutoIndex = !process.env.DISABLE_INDEX +/** + * Maximum recursion depth for meta listings. + */ +const MaximumDepth = 128 + function sendFile(res, file, stats) { let contentType = getFileContentType(file) @@ -36,12 +41,19 @@ function sendFile(res, file, stats) { * Send the file, JSON metadata, or HTML directory listing. */ function serveFile(req, res, next) { - if (req.query.meta != null || req.query.json != null) { - // Preserve support for ?meta and ?json for backwards compat. - delete req.query.meta - delete req.query.json - const search = qs.stringify(req.query) - res.redirect(`/_meta${req.pathname}${search}`) + if (req.query.meta != null) { + getMetadata(req.packageDir, req.file, req.stats, MaximumDepth, function (error, metadata) { + if (error) { + console.error(error) + res.status(500).type('text').send(`Cannot generate metadata for ${req.packageSpec}${req.filename}`) + } else { + // Cache metadata for 1 year. + res.set({ + 'Cache-Control': 'public, max-age=31536000', + 'Cache-Tag': 'meta' + }).send(metadata) + } + }) } else if (req.stats.isFile()) { // Cache files for 1 year. res.set({ diff --git a/server/middleware/serveMetadata.js b/server/middleware/serveMetadata.js deleted file mode 100644 index 0e8ec84..0000000 --- a/server/middleware/serveMetadata.js +++ /dev/null @@ -1,23 +0,0 @@ -const getMetadata = require('./utils/getMetadata') - -/** - * Maximum recursion depth for meta listings. - */ -const MaximumDepth = 128 - -function serveMetadata(req, res) { - getMetadata(req.packageDir, req.file, req.stats, MaximumDepth, function (error, metadata) { - if (error) { - console.error(error) - res.status(500).type('text').send(`Cannot generate metadata for ${req.packageSpec}${req.filename}`) - } else { - // Cache metadata for 1 year. - res.set({ - 'Cache-Control': 'public, max-age=31536000', - 'Cache-Tag': 'meta' - }).send(metadata) - } - }) -} - -module.exports = serveMetadata