Creating a Class 2 WebDAV Server
In addition to features provided by Class 1 WebDAV server, Class 2 WebDAV server supports files and folders locking.
Locking is required to protect the item from being modified by other users. Many WebDAV clients such as Microsoft Web Folders, Mac OS X WebDAV client and Microsoft Office require Class 2 WebDAV server.
To create a Class 2 server, you must implement ILock interface on your folder and file items. Also before updating file content or item custom properties as well as when copying, moving and deleting an item you must verify if the client provided a valid lock-token.
How Locking Works
When a WebDAV client requires to protect an item from modifications, that could be made by other users, it locks the item (usually file), submitting LOCK request to the server. The server generates the new lock token, marks the item as locked and returns the lock token to the client. The WebDAV client application keeps the lock token and when it requires to perform any updates, it supplies the lock token with the request. When the server receives the update request, it verifies that the lock token belongs to the item that is being updated and performs modifications. The diagram below illustrates the whole process:
The actual sequence of requests depends on the operation performed and varies between different WebDAV clients. But to give you an idea of what WebDAV requests are being sent, below is a typical sequence of requests for average WebDAV client for file upload:
- Verify if a file with such name exists.
- Create a zero-length file.
- Lock the newly created file, get the lock token generated by the server and save it on a client.
- Upload content, specifying lock-token.
- Unlock the file.
In addition, the client could submit more requests, for getting and updating file properties, creating temporary files, verifying if a file was actually created, listing folder contents, etc.
Note that while you have to add ILock interface on folder items to report server compliance, most WebDAV clients, including Microsoft Web Folders/mini redirector, Mac OS X Finder, Microsoft Office and OpenOffice, never lock folder items, so on folders you can leave the implementation blank.
How WebDAV Client Discovers Server Compliance
When discovering WebDAV item compliance many WebDAV clients rely on DAV header returned with OPTIONS request. After you implement ILock interface on an item the server will respond with DAV: 1, 2, 3 header, meaning the item supports locking. The server will also return LOCK and UNLOCK verbs in Allow and Public headers.
As soon as some WebDAV clients may rely on DAV or Allow / Public headers returned in response to folder item, it is recommended to add ILock interface on a folder items even if you do not plan to implement lock functions on folders.
When ILock interface is implemented on a folder item your server will report a Class 2 compliance.
Locking the Item
ILock interface provides the means for locking the hierarchy item, updating lock timeout and accessing the list of applied locks. When WebDAV client issues lock the request WebDAV engine calls ILock.lock() function passing information about requested lock. In your lock() implementation, you must generate the new lock-token (usually a GUID), associate the lock-token with the item in the repository and return the lock-token to the engine. Optionally in your lock() implementation you can modify the timeout. The engine then sends lock and timeout values back to WebDAV client.
Locks this item. This code is part of WebDAV Server File System sample provided with IT Hit WebDAV Server Engine for Node.js
The LockLevel.Shared argument specifies if the client is requesting an exclusive or shared lock. If the user set LockLevel.Exclusive lock other users will not be able to set any locks. If the user set shared lock other users will be able to set only shared lock on the item. There could be only 1 exclusive lock set on an item or it can have 1 or more shared locks. If the item is locked and the new lock can not be applied you can throw LockedException, this will inform the client about lock conflict on the server.
The isDeep argument specifies if the lock should be applied only to this item or to the entire subtree. In the case of deep lock (no matter shared or exclusive), you must verify if no exclusive lock is applied to any child item. In the case of deep exclusive lock, you must verify if no shared lock is applied to any child item. If any lock conflicts occur, to provide WebDAV client with information about locked children, you can throw MultistatusException with information about each locked child item.
The lock must be automatically removed by the server after an amount of time specified in a requestedTimeOut parameter are elapsed. A negative value means infinite lock, that should not be removed automatically. You can set the timeout that is different from the one requested by the client. The actual timeout that you apply must be returned to the framework via LockResult return value together with the generated lock-token. The WebDAV framework will then return the updated timeout to WebDAV client.
The owner argument specifies the name of the user applying the lock. Note that this is only an informational sting provided by WebDAV client and it cannot be used for security purposes. To get the name of authenticated user, you must use other mechanisms.
The WebDAV client can change the lock timeout at later times. In this case, the framework will call ILock.refreshLock() function providing the lock-token and new timeout value. Again in this function you can set the timeout that is different from the one requested by the client.
Updates lock timeout information on this item. This code is part of WebDAV Server File System sample provided with IT Hit WebDAV Server Engine for Node.js
The WebDAV client application can request the list of locks applied to the item. In this case framework calls ILock.getActiveLocks() function:
Retrieves non expired locks for this item. This code is part of WebDAV Server File System sample provided with IT Hit WebDAV Server Engine for Node.js