0002. WebDAV Request Pipeline And Runtime Boundary¶
Status¶
Accepted
Context¶
This package exposes a WebDAV server endpoint inside a Laravel application, but the actual protocol runtime is implemented by SabreDAV.
That creates two competing concerns:
- the package must keep the request flow explicit, replaceable, and understandable from Laravel's perspective
- the package must still hand off execution to the SabreDAV runtime, which takes over protocol handling and response generation
If request handling and SabreDAV runtime execution are collapsed into one class, several problems appear:
- controller responsibilities become blurred
- authentication, routing, space resolution, authorization, and node construction become harder to replace independently
- testing becomes brittle because
server->start()terminates the request lifecycle - consumers of the package lose clear extension points for auth, storage routing, and authorization
The package already has an explicit internal flow:
WebDavControlleraccepts the request and checks whether a Basic Auth attempt existsWebDavServerFactorybuilds the SabreDAVServerDefaultRequestContextResolverresolves credentials, principal, space key, and storage spaceStorageRootBuildercreates the WebDAV root tree for the resolved principal and storage spaceSabreServerConfiguratorapplies SabreDAV runtime configurationServerRunnerInterfaceexecutes the prepared server
Decision¶
The package keeps the WebDAV request pipeline explicit and separates request orchestration from runtime execution.
The architectural rules are:
WebDavControlleris responsible only for request entry concerns- server construction happens in
WebDavServerFactory - request context resolution happens through dedicated resolver/authenticator/extractor components
- storage tree construction happens through
StorageRootBuilder - SabreDAV runtime configuration happens through
ServerConfiguratorInterface - final runtime execution happens through
ServerRunnerInterface
ServerRunnerInterface is the explicit runtime boundary.
The default implementation remains SabreServerRunner, which calls server->start(); exit;, but the package does not
hardcode that behavior into the controller or factory.
All major extension points in the request pipeline continue to be exposed through contracts and default bindIf()
bindings so that consuming applications can replace them without forking the package.
Consequences¶
Positive consequences:
- the full request path is explicit and traceable from controller to filesystem access
- authentication, space resolution, authorization, and runtime execution stay independently replaceable
- the controller remains thin and focused
- tests can verify orchestration and request handling without embedding SabreDAV process termination everywhere
- the architecture aligns with the package goal of contract-driven extensibility
Trade-offs:
- the request flow spans more classes than a monolithic controller-based implementation
- understanding the full runtime path requires familiarity with several collaborators
- the runtime boundary introduces one additional abstraction layer
Rejected alternative:
- call
Server::start()directly insideWebDavController - rejected because it couples request orchestration to SabreDAV runtime execution, weakens replaceability, and makes testing harder