feat: Propagate Request Headers#19572
Conversation
| * no header propagation is performed (the feature is effectively disabled). | ||
| */ | ||
| @JsonProperty | ||
| public Map<String, String> getHeaderToContextKey() |
FrankChen021
left a comment
There was a problem hiding this comment.
| Severity | Findings |
|---|---|
| P0 | 0 |
| P1 | 0 |
| P2 | 1 |
| P3 | 0 |
| Total | 1 |
Reviewed 33 files, including all 22 changed files.
I found one issue: configured request-header targets can bypass existing query-context authorization when mapped to operational context keys such as priority or lane.
This is an automated review by Codex GPT-5.5
FrankChen021
left a comment
There was a problem hiding this comment.
| Severity | Findings |
|---|---|
| P0 | 0 |
| P1 | 0 |
| P2 | 1 |
| P3 | 0 |
| Total | 1 |
Reviewed 11 of 32 changed files.
This is an automated review by Codex GPT-5.5
FrankChen021
left a comment
There was a problem hiding this comment.
| Severity | Findings |
|---|---|
| P0 | 0 |
| P1 | 0 |
| P2 | 1 |
| P3 | 0 |
| Total | 1 |
Reviewed 37 of 37 changed files.
This is an automated review by Codex GPT-5.5
FrankChen021
left a comment
There was a problem hiding this comment.
I have reviewed the code for correctness, edge cases, concurrency, and integration risks; no issues found.
Reviewed 41 of 41 changed files.
This is an automated review by Codex GPT-5.5
Description
Adds a configurable mechanism to capture inbound HTTP headers and propagate them through Druid:
Inbound capture — a servlet filter (RequestHeaderContextFilter) reads the headers listed in druid.audit.requestHeaders.headerToContextKey, binds the values to a request thread-local, and clears them in a finally block.
Injection into Query.getContext() — QueryLifecycle.initialize() strips any user-supplied values for the configured reserved context keys (anti-spoof), then injects the filter-captured values. Druid's existing native sub-query context propagation flows the values to historicals/peons for free.
Wire propagation on broker → historical RPCs — DirectDruidClient reads from the current query context and re-attaches the configured headers onto each outbound Request, so the receiving node's filter captures them just as if a client had sent them. End-to-end propagation without trusting the JSON body context.
Typed RequestInfo.traceId audit column — AuthorizationUtils.buildRequestInfo reads the value of the "traceId" context key (canonical name) from the filter thread-local, populating a new typed field on RequestInfo. Every AuditEntry built via AuthorizationUtils automatically carries the trace ID, with @JsonInclude(NON_NULL) so existing audit JSON is byte-identical when no trace header is sent.
Config
Default: X-Druid-Trace-Id → traceId (enabled out of the box)
druid.audit.requestHeaders.headerToContextKey={"X-Druid-Trace-Id": "traceId"}Add additional headers
Explicitly disable (empty map)
druid.audit.requestHeaders.headerToContextKey={}Mapping any header to a Druid reserved context key (queryId, subQueryId, sqlQueryId) throws at config-bind time so a client can't overwrite the server-assigned queryId.
Release note
Druid now supports propagating configured inbound HTTP headers (default X-Druid-Trace-Id) through the query context and into audit events. Configure via
druid.audit.requestHeaders.headerToContextKey. Mapping a header to a Druid reserved context key (queryId, subQueryId, sqlQueryId) is rejected at startup. A new typed traceId field on RequestInfo lands in the audit table for correlation with distributed-trace systems.Key changed/added classes
This PR has: