Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Let's say you need to implement a WebDAV server with access control to files, directories and various file system functions. Users must authenticate with a token or password specified in the authorization headers.
I tried to implement similar access control using a few different hacks around the
dav_server
, but it was unsuccessful. In particular, I don't recommend trying to encode anything to pass to the file system adapter in file paths, since thedav_server
needs them to provide the full path to the files in its responses.To provide access control to file systems of this kind, I organized access to file system adapters through the
GuardedFileSystem<C>
trait, whose methods require a reference to generic credentialsC
to operate. I kept the same stateless approach to handling file system requests. TheDavHandler<C>
receives credentials from the library user in theDavHandler::<C>::handle_guarded
method.Backward compatibility
I want to preserve the support of old
DavFileSystem
implementations. Writing new adapters to file systems without access control shouldn't become any more difficult either. For example, introducing aGuardedFileSystem
doesn't require any changes todav-server-opendalfs
(can be compiled as is).For this purpose, blanket implementation
GuardedFileSystem<()>
forDavFileSystem
was made. It required figuring out howBox<dyn GuardedFileSystem<C>>
would be cloned. The old approach withBoxCloneFs
required casting aBox<dyn DavFileSystem>
intoBox<dyn GuardedFileSystem<()>>
which is problematic. Instead, I took a crate from dtolnay —dyn-clone
, which solves the problem of cloningBox<dyn X>
— thanks to it, a trait can be object-safe, and at the same time impose a requirement on the cloning of its implementations.Since
BoxCloneFs
is no longer needed, I suggest removing this trait. Even though it was marked as#[doc(hidden)]
, it's essentially a backwards-incompatible change, but it won't require many edits from those maintaining theirDavFileSystem
implementations and who usedBoxCloneFs
. Since we already usedyn-clone
for file system types, I used the same approach forDavLockSystem
andDavMetaData
(BoxCloneLs
andBoxCloneMd
were removed too).The old methods
DavHandler::handle
and others without access control retained their signature and the code with them doesn't require refactoring since the generic credentials parameterC
has a default valueC = ()
.The
litmus
server exampleexamples/sample-litmus-server.rs
reads auth headers but doesn't use credentials in the file system adapter, so it doesn't require refactoring.Examples
examples/auth.rs
.To do
DavHandler<C>
could take the principal (to specify locks' owner) automatically from the credentials type parameterC
if it implements thePrincipal
trait (not implemented). I decided that the confusion that such a feature would introduce was not worth the loss of flexibility in specifying the principal.if_match_get_tokens
function needs to be refactored as the method ofDavInner
, since half of its 6 arguments are alreadyDavInner
's fields. I didn't do this because it would introduce too many changes outside the scope of the pull request.DavConfig
fields to construct theDavInner
, then we clone them to handle asynchronous requests to theDavInner
, after which we clone a bunch of them intoPropWriter
(which is also cloned) for directory traversal. Most likely we should relate toDavInner
throughself: Arc<Self>
(or&self
) and clone theArc
if necessary to prevent excess allocations.