Make the x-dotrequest-cost response header configurable independently of request-cost accounting
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Problem
Request-cost accounting and the x-dotrequest-cost response header are the same switch. addCostHeader is gated only on isAccountingEnabled() (RequestCostApiImpl.java:333-336), so there is no way to collect request-cost telemetry without also emitting a header on every response — or to suppress the header without also killing the telemetry.
Both configurations are legitimate:
- Some customers want the header — it is useful for debugging and for their own cost attribution.
- Some customers do not want it. An unexplained header on every response reads as surveillance or throttling to anyone running a security scan.
Right now they cannot have what they want independently, and the platform loses telemetry as the price of honouring the second preference.
Real-world driver
Lennox asked for both new headers removed (FD 36186) after seeing x-dotrequest-cost and x-dotratelimit-toks-max and concluding dotCMS was rate-limiting them. The accommodation was DOT_REQUEST_COST_ACCOUNTING_ENABLED=false in system_table on three of their environments — the only lever available.
Consequence: three environments are silently excluded from the request-cost telemetry epic (IaC #8162), and they cannot be re-enabled without breaking a customer commitment. Investigation: IaC #8196.
This is smaller than a refactor — the pattern already exists next door
The rate-limit header in the same filter already has its own independent switch: RATE_LIMIT_ADD_HEADER_INFO (default true, LeakyTokenBucketImpl.java:57-58), separate from RATE_LIMIT_ENABLED. The cost header just never got the equivalent.
Suggested shape, mirroring it exactly:
- add
REQUEST_COST_ADD_HEADER_INFO, defaulttrue(current behaviour unchanged) - gate
addCostHeaderon it - leave
REQUEST_COST_ACCOUNTING_ENABLEDas the master switch for accounting + telemetry
One config key and one if. No change to accounting, the publisher, the filter chain, or the payload. Worth resisting anything larger unless something below turns up a reason.
Acceptance criteria
- All four combinations behave correctly:
| accounting | header switch | telemetry publishes | x-dotrequest-cost |
|---|---|---|---|
| on | on | yes | yes (today's behaviour) |
| on | off | yes | no ← the case we cannot express today |
| off | on | no | no |
| off | off | no | no |
- Default is unchanged for every existing install
- Settable per environment via
DOT_REQUEST_COST_ADD_HEADER_INFOso it can be pinned in a manifest (an env var short-circuitssystem_table,Config.java:772-781) as well as set at runtime - The admin full-accounting report (
?REQUEST_COST_ACCOUNTING_TYPE=..., admin-only) still works with the header suppressed - Test covering the on/off case, since that is the one with no current expression
Notes
- Consider whether
RATE_LIMIT_ADD_HEADER_INFOand the new key should be documented together — a customer objecting to one will usually object to both, and today that pairing is tribal knowledge. - Once this ships, IaC #8196 can re-enable Lennox with the header still suppressed, which is what the customer actually asked for.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in RequestCostApiImpl.java:333-336 and compare the existing independent switch in LeakyTokenBucketImpl.java:57-58. Check Config.java:772-781 to understand environment-variable precedence, then add a test covering accounting enabled with the header switch disabled. Done means all four combinations work, the default remains unchanged, and the admin full-accounting report still works when the header is suppressed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 75/100