Application-Defined Metadata#

Added in version 2.2.0.

Starting in 2.2, ESS adds support for application-defined metadata/properties associated with a request; specifically, ESS supports the use of the baggage HTTP header by applications. ESS further expands on this support by providing configuration to add non-baggage request headers to the baggage for propagation within its system.

With ESS’ support application-defined metadata/properties, application-defined metadata can be:

Configuration#

To support this feature, ESS provides the following configuration options:

Note

See Manage Application-Defined Metadata Propagation to configure using kustomization.

INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW

Adds specified non-baggage request headers to the baggage for propagation (unless also specified in the corresponding *_DENY configuration); i.e., support propagation of non-baggage headers as application-defined properties.

This configuration is case-insensitive.

INRUPT_REQUEST_METADATA_REFLECTOR_HEADER_ALLOW

Determines which propagated properties can be returned as response headers (unless also specified in the corresponding *_DENY configuration). This configuration is case-sensitive to the entries in the propagated baggage.

Tip

  • To return a propagated property that was added to the baggage via INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW, ensure that the cases of these properties match.

  • When returning application-properties as response headers, you may need to update QUARKUS_HTTP_CORS_EXPOSED_HEADERS to extend the list of CORS-safelisted response headers.

INRUPT_LOGGING_REQUEST_METADATA_ALLOW

Determines which propagated properties can be included in associated log messages (unless also specified in the corresponding *_DENY configuration). This configuration is case-sensitive to the propagated baggage entries.

Tip

To include a propagated property that was added to the baggage via INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW, ensure that the cases of these properties match.

INRUPT_AUDIT_PRODUCER_REQUEST_METADATA_ALLOW

Determines which propagated properties can be included in associated audit events (unless also specified in the corresponding *_DENY configuration). This configuration is case-sensitive to the propagated baggage entries.

Tip

To include a propagated property that was added to the baggage via INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW, ensure that the cases of these properties match.

Considerations#

Baggage Header#

ESS uses the baggage to support application-defined metadata/property. However, client requests do not need to include a baggage header. If clients send only non-baggage request headers for application-defined properties (as determined by INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW), ESS creates a baggage for propagation within its system. However, if a baggage request header exists, ESS adds the non-baggage requests headers (if any, as determined by ESS configuration) to the baggage, and propagates the enhanced baggage. If a property is sent both as a header and as an entry in the baggage, ESS’ default behavior is to not update the baggage entry. See Duplicate Property Definition for more information.

Duplicate Property Definition#

The INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW configuration adds headers to the request’s baggage for propagation within ESS.

If a property is sent both as a header and as an entry in the baggage, ESS’ default behavior is to not replace the baggage entry with the header. To override this behavior and update the baggage entry with the header value, you can set INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_OVERRIDES option to true.

Property Definition by Internal Requests#

To process a client request, ESS may make various internal HTTP requests to its microservices. Underlying technologies (such as Kubernetes Ingress) may modify the internal HTTP request header that may affect the metadata values that are included in logs/audit events/response headers.

For example, consider an ESS deployment that uses the Ingress-NGINX controller. Ingress-NGINX itself adds an x-request-id header to its requests. If the INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW value includes the x-request-id header:

  • Scenario 1: Duplicate Property Definition

    • An application’s request includes an x-request-id header.

    • ESS adds the x-request-id (and its value) as an entry to the baggage (per INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_ALLOW).

    • Then, Ingress-NGINX would send requests with:

      • the aforementioned baggage that contains the x-request-id entry and

      • an x-request-id header set by Ingress-NGINX.

    ESS’ default behavior is to leave the baggage x-request-id entry unchanged. To have ESS override and update the baggage entry with the header value, set INRUPT_REQUEST_METADATA_PROPAGATOR_HEADER_OVERRIDES to true.

  • Scenario 2: Property Only Defined by Internal Technology

    • An application’s request does not include an x-request-id header or a baggage header with an x-request-id entry.

    • Then, Ingress-NGINX sends internal requests with the x-request-id header. ESS adds this x-request-id header from Ingress-NGINX to the baggage for propagation within its system.

Inrupt Client Libraries Header Support#

Inrupt’s client libraries (Java and JavaScript) support HTTP header handling:

Tip

Use ISO-8859-1 for the header values.

To specify headers on all client requests, you can set the headers to the SolidClient/SolidSyncClient. For example:

import com.inrupt.client.Headers;
import com.inrupt.client.solid.SolidClient;

// ...
// ...

final SolidClient mySolidClient = SolidClient.getClientBuilder()
                .headers(Headers.of(Map.of("x-request-id", List.of("7492595229158059")))).build()
                .session(session);

client.read(URI.create(resourceURL), MyExtendedRDF.class)
    .thenAccept(response -> {
       List<String> responseHeaderValues = response.getHeaders().allValues("x-request-id");
       // ...
});

To specify headers per request, you can set the headers at the request operation level. For example:

import com.inrupt.client.Headers;
import com.inrupt.client.solid.SolidClient;

// ...
// ...

final SolidClient mySolidClient = SolidClient.getClient().session(session);

Headers myHeaders = Headers.of(Map.of("x-request-id", List.of("7492595229158059")));

mySolidClient.read(URI.create(resourceURL), myHeaders, Expense.class)
   .thenAccept(response -> {
       List<String> responseHeaderValues = response.getHeaders().allValues("x-request-id");
       // ...
});

Limits and Restrictions#