Problem/Motivation
The existing constraints cover request context well (path, route, HTTP method, query string, domain) but none of them inspect the HTTP request headers.
A growing number of Drupal sites operate in a decoupled or headless architecture where the same backend serves multiple consumers: a web frontend, a mobile app, a kiosk, a third-party integration, etc. These consumers often identify themselves through a custom request header (e.g. X-Client-Type: mobile-app) or through standard headers like Accept or Accept-Language.
In this context, some consumers trigger significantly heavier server-side processing than others. For example, a mobile app may request a JSON:API resource that resolves deep paragraph nesting and several entity references in a single call, while the same route hit by the web frontend only partially hydrates the same data. The HTTP method is identical (GET), the route is the same, but the memory pressure is very different depending on who is calling.
None of the existing constraints can express "apply this policy only when the request comes from consumer X", without coupling to a path or a query string that the consumer may not control.
Proposed resolution
Create a new constraint plugin based on the value of an HTTP request header.
Configuration form:
- Header name (text field, e.g. X-Consumer, Accept)
- Match mode (select, one of: contains / starts with / ends with / matches exactly / regex)
- Header value (text field)
The `evaluate()` method would:
- Fetch the current request from the request_stack service
- Read the configured header from the request
- Compare its value against the configured string using the selected match mode:
- contains — str_contains($value, $pattern)
- starts with — str_starts_with($value, $pattern)
- ends with — str_ends_with($value, $pattern)
- matches exactly — strict string equality
- regex — preg_match($pattern, $value)
- Return TRUE if the header is present and the value matches
The negate option (already built into the base plugin) handles the inverse case out of the box: e.g. "apply to all requests except those coming from the internal crawler".
Use case example
A decoupled Drupal site exposes a JSON:API endpoint consumed by several mobile clients (X-Consumer: mobile-android, X-Consumer: mobile-ios). Both trigger deep paragraph resolution that hits the 128M default limit.
A single policy covers both clients without listing each variant explicitly:
- Header name: X-Consumer
- Match mode: starts with
- Value: mobile
- Memory: 256M
A second policy targets only a legacy integration client that sends X-Consumer: legacy-erp-v1:
- Header name: X-Consumer
- Match mode: ends with
- Value: erp-v1
- Memory: 512M
This avoids duplicating policies per client variant and keeps the config readable and maintainable as new consumers are onboarded.
Issue fork memory_limit_policy-3590713
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
vbouchetImplemented