Architecture

Every WebDAV request passes through this runtime flow:

Laravel WebDAV Server request flow

Request Pipeline

  1. WebDavController::__invoke() accepts the incoming request for /webdav/{space}/{path?}.
  2. If no Basic Auth attempt is present, the controller returns 401 Unauthorized with WWW-Authenticate.
  3. If credentials are present, WebDavServerFactory::make(request) builds the SabreDAV server instance.
  4. DefaultRequestContextResolver::resolve(request) gathers the runtime context:
  5. RequestBasicCredentialsExtractor::extract(request) parses credentials
  6. ValidatorPrincipalAuthenticator::authenticate(username, password) resolves the principal through CredentialValidatorInterface
  7. RequestSpaceKeyResolver::resolve(request) resolves {space} or falls back to config('webdav-server.storage.default_space')
  8. SpaceResolverInterface::resolve(principal, spaceKey) resolves the effective storage target as a WebDavStorageSpaceValueObject; the default implementation DefaultSpaceResolver delegates path assembly to PathResolverInterface — the formula {root}/{prefix}/{principal.id} lives in exactly one place
  9. the gathered runtime DTO is RequestContextDto
  10. StorageRootBuilder::build(principal, space) creates the SabreDAV root tree:
  11. StorageRootCollection
  12. StorageDirectory / StorageFile
  13. Before filesystem operations execute, node classes call PathAuthorizationInterface. On denial, the package throws Sabre\DAV\Exception\Forbidden.
  14. Allowed operations run against the resolved Laravel filesystem disk.
  15. SabreServerConfigurator::configure(server, spaceKey) applies runtime configuration such as the effective base URI, optional SabreDAV logger wiring, and user-defined tagged SabreDAV plugins in addition to the package defaults.
  16. ServerRunnerInterface::run(server) hands off execution to the runtime adapter.
  17. The default adapter SabreServerRunner starts SabreDAV and terminates the request lifecycle.

All extension points are bound via bindIf() in WebdavServerServiceProvider, so app-level bindings can override defaults. The package architecture is intended to remain SOLID-compliant and to prefer established design patterns such as Factory, Strategy, Builder, and Adapter where they clearly fit recurring problems.

Note

The runtime pipeline and its extension boundaries are documented as explicit parts of the package design.

Runtime Notes

  • The package registers the route shape '/webdav/{space}/{path?}'.
  • OPTIONS /webdav/{space}/ is routed into SabreDAV so capability discovery reaches the DAV runtime instead of Laravel's method handling.
  • Root-level PROPFIND requests for /webdav/{space}/ return normal SabreDAV 207 Multi-Status XML responses, even when the resolved storage root is still empty.
  • spaceKey is resolved from the {space} route parameter via RequestSpaceKeyResolver; falls back to config('webdav-server.storage.default_space', 'default') if the parameter is absent.
  • Auth-related extractor/authenticator failures throw domain exceptions:
  • MissingCredentialsException
  • InvalidCredentialsException
  • Account and storage resolution also use package exception hierarchies:
  • AccountNotFoundException
  • AccountDisabledException
  • InvalidAccountConfigurationException
  • SpaceNotConfiguredException
  • InvalidSpaceConfigurationException
  • InvalidDefaultSpaceConfigurationException
  • StreamReadException
  • PathResolverInterface owns the user-scoped path assembly formula ({root}/{prefix}/{principal.id}); DefaultSpaceResolver delegates to it and the WebDavPath Facade exposes it to application code.
  • Controller runtime execution is delegated via ServerRunnerInterface.
  • Default runner is SabreServerRunner, which starts SabreDAV and terminates the request lifecycle.
  • CSRF bypass is registered in WebdavServerServiceProvider::registerCsrfException().
  • CSRF middleware resolution is version-tolerant:
  • Illuminate\Foundation\Http\Middleware\PreventRequestForgery (Laravel 13+)
  • fallback: Illuminate\Foundation\Http\Middleware\VerifyCsrfToken (Laravel 12)
  • CSRF route prefix comes from config('webdav-server.route_prefix') and falls back to config('webdav-server.base_uri').
  • Base URI for SabreDAV is configured in SabreServerConfigurator via config('webdav-server.base_uri', '/webdav/').
  • Additional SabreDAV ServerPlugin instances can be attached from the consuming application by tagging them with WebdavServerServiceProvider::sabrePluginTag().
  • Package logging is controlled through config('webdav-server.logging.driver') and config('webdav-server.logging.level', 'info').
  • When logging.driver is null, package logging and SabreDAV logging are disabled completely.
  • info is used for operational events such as authentication and authorization outcomes.
  • debug is used for request parsing, context resolution, storage resolution, Gate checks, server construction, and SabreDAV runtime configuration.
  • Additional debug logging traces Windows-relevant DAV handling such as OPTIONS, root PROPFIND, request depth, and the effective SabreDAV baseUri.