---
title: "ADR-0016: Public RequestFactory as the URI boundary"
manual: "HTTP Guard"
version: "main"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-http-guard:adr-0016@main"
source: "Adr/ADR-0016-PublicRequestFactoryBoundary.rst"
rendered: "2026-10-18T14:31:38+00:00"
---

# ADR-0016: Public RequestFactory as the URI boundary {#adr-0016}

-   *Status:* Accepted
-   *Date:* 2026-10-10
-   *Relation:* Supplements ADR-0003; its middleware and transport boundaries remain.

## Context {#adr-0016-context}

A PSR-7 URI object may already have lost information from the original
string. Middleware cannot recover that information to distinguish forbidden
raw syntax. The registered TYPO3 path therefore needs validation before
Core processes the raw URI. The public
`TYPO3CMSCoreHttpRequestFactory` is the entry point for this
boundary; the internal `GuzzleClientFactory` is not replaced.

Core 13 and Core 14 differ in `readonly` inheritance. A version
number alone does not establish a compatible parent class. A conflicting
object mapping or different factory instances would also change the
qualified entry point.

## Decision {#adr-0016-decision}

[`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/14.3/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php) registers `GuardedRequestFactory13` or
`GuardedRequestFactory14` according to the actual supported Core
shape, when no existing mapping is present. Registration is validated on
every request, including Disabled mode. Conflicts are neither overwritten
nor silently accepted. The Core factory and the PSR factory alias must
resolve to the same expected instance.

`RequestFactoryCompatibility` validates the supported version,
inheritance, visibility, return type, parameter names, types and defaults,
and constructor before loading the replacement class. The parent's
`readonly` shape must match its Core branch. The public request
signature remains intact.

`RawRequestGuardTrait` validates the raw URI before PSR-7
processing in Enforce mode. Observe reports a denial and continues to
delegate; Disabled skips raw policy validation. The replacement then
delegates to the exact original Core factory, preserving method, options
and context. Middleware ordering, Core context restrictions and the
controlled terminal transport from [ADR-0003: Two middleware boundaries and a controlled terminal transport](https://docs.typo3.org/permalink/netresearch/nr-http-guard:adr-0003@main) remain additional
boundaries.

## Alternatives considered {#adr-0016-alternatives}

-   **PSR-7 middleware alone:** cannot validate raw information already lost.
-   **Replace the internal GuzzleClientFactory:** couples the extension to an
    internal Core API and replaces more than the required URI boundary.
-   **One replacement class for both Core branches:** ignores incompatible
    `readonly` inheritance rules.
-   **Accept only a version number or any existing mapping:** establishes
    neither the actual ABI nor the active factory identity.

## Consequences {#adr-0016-consequences}

The registered Core factory gains an earlier validation boundary without
a second HTTP stack. Incompatible APIs or conflicting registration produce
a controlled failure. Projects with their own factory replacement need an
explicit integration. Early bootstrap calls, independent clients and
direct sockets remain outside this boundary. For an already constructed
PSR-18 request, raw URI validation remains the caller's responsibility;
see [Raw URLs and PSR-7](https://docs.typo3.org/permalink/netresearch/nr-http-guard:api-raw-uri@main) and [Coverage and trust boundary](https://docs.typo3.org/permalink/netresearch/nr-http-guard:security-coverage@main).

## Sources and evidence {#adr-0016-verification}

The implementation is in `Classes/Http/RequestFactoryCompatibility.php`,
`Classes/Http/RawRequestFactoryRegistration.php`,
`Classes/Http/RawRequestGuardTrait.php` and the two replacement
classes. Wiring is in [`Configuration/Services.yaml`](https://docs.typo3.org/m/typo3/reference-coreapi/14.3/en-us/ExtensionArchitecture/FileStructure/Configuration/ServicesYaml.html#file-extension-configuration-services-yaml) and
[`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/14.3/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php).

`Tests/Unit/RequestFactoryCompatibilityTest.php`,
`Tests/Unit/RequestFactoryAbiContractTest.php`,
`Tests/Unit/RawRequestFactoryModeTest.php` and
`Tests/Unit/CoreConfigurationShapeTest.php` maintain compatibility,
mode and configuration controls. The genuine Core bootstrap probe in
`Tests/Functional/production-bootstrap.php` checks factory identity
and raw syntax rejection with separate contact counters. Previously
executed results are recorded under [Verification report](https://docs.typo3.org/permalink/netresearch/nr-http-guard:verification-report@main).
Authoring this ADR inspected the current sources; it did not execute these
tests again or produce a new Native mutation measurement.

## Reconsideration trigger {#adr-0016-reassessment-trigger}

Changes to the public Core signature, inheritance, object registration or
PSR alias wiring require renewed ABI and bootstrap qualification. An
expanded coverage promise needs evidence for each additional entry path.
