Class CombineProtocol

java.lang.Object
org.frontcache.include.combine.CombineProtocol

public final class CombineProtocol extends Object
The combine-and-reduce wire contract, in one place: parameter names, the encoding of a member's query string, and the small URL arithmetic both ends need. See docs/archive/combine-reduce-proposal.md sections 5 and 6. Both halves of the contract live in this package so an origin embedding frontcache-core cannot drift from the edge - see CombineRequest and CombineResponse, which are the origin's half.

Request

GET {path}?fc-combine=1&fc-parts={n}&fc-part-0={q0}&fc-part-1={q1}&...
where q(i) is member i's complete original query string (no leading ?), percent-encoded as a single value.

Why the parts are indexed rather than repeated

fc-part=a&fc-part=b would be shorter, and would make the origin depend on its container preserving the order of getParameterValues - which the servlet spec does not require. The response is positional against i, so an ordering the origin cannot rely on is exactly the wrong thing to build the contract from. With fc-part-{i} the origin reads a known index and the question does not arise.

Why a member's query is carried as one encoded value

Because it is injection-safe by construction: a member's query is a value, never concatenated into the query grammar, so no include URL can smuggle a parameter into the combined request or into a sibling member. It is also the only shape that survives members differing in more than one parameter, or in which parameters they carry at all - see the proposal section 5.1 for why ?id=1|2|3 was not taken.
  • Field Details

    • VERSION

      public static final int VERSION
      Protocol version. Sent as the value of PARAM_COMBINE and echoed in HEADER_COMBINE.
      See Also:
    • PARAM_PREFIX

      public static final String PARAM_PREFIX
      Reserved query-parameter prefix. An include whose own query carries a parameter starting with this is never combined - the edge refuses rather than risk a collision the origin cannot detect.
      See Also:
    • PARAM_COMBINE

      public static final String PARAM_COMBINE
      Presence makes a request a combined request; the value is VERSION.
      See Also:
    • PARAM_PARTS

      public static final String PARAM_PARTS
      Number of members. Lets the origin size its batch before parsing, and the edge check the answer.
      See Also:
    • PARAM_PART

      public static final String PARAM_PART
      Prefix of the per-member parameter: fc-part-0, fc-part-1, ...
      See Also:
    • HEADER_COMBINE

      public static final String HEADER_COMBINE
      Response header. Its presence on a 2xx is the ONLY signal that the origin understood the request - an origin that does not implement combining answers something else, and the edge degrades (proposal section 9.1). A header rather than a media type because x-frontcache-* names are already chosen to survive every intermediary in the deployment (see FCHeaders).
      See Also:
    • ENVELOPE_CONTENT_TYPE

      public static final String ENVELOPE_CONTENT_TYPE
      See Also:
  • Method Details

    • buildCombinedQuery

      public static String buildCombinedQuery(List<String> memberQueries)
      The combined query string, including the leading ?.
      Parameters:
      memberQueries - each member's query string without a leading ?; null is treated as empty
    • encodePart

      public static String encodePart(String query)
      Percent-encodes one member query string for transport as a single parameter value. application/x-www-form-urlencoded (space as +), which is what every servlet container decodes query parameters as - so the origin's own getParameter hands the member's query back already decoded.
    • decodePart

      public static String decodePart(String encoded)
      Inverse of encodePart(String).
    • hasReservedParam

      public static boolean hasReservedParam(String query)
      Does this query string carry a parameter whose name is inside the reserved fc- space? Such an include is not combinable: its parameter would arrive at the origin beside the ones this protocol puts there, and the origin has no way to tell them apart.
    • endpointOf

      public static String endpointOf(String url)
      Everything before the ? - the endpoint a batch is grouped by and addressed to.
    • pathOf

      public static String pathOf(String url)
      The URI path of an absolute include URL - http://host:8080/a/b.htm?x=1 to /a/b.htm. Exists so the combine path can apply dynamic-urls.conf to a member the way FrontCacheEngine.ignoreCache applies it to a request: against the path, since that is what RequestContext.getRequestURI() holds. Matching a different string here would make a combined member cacheable where a single include was not.
    • queryOf

      public static String queryOf(String url)
      Everything after the ?, or "" when there is none. Never null.
    • groupKey

      public static String groupKey(String url, String combineGroup)
      Batch identity: the endpoint plus the combine attribute's value. The endpoint is always part of it, so a group name reused across two paths splits into two batches rather than producing a request no single endpoint can answer.