Repository: angular/angular
File: packages/common/http/src/transfer_cache.ts (TypeScript)

Code before:
  const transferState = inject(TransferState);

  const originMap: Record<string, string> | null = inject(HTTP_TRANSFER_CACHE_ORIGIN_MAP, {
    optional: true,
  });

  const cachedResponse = StateFromCache(req, options, transferState, originMap);
  if (cachedResponse) {
    return of(cachedResponse);
  }

  const {isCacheActive, ...globalOptions} = options;
  const {transferCache: requestOptions, method: requestMethod} = req;
  let headersToInclude = globalOptions.includeHeaders;
  if (typeof requestOptions === 'object' && requestOptions.includeHeaders) {
    headersToInclude = requestOptions.includeHeaders;
  }

  const requestUrl =
    typeof ngServerMode !== 'undefined' && ngServerMode && originMap
      ? mapRequestOriginUrl(req.url, originMap)
      : req.url;
  const storeKey = makeCacheKey(req, requestUrl);

  // In the following situations we do not want to cache the request
  if (
    !isCacheActive ||
    requestOptions === false ||
    // POST requests are allowed either globally or at request level
    (requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions) ||
    (requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod)) ||
    // Do not cache request that require authorization when includeRequestsWithAuthHeaders is falsey
    (!globalOptions.includeRequestsWithAuthHeaders && hasAuthHeaders(req)) ||
    globalOptions.filter?.(req) === false
  ) {
    return next(req);
  }

  const event$ = next(req);

  if (typeof ngServerMode !== 'undefined' && ngServerMode) {
    // Request not found in cache. Make the request and cache it if on the server.
    return event$.pipe(
      tap((event: HttpEvent<unknown>) => {
        // Only cache successful HTTP responses.
        if (event instanceof HttpResponse) {
          transferState.set<TransferHttpResponse>(storeKey, {
            [BODY]:
              req.responseType === 'arraybuffer' || req.responseType === 'blob'
                ? toBase64(event.body)
                : event.body,

Review comment (performance):
We have a similar check in the `StateFromCache` function. It'd be great to extract it out to a separate function and reuse in both places.

Code after:
    }

    return new HttpResponse({
      body,
      headers,
      status,
      statusText,
      url,
    });
  }

  return null;
}

export function transferCacheInterceptorFn(
  req: HttpRequest<unknown>,
  next: HttpHandlerFn,
): Observable<HttpEvent<unknown>> {
  const options = inject(CACHE_OPTIONS);
  const transferState = inject(TransferState);

  const originMap = inject(HTTP_TRANSFER_CACHE_ORIGIN_MAP, {optional: true});

  const cachedResponse = retrieveStateFromCache(req, options, transferState, originMap);
  if (cachedResponse) {
    return of(cachedResponse);
  }

  const {transferCache: requestOptions} = req;
  const headersToInclude = getHeadersToInclude(options, requestOptions);

  const requestUrl =
    typeof ngServerMode !== 'undefined' && ngServerMode && originMap
      ? mapRequestOriginUrl(req.url, originMap)
      : req.url;
  const storeKey = makeCacheKey(req, requestUrl);

  // In the following situations we do not want to cache the request
  if (!shouldCacheRequest(req, options)) {
    return next(req);
  }

  const event$ = next(req);

  if (typeof ngServerMode !== 'undefined' && ngServerMode) {
    // Request not found in cache. Make the request and cache it if on the server.
    return event$.pipe(
      tap((event: HttpEvent<unknown>) => {
        // Only cache successful HTTP responses.
        if (event instanceof HttpResponse) {
          transferState.set<TransferHttpResponse>(storeKey, {