Class RequestContext
- All Implemented Interfaces:
Serializable, ConcurrentMap<String,Object>, Map<String, Object>
The Request Context holds request, response, state information and data to access and share.
The RequestContext lives for the duration of the request and is ThreadLocal.
extensions of RequestContext can be substituted by setting the contextClass.
Most methods here are convenience wrapper methods; the RequestContext is an extension of a ConcurrentHashMap
- See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from class ConcurrentHashMap
ConcurrentHashMap.KeySetView<K,V> Nested classes/interfaces inherited from class AbstractMap
AbstractMap.SimpleEntry<K,V>, AbstractMap.SimpleImmutableEntry<K, V> -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidaddOriginResponseHeader(String name, String value) adds a header to the origin response headerscopy()booleangetBoolean(String key) Convenience method to return a boolean value for a given keybooleangetBoolean(String key, boolean defaultResponse) Convenience method to return a boolean value for a given keyThe client IP of this request, resolved once.Name of the bots.conf rule that decidedgetClientType().Names of the cookies the client sent, parsed once per request and memoized.jakarta.servlet.FilterChainintorg.apache.hc.core5.http.ClassicHttpResponsebooleanreturns the content-length of the origin responsethe Origin response headersjakarta.servlet.http.HttpServletRequestbooleanThe trustworthy client address, resolved once per request.jakarta.servlet.http.HttpServletResponsebooleanintreturns the response status code.returns a set throwableBuffer for the X-frontcache-trace-* headers.The User-Agent header, read once per request.booleanbooleancheck if response has "Content-Type" header with "text" insidebooleanbooleanbooleanCheck if run as ServletFilterbooleanbooleanbooleanbooleanvoidReleases the origin response opened by FC_BypassCache, closing it once BOTH parties are done.voidsets a key value to Boolen.TRUEvoidputs the key, value into the map.voidsets chunkedRequestBody to truevoidsetClientIP(String clientIP) voidsetClientType(String currentClientType) voidsetClientTypeRule(String ruleName) voidsetCurrentRequestURL(String currentRequestURL) voidThe site this node serves (front-cache.default-domain), stamped on the context by the engine.voidvoidsetFallbackUsed(String reason) voidsetFallbackWebResponse(WebResponse webResponse) The fallback to serve instead of the origin response, parked here by FC_BypassCache.getFallback().voidsetFilterChain(jakarta.servlet.FilterChain filterChain) voidsetFrontCacheHost(String frontCacheHost) sets frontCacheHostvoidsetFrontCacheHttpPort(String frontCacheHttpPort) voidsetFrontCacheHttpsPort(String frontCacheHttpsPort) voidsetFrontCacheId(String frontCacheId) voidsetFrontCacheProtocol(String frontCacheProtocol) voidMarks a synthetic context built for a load-time guard self-check (redirect-loop detection, the exemption warnings) rather than for a real request.voidsetGuardRetryAfterSeconds(int seconds) Seconds until a rate-limited client's window rolls over, stashed by the rate predicate and emitted as Retry-After by the guard response.voidsetHttpClientResponse(org.apache.hc.core5.http.ClassicHttpResponse response) voidsetIncludeLevel(String includeLevel) voidvoidsets the content-length from the origin responsevoidsets the content-length from the origin responsevoidsetOriginURL(URL originURL) voidsetPublicHost(String publicHost) The site's public hostname (front-cache.default-domain), or null when the node has none configured.voidsetPublicProtocol(String publicProtocol) The scheme the client actually used, recovered from X-Forwarded-Proto (trusted peers only) or front-cache.public-scheme.voidsetRequest(jakarta.servlet.http.HttpServletRequest request) sets the HttpServletRequest into the "request" keyvoidvoidsetRequestId(String frontcacheRequestId) voidsetRequestQueryParams(Map<String, List<String>> qp) sets the request query params listvoidsetRequestQueryString(String requestQueryString) voidsetRequestType(String frontcacheRequestType) voidsetRequestURI(String uri) voidsetResponse(jakarta.servlet.http.HttpServletResponse response) sets the "response" key to the HttpServletResponse passed invoidsetResponseBody(String body) sets the "responseBody" value as a String.voidsetResponseDataStream(InputStream responseDataStream) sets the InputStream of the response into the responseDataStreamvoidsetResponseGZipped(boolean gzipped) sets the flag responseGZipped if the response is gzippedvoidsetResponseStatusCode(int nStatusCode) Use this instead of response.setStatusCode()voidsets a throwablevoidvoidsetWarmRequest(String mode) Marks this request as the cache warmer's - set by the engine only after the warm token checked out (seeorg.frontcache.warmer.WarmRequest).voidsetWarmResult(String result) What the cache processor did with a warm request - reported to the warmer asx-frontcache-warm-result.toString()A bounded, one-line summary for diagnostics - NOT a dump of the map.Methods inherited from class ConcurrentHashMap
clear, compute, computeIfAbsent, computeIfPresent, contains, containsKey, containsValue, elements, entrySet, equals, forEach, forEach, forEach, forEachEntry, forEachEntry, forEachKey, forEachKey, forEachValue, forEachValue, get, getOrDefault, hashCode, isEmpty, keys, keySet, keySet, mappingCount, merge, newKeySet, newKeySet, put, putAll, putIfAbsent, reduce, reduceEntries, reduceEntries, reduceEntriesToDouble, reduceEntriesToInt, reduceEntriesToLong, reduceKeys, reduceKeys, reduceKeysToDouble, reduceKeysToInt, reduceKeysToLong, reduceToDouble, reduceToInt, reduceToLong, reduceValues, reduceValues, reduceValuesToDouble, reduceValuesToInt, reduceValuesToLong, remove, remove, replace, replace, replaceAll, search, searchEntries, searchKeys, searchValues, size, valuesMethods inherited from class AbstractMap
clone
-
Constructor Details
-
RequestContext
public RequestContext()
-
-
Method Details
-
getTraceHeaders
Buffer for the X-frontcache-trace-* headers. Includes are resolved on the include-processor's worker threads, but HttpServletResponse (and Jetty's underlying HttpFields) is NOT thread safe - concurrent setHeader() calls corrupt the field list (NPE in HttpFields$Mutable$Wrapper.put) and a late/timed-out include can hit an already committed or recycled response. So worker threads only fill this map; the request thread flushes it onto the response right before the body is written.- Returns:
- the shared (thread safe) trace header buffer of this request
-
getBoolean
Convenience method to return a boolean value for a given key- Parameters:
key-- Returns:
- true or false depending what was set. default is false
-
getBoolean
Convenience method to return a boolean value for a given key- Parameters:
key-defaultResponse-- Returns:
- true or false depending what was set. default defaultResponse
-
set
-
set
-
getRequest
public jakarta.servlet.http.HttpServletRequest getRequest()- Returns:
- the HttpServletRequest from the "request" key
-
setRequest
public void setRequest(jakarta.servlet.http.HttpServletRequest request) sets the HttpServletRequest into the "request" key- Parameters:
request-
-
getResponse
public jakarta.servlet.http.HttpServletResponse getResponse()- Returns:
- the HttpServletResponse from the "response" key
-
setResponse
public void setResponse(jakarta.servlet.http.HttpServletResponse response) sets the "response" key to the HttpServletResponse passed in- Parameters:
response-
-
getThrowable
-
setThrowable
-
setFrontCacheHost
sets frontCacheHost- Parameters:
frontCacheHost- a URL
-
getFrontCacheHost
- Returns:
- "frontCacheHost" URL
-
setFrontCacheProtocol
- Parameters:
frontCacheProtocol-
-
getFrontCacheProtocol
- Returns:
-
setPublicHost
The site's public hostname (front-cache.default-domain), or null when the node has none configured. This is NOTgetFrontCacheHost()and the two must not be confused - that is the whole of docs/archive/guard-redirect-url-host-fix.md. getFrontCacheHost() is the Host header as it arrived, which is what predicates match, what the log lines record and what the cache key is built from; a node is reachable under several of them (the CDN's, an internal alias, its own name, a bare IP). This one is the single name we are willing to hand to a browser. Null means "not configured" - callers fall back to the arriving host. See FrontCacheEngine.getPublicDomain(), which is what maps the unset/placeholder property values onto null. -
getPublicHost
- Returns:
- the site's public hostname, or null when none is configured
-
setPublicProtocol
The scheme the client actually used, recovered from X-Forwarded-Proto (trusted peers only) or front-cache.public-scheme. Separate fromgetFrontCacheProtocol(), which stays the scheme of the connection as this process saw it. Behind a TLS-terminating proxy the two differ, and the cache key is built from the latter - so overloading it would silently re-key the whole cache. Only URLs we emit to a client read this one. -
getPublicProtocol
- Returns:
- the public scheme, or null when it could not be established (fall back to
getFrontCacheProtocol())
-
setOriginURL
-
getOriginURL
-
setResponseBody
sets the "responseBody" value as a String. This is the response sent back to the client.- Parameters:
body-
-
getResponseBody
- Returns:
- the String response body to be snt back to the requesting client
-
setResponseDataStream
sets the InputStream of the response into the responseDataStream- Parameters:
responseDataStream-
-
setResponseGZipped
public void setResponseGZipped(boolean gzipped) sets the flag responseGZipped if the response is gzipped- Parameters:
gzipped-
-
getResponseGZipped
public boolean getResponseGZipped()- Returns:
- true if responseGZipped is true (the response is gzipped)
-
getResponseDataStream
- Returns:
- the InputStream Response
-
getResponseStatusCode
public int getResponseStatusCode()returns the response status code. Default is 200- Returns:
-
setResponseStatusCode
public void setResponseStatusCode(int nStatusCode) Use this instead of response.setStatusCode()- Parameters:
nStatusCode-
-
getOriginResponseHeaders
-
isCacheableResponse
public boolean isCacheableResponse()check if response has "Content-Type" header with "text" inside- Returns:
-
isCacheableRequest
public boolean isCacheableRequest()- Returns:
-
addOriginResponseHeader
-
getOriginContentLength
returns the content-length of the origin response- Returns:
- the content-length of the origin response
-
setOriginContentLength
sets the content-length from the origin response- Parameters:
v-
-
setRequestURI
-
getRequestURI
-
setRequestQueryString
-
getRequestQueryString
-
setOriginContentLength
sets the content-length from the origin response- Parameters:
v- parses the string into an int
-
isChunkedRequestBody
public boolean isChunkedRequestBody()- Returns:
- true if the request body is chunked
-
setChunkedRequestBody
public void setChunkedRequestBody()sets chunkedRequestBody to true -
isGzipRequested
public boolean isGzipRequested()- Returns:
- true is the client request can accept gzip encoding. Checks the "accept-encoding" header
-
getRequestQueryParams
-
setRequestQueryParams
-
getHttpClientResponse
public org.apache.hc.core5.http.ClassicHttpResponse getHttpClientResponse() -
setHttpClientResponse
public void setHttpClientResponse(org.apache.hc.core5.http.ClassicHttpResponse response) -
releaseHttpClientResponse
public void releaseHttpClientResponse()Releases the origin response opened by FC_BypassCache, closing it once BOTH parties are done. The response is opened on a command worker thread but its body is streamed by the request thread, so neither thread can close it unilaterally. On a command TIMEOUT the request thread finishes early (through the fallback) while the worker is still inside httpclient.execute() - a blocking socket read ignores the interrupt - and then stashes a response nobody is left to close, leaking the pooled connection permanently (leased entries are never reclaimed by closeExpiredConnections). Both threads call this in a finally; whichever arrives last does the close, so the connection is returned exactly once no matter which one wins the race. -
setFallbackWebResponse
The fallback to serve instead of the origin response, parked here by FC_BypassCache.getFallback(). The fallback is resolved on the command worker thread but written by the request thread, which is the only thread that may touch the servlet output stream in bypass mode. Writing it from getFallback() instead raced with the request thread's own writeResponse(): the fallback body went out first, then addResponseHeaders() stamped the context status over it - which defaults to 500 - and any origin body that arrived late was appended to it. Whenever the fallback was smaller than the container's response buffer (32KB in Jetty) the response was not yet committed when that happened, so the status actually took effect and the client got a 500. -
getFallbackWebResponse
-
setFrontCacheHttpPort
-
getFrontCacheHttpPort
-
setFrontCacheHttpsPort
-
getFrontCacheHttpsPort
-
setFilterChain
public void setFilterChain(jakarta.servlet.FilterChain filterChain) -
getFilterChain
public jakarta.servlet.FilterChain getFilterChain() -
isFilterMode
public boolean isFilterMode()Check if run as ServletFilter- Returns:
-
setFrontCacheId
- Parameters:
frontCacheId-
-
getFrontCacheId
- Returns:
-
setFallbackUsed
public void setFallbackUsed() -
setFallbackUsed
-
isFallbackUsed
public boolean isFallbackUsed() -
getFallbackReason
- Returns:
- the failure category (short-circuited|timeout|rejected|bad-request|failure) when known,
otherwise "error". Only meaningful when
isFallbackUsed()is true.
-
setRequestType
-
getRequestType
-
setRequestId
-
getRequestId
-
setRequestFromFrontcache
public void setRequestFromFrontcache() -
getRequestFromFrontcache
public boolean getRequestFromFrontcache() -
getCurrentRequestURL
-
setCurrentRequestURL
-
getCookieNames
Names of the cookies the client sent, parsed once per request and memoized. Used by the guard rules (org.frontcache.guard), which run on every request before cache and origin - so a request pays for cookie parsing only when some rule asks about a cookie, and never more than once. Names only: guard rules test presence and must not read, compare or log cookie values.- Returns:
- cookie names, empty when there is no (or no longer a) usable servlet request
-
getClientType
-
setClientType
-
getClientIP
The client IP of this request, resolved once.FCUtils.getClientIP(HttpServletRequest)walks up to thirteen candidate headers, and it used to be called afresh for every log line - once per request, again per include, again on the origin call. Resolving it once per exchange makes those free. The engine stamps it in init(), on the request thread while the servlet request is still live, which is also what makes it CORRECT for work that outlives the request: an async include runs after the container has recycled the request, where a late resolve can only answer "unresolved". A context built outside the engine (a copy, a test) resolves lazily here instead. -
setClientIP
-
getResolvedClientIP
The trustworthy client address, resolved once per request. Deliberately NOTgetClientIP(). That one walks thirteen client-supplied headers and returns the first non-empty value, which is right for a log column and would let any client mint itself a fresh counter per request - or claim a crawler's address - by sending its own X-Forwarded-For. This goes throughClientIpResolver, which reads a forwarding header only from a configured trusted proxy and walks it right to left. The two can legitimately disagree, which is why the guard log line carries this one explicitly. Two callers, both of which must never see a spoofable value: the rate limiter's counter key, and theclient-ip:predicate used by guard rules and by bots.conf classification.- Returns:
- canonical client address, or null when it cannot be established
-
getRateLimitKey
- Returns:
getResolvedClientIP()- the name the rate limiter knows it by
-
getUserAgent
The User-Agent header, read once per request. Memoized for the same reason the cookie names are: bot classification asks several rules for it on every request, and an async include's servlet request may be recycled by the time one of them asks - in which case the answer is "no user agent", not an exception.- Returns:
- the header value, or null when there is none (or it is no longer readable)
-
getClientTypeRule
Name of the bots.conf rule that decidedgetClientType(). Kept for diagnostics; the client type itself is what everything downstream reads. -
setClientTypeRule
-
setWarmRequest
Marks this request as the cache warmer's - set by the engine only after the warm token checked out (seeorg.frontcache.warmer.WarmRequest). Nothing a client sends can set it.- Parameters:
mode-fill|refresh
-
isWarmRequest
public boolean isWarmRequest() -
getWarmMode
- Returns:
fill|refresh, or null when this is not a warm request
-
setWarmResult
What the cache processor did with a warm request - reported to the warmer asx-frontcache-warm-result. Recorded on warm requests only. -
getWarmResult
-
setGuardProbe
public void setGuardProbe()Marks a synthetic context built for a load-time guard self-check (redirect-loop detection, the exemption warnings) rather than for a real request. Predicates with side effects - today, the rate limiter - must do nothing for one of these. -
isGuardProbe
public boolean isGuardProbe() -
setGuardRetryAfterSeconds
public void setGuardRetryAfterSeconds(int seconds) Seconds until a rate-limited client's window rolls over, stashed by the rate predicate and emitted as Retry-After by the guard response. -
getGuardRetryAfterSeconds
public int getGuardRetryAfterSeconds()- Returns:
- the Retry-After value in seconds, or 0 when the matching rule had nothing to say
-
copy
-
setDomain
The site this node serves (front-cache.default-domain), stamped on the context by the engine. Used for request logging, cache-entry ownership and the command group key. -
getDomain
-
setLogToHTTPHeaders
public void setLogToHTTPHeaders() -
getLogToHTTPHeaders
public boolean getLogToHTTPHeaders() -
setIncludeLevel
-
getIncludeLevel
-
setToplevelCached
public void setToplevelCached() -
isToplevelCached
public boolean isToplevelCached() -
toString
A bounded, one-line summary for diagnostics - NOT a dump of the map. This used to besuper.toString()(every entry, including the HttpServletRequest, the HttpServletResponse, the open origin ClassicHttpResponse and the whole origin header map) put through a freshly-compiled regex to squash newlines. The reason that mattered is where it is called from: all four command fallbacks log it - so it runs on EVERY request precisely when the origin is failing and every request is taking the fallback path. The log line meant to help diagnose an outage was amplifying the load during one, and it dragged whole request/response objects through their own toString() to do it. Fixed fields, so there is nothing to escape: none of them can contain a newline, and the URI and query string are the only caller-influenced values - they are length-capped rather than pattern-matched.- Overrides:
toStringin classConcurrentHashMap<String,Object>
-