Better header check + remove last-modified header

This commit is contained in:
Sander Declerck 2025-11-14 10:23:06 +01:00
parent 40523f29dd
commit 290a630526
No known key found for this signature in database
2 changed files with 47 additions and 20 deletions

View file

@ -7,7 +7,8 @@ let hasSuppressedVersions = false;
* @param {NodeJS.Dict<string | string[]>} headers * @param {NodeJS.Dict<string | string[]>} headers
*/ */
export function modifyNpmInfoRequestHeaders(headers) { export function modifyNpmInfoRequestHeaders(headers) {
if (headers["accept"]?.includes("application/vnd.npm.install-v1+json")) { const accept = getHeaderValueAsString(headers, "accept");
if (accept?.includes("application/vnd.npm.install-v1+json")) {
// The npm registry sometimes serves a more compact format that lacks // The npm registry sometimes serves a more compact format that lacks
// the time metadata we need to filter out too new packages. // the time metadata we need to filter out too new packages.
// Force the registry to return the full metadata by changing the Accept header. // Force the registry to return the full metadata by changing the Accept header.
@ -41,6 +42,11 @@ export function isPackageInfoUrl(url) {
*/ */
export function modifyNpmInfoResponse(body, headers) { export function modifyNpmInfoResponse(body, headers) {
try { try {
const contentType = getHeaderValueAsString(headers, "content-type");
if (!contentType?.toLowerCase().includes("application/json")) {
return body;
}
if (body.byteLength === 0) { if (body.byteLength === 0) {
return body; return body;
} }
@ -74,9 +80,10 @@ export function modifyNpmInfoResponse(body, headers) {
if (timestamp > cutOff) { if (timestamp > cutOff) {
deleteVersionFromJson(bodyJson, version); deleteVersionFromJson(bodyJson, version);
if (headers) { if (headers) {
// When modifying the response, the etag no longer matches the content // When modifying the response, the etag and last-modified headers
// so the etag needs to be removed before sending the response. // no longer match the content so they needs to be removed before sending the response.
delete headers["etag"]; delete headers["etag"];
delete headers["last-modified"];
} }
continue; continue;
} }
@ -163,3 +170,21 @@ function getMostRecentTag(tagList) {
export function getHasSuppressedVersions() { export function getHasSuppressedVersions() {
return hasSuppressedVersions; return hasSuppressedVersions;
} }
/**
* @param {NodeJS.Dict<string | string[]> | undefined} headers
* @param {string} headerName
*/
function getHeaderValueAsString(headers, headerName) {
if (!headers) {
return undefined;
}
let header = headers[headerName];
if (Array.isArray(header)) {
return header.join(", ");
}
return header;
}

View file

@ -231,23 +231,6 @@ describe("npmInterceptor minimum package age", async () => {
assert.equal(modifiedJson["dist-tags"]["alpha"], undefined); assert.equal(modifiedJson["dist-tags"]["alpha"], undefined);
}); });
/**
* @param {import("../interceptorBuilder.js").Interceptor} interceptor
* @param {string} body
* @returns {Promise<string>}
*/
async function runModifyNpmInfoRequest(url, body) {
const interceptor = npmInterceptorForUrl(url);
const requestHandler = await interceptor.handleRequest(url);
if (requestHandler.modifiesResponse()) {
const modifiedBuffer = requestHandler.modifyBody(Buffer.from(body));
return modifiedBuffer.toString("utf8");
}
return body;
}
it("Should not filter packages when skipMinimumPackageAge is enabled", async () => { it("Should not filter packages when skipMinimumPackageAge is enabled", async () => {
minimumPackageAgeSettings = 5; minimumPackageAgeSettings = 5;
skipMinimumPackageAgeSetting = true; skipMinimumPackageAgeSetting = true;
@ -296,4 +279,23 @@ describe("npmInterceptor minimum package age", async () => {
return date; return date;
} }
/**
* @param {import("../interceptorBuilder.js").Interceptor} interceptor
* @param {string} body
* @returns {Promise<string>}
*/
async function runModifyNpmInfoRequest(url, body) {
const interceptor = npmInterceptorForUrl(url);
const requestHandler = await interceptor.handleRequest(url);
if (requestHandler.modifiesResponse()) {
const modifiedBuffer = requestHandler.modifyBody(Buffer.from(body), {
["content-type"]: "application/json",
});
return modifiedBuffer.toString("utf8");
}
return body;
}
}); });