private Mono<? extends Resource> transform(String content, Resource resource, ResourceTransformerChain chain, ServerWebExchange exchange) { if (!content.startsWith(MANIFEST_HEADER)) { if (logger.isTraceEnabled()) { logger.trace(exchange.getLogPrefix() + "Skipping " + resource + ": Manifest does not start with 'CACHE MANIFEST'"); } return Mono.just(resource); } return Flux.generate(new LineInfoGenerator(content)) .concatMap(info -> processLine(info, exchange, resource, chain)) .reduce(new ByteArrayOutputStream(), (out, line) -> { writeToByteArrayOutputStream(out, line + "\n"); return out; }) .map(out -> { String hash = DigestUtils.md5DigestAsHex(out.toByteArray()); writeToByteArrayOutputStream(out, "\n" + "# Hash: " + hash); return new TransformedResource(resource, out.toByteArray()); }); }