Class LoopbackWarmTransport

java.lang.Object
org.frontcache.warmer.LoopbackWarmTransport
All Implemented Interfaces:
Closeable, AutoCloseable, WarmTransport

public class LoopbackWarmTransport extends Object implements WarmTransport
Sends a warm request to this node's own front door.

Its own client, never the engine's

The engine's origin client is sized for origin calls, and a warm request uses an origin connection itself, through Cache-Miss. Borrowing from one pool for both legs of the same call can deadlock at pool size = concurrency. So this pool is sized to the run's concurrency and belongs to the run.

The Host header is set explicitly

The connection goes to the loopback target; the Host header is the key base's. That header is what the cache key is built from (KeyBase), and HttpClient only derives a Host from the request's authority when none is present - so the request carries the key base's and the route stays the loopback's. The request target is sent as the raw path, never re-parsed as a URI: a key a visitor produced must be replayed byte for byte.

The key's scheme is not the loopback's

The key takes its scheme from request.getScheme(), which on a container honouring forwarded headers - the bundled Jetty's ForwardedRequestCustomizer - is X-Forwarded-Proto, not the socket. Visitors behind a TLS-terminating nginx are keyed https:// on a plain-HTTP connector, so an https key base over an http loopback is the normal case, and this transport sends X-Forwarded-Proto: <key base scheme> whenever the two differ. The same header makes the engine pick originUrlHttps, so the origin is called the way a visitor's miss calls it. A container that ignores the header keys on the connection instead; the node reports the key it used (x-frontcache-warm-key) and the run stops on the first one outside the key base, rather than storing a list's worth of entries nobody reads. An https loopback (front-cache.warmer.loopback-url) is still supported. The node's certificate names the site, not 127.0.0.1, so this client trusts the certificate and skips hostname verification - which is only acceptable because the target is restricted to a loopback address (requireLoopback(String)).
  • Constructor Details

    • LoopbackWarmTransport

      public LoopbackWarmTransport(String loopbackTarget, KeyBase keyBase, String mode, String clientType, String userAgent, int concurrency, int requestTimeoutMs)
      Parameters:
      loopbackTarget - http(s)://127.0.0.1:<port> - see requireLoopback(String)
  • Method Details

    • requireLoopback

      public static String requireLoopback(String loopbackTarget)
      The loopback target must be this machine. The token rides on every warm request, and a target elsewhere would hand it to whoever listens there - while the node itself ignores the token from a non-loopback peer anyway, so such a run could never have worked.
      Returns:
      why loopbackTarget is not acceptable, or null when it is
    • warm

      public WarmTransport.Outcome warm(String pathAndQuery) throws IOException
      Specified by:
      warm in interface WarmTransport
      Parameters:
      pathAndQuery - starts with /
      Throws:
      IOException - when there was no answer at all - a timeout, a refused connection
    • close

      public void close() throws IOException
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Specified by:
      close in interface WarmTransport
      Throws:
      IOException