mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-24 22:48:06 +00:00
4dc30ea9bc
* fix(http): share concurrent identical cache provider requests Identical requests that use a cache provider and run at the same time now share one in-flight request instead of each fetching from the server. Callers that join an in-flight request get a deep copy of the response. This replaces the per-URL mutex, which only covered the cache check and was released before the fetch finished. Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> * fix(http): reuse cache providers for npm and typst lookups The npm and typst datasources now use one module-level cache provider, so concurrent lookups of the same package share one request. The request key is only hashed for GET and HEAD requests and includes `throwHttpErrors`. Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> Co-Authored-By: Claude Sonnet 5.5 <michael.kriese+claude-code@mend.io> * fix(http): don't share requests that differ in response type Add `responseType` and `responseBecomesConfig` to the key of shared requests, and test that requests with different headers aren't shared and that a shared response is copied for every caller. Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> Co-Authored-By: Claude Sonnet 5.5 <michael.kriese+claude-code@mend.io> * fix(http): keep in-flight requests per Http class and copy binary bodies Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> --------- Co-authored-by: Claude Opus 5.5 <michael.kriese+claude-code@mend.io>
40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import { HOST_BLOCKED } from '../../constants/error-messages.ts';
|
|
import { clone } from '../clone.ts';
|
|
import type { HttpResponse } from './types.ts';
|
|
|
|
// Copying will help to avoid circular structure
|
|
// and mutation of the cached response.
|
|
export function copyResponse<T>(
|
|
{ statusCode, headers, body, cached }: HttpResponse<T>,
|
|
deep: boolean,
|
|
): HttpResponse<T> {
|
|
const res: HttpResponse<T> = { statusCode, headers, body };
|
|
|
|
if (deep) {
|
|
res.headers = clone(headers);
|
|
if (Buffer.isBuffer(body)) {
|
|
// Buffer#slice returns a view, so copy it explicitly
|
|
res.body = Buffer.from(body) as T;
|
|
} else if (body instanceof Uint8Array) {
|
|
res.body = body.slice() as T;
|
|
} else {
|
|
res.body = clone<T>(body);
|
|
}
|
|
}
|
|
|
|
if (cached) {
|
|
res.cached = true;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* The log message for a request the HTTP layer refused, distinguishing a host blocked by the internal-host policy from one an administrator disabled.
|
|
*
|
|
* Both are reported the same way by their callers - traced and swallowed - so only the wording tells them apart in the logs.
|
|
*/
|
|
export function refusedHostMessage(err: Error): string {
|
|
return err.message === HOST_BLOCKED ? 'Host blocked' : 'Host disabled';
|
|
}
|