dav.webdav #
WebDAV Server in V
This project implements a WebDAV server using the vweb
framework and modules from crystallib
. The server supports essential WebDAV file operations such as reading, writing, copying, moving, and deleting files and directories. It also includes authentication and request logging for better control and debugging.
Features
- File Operations:Supports standard WebDAV methods:
GET
,PUT
,DELETE
,COPY
,MOVE
, andMKCOL
(create directory) for files and directories.- Authentication:Basic HTTP authentication using an in-memory user database (username:password
).- Request Logging:Logs incoming requests for debugging and monitoring purposes.- WebDAV Compliance:Implements WebDAV HTTP methods with proper responses to ensure compatibility with WebDAV clients.- Customizable Middleware:Extend or modify middleware for custom logging, authentication, or request handling.
Usage
Running the Server
import freeflowuniverse.herolib.dav.webdav
mut app := webdav.new_app(
root_dir: '/tmp/rootdir' // Directory to serve via WebDAV
user_db: {
'admin': 'admin' // Username and password for authentication
}
)!
app.run()
Mounting the Server
Once the server is running, you can mount it as a WebDAV volume:
sudo mount -t davfs <server_url> <mount_point>
For example:
sudo mount -t davfs http://localhost:8080 /mnt/webdav
Important Note: Ensure the root_dir
is not the same as the mount point to avoid performance issues during operations like ls
.
Supported Routes
Method | Route | Description |
---|---|---|
GET | /:path... | Retrieves the contents of a file. |
PUT | /:path... | Creates a new file or updates an existing one. |
DELETE | /:path... | Deletes a file or directory. |
COPY | /:path... | Copies a file or directory to a new location. |
MOVE | /:path... | Moves a file or directory to a new location. |
MKCOL | /:path... | Creates a new directory. |
OPTIONS | /:path... | Lists supported WebDAV methods. |
PROPFIND | /:path... | Retrieves properties (e.g., size, date) of a file or directory. |
Authentication
This WebDAV server uses Basic Authentication. Set the Authorization
header in your client to include your credentials in base64 format:
Authorization: Basic <base64-encoded-credentials>
Example: For the credentials admin:admin
, the header would look like this:
Authorization: Basic YWRtaW46YWRtaW4=
Configuration
You can configure the WebDAV server using the following parameters when calling new_app
:
Parameter | Type | Description |
---|---|---|
root_dir | string | Root directory to serve files from. |
user_db | map[string]string | A map containing usernames as keys and passwords as values. |
port (optional) | int | The port on which the server will run. Defaults to 8080 . |
Example Workflow
- Start the server:
v run webdav_server.v
- Mount the server using
davfs
:
sudo mount -t davfs http://localhost:8080 /mnt/webdav
- Perform operations:
- Create a new file:
echo 'Hello WebDAV!' > /mnt/webdav/hello.txt
- List files:
ls /mnt/webdav
- Delete a file:
rm /mnt/webdav/hello.txt
- Check server logs for incoming requests and responses.
Performance Notes
- Avoid mounting the WebDAV server directly into its own root directory (
root_dir
), as this can cause significant slowdowns for file operations likels
. - Use tools like
cadaver
,curl
, ordavfs
for interacting with the WebDAV server.
Dependencies
- V Programming Language
- Crystallib VFS Module (for WebDAV support)
Future Enhancements
- Support for advanced WebDAV methods like
LOCK
andUNLOCK
. - Integration with persistent databases for user credentials.
- TLS/SSL support for secure connections.
WebDAV Property Model
This file implements the WebDAV property model as defined in RFC 4918. It provides a set of property types that represent various WebDAV properties used in PROPFIND and PROPPATCH operations.
Overview
The model_property.v
file defines:
- A
Property
interface that all WebDAV properties must implement - Various property type implementations for standard WebDAV properties
- Helper functions for XML serialization and time formatting
Property Interface
pub interface Property {
xml() string
xml_name() string
}
All WebDAV properties must implement:- xml()
: Returns the full XML representation of the property with its value
xml_name()
: Returns just the XML tag name of the property (used in property requests)
Property Types
The file implements the following WebDAV property types:
Property Type | Description |
---|---|
DisplayName | The display name of a resource |
GetLastModified | Last modification time of a resource |
GetContentType | MIME type of a resource |
GetContentLength | Size of a resource in bytes |
ResourceType | Indicates if a resource is a collection (directory) or not |
CreationDate | Creation date of a resource |
SupportedLock | Lock capabilities supported by the server |
LockDiscovery | Active locks on a resource |
Helper Functions
fn (p []Property) xml() string
: Generates XML for a list of propertiesfn format_iso8601(t time.Time) string
: Formats a time in ISO8601 format for WebDAV
Usage
These property types are used when responding to WebDAV PROPFIND requests to describe resources in the WebDAV server.
WebDAV Locker
This file implements a locking mechanism for resources in a WebDAV context. It provides functionality to manage locks on resources, ensuring that they are not modified by multiple clients simultaneously.
Overview
The locker.v
file defines:
- A
Locker
structure that manages locks for resources. - A
LockResult
structure that represents the result of a lock operation. - Methods for locking and unlocking resources, checking lock status, and managing locks.
Locker Structure
struct Locker {
mut:
locks map[string]Lock
}
locks
: A mutable map that stores locks keyed by resource name.
LockResult Structure
pub struct LockResult {
pub:
token string // The lock token
is_new_lock bool // Whether this is a new lock or an existing one
}
token
: The unique identifier for the lock.is_new_lock
: Indicates if this is a new lock or an existing one.
Locking and Unlocking
pub fn (mut lm Locker) lock(l Lock) !Lock
: Attempts to lock a resource for a specific owner. Returns aLockResult
with the lock token and whether it's a new lock.pub fn (mut lm Locker) unlock(resource string) bool
: Unlocks a resource by removing its lock.pub fn (lm Locker) is_locked(resource string) bool
: Checks if a resource is currently locked.pub fn (lm Locker) get_lock(resource string) ?Lock
: Returns the lock object for a resource if it exists and is valid.pub fn (mut lm Locker) unlock_with_token(resource string, token string) bool
: Unlocks a resource if the correct token is provided.
Recursive Locking
pub fn (mut lm Locker) lock_recursive(l Lock) !Lock
: Locks a resource recursively, allowing for child resources to be locked (implementation for child resources is not complete).
Cleanup
pub fn (mut lm Locker) cleanup_expired_locks()
: Cleans up expired locks (implementation is currently commented out).
fn format_xml #
fn format_xml(xml_str string) string
parse_xml takes an XML string and returns a cleaned version with whitespace removed between tags
fn new_server #
fn new_server(args ServerArgs) !&Server
fn parse_depth #
fn parse_depth(depth_str string) Depth
parse_depth parses the Depth header value
fn parse_propfind_xml #
fn parse_propfind_xml(req http.Request) !PropfindRequest
parse_propfind_xml parses the XML body of a PROPFIND request
interface Property #
interface Property {
xml() xml.XMLNodeContents
xml_name() string
xml_str() string
}
Property represents a WebDAV property
fn (Locker) lock #
fn (mut lm Locker) lock(l Lock) !Lock
lock attempts to lock a resource for a specific owner Returns a LockResult with the lock token and whether it's a new lock Returns an error if the resource is already locked by a different owner
fn (Locker) unlock #
fn (mut lm Locker) unlock(resource string) bool
fn (Locker) is_locked #
fn (lm Locker) is_locked(resource string) bool
is_locked checks if a resource is currently locked
fn (Locker) get_lock #
fn (lm Locker) get_lock(resource string) ?Lock
get_lock returns the Lock object for a resource if it exists and is valid
fn (Locker) unlock_with_token #
fn (mut lm Locker) unlock_with_token(resource string, token string) bool
fn (Locker) cleanup_expired_locks #
fn (mut lm Locker) cleanup_expired_locks()
fn ([]PropfindResponse) xml #
fn (r []PropfindResponse) xml() string
generate_propfind_response generates a PROPFIND response XML string from Response structs
enum Depth #
enum Depth {
infinity = -1
zero = 0
one = 1
}
enum PropfindType #
enum PropfindType {
allprop // Request all properties
propname // Request property names only
prop // Request specific properties
invalid // Invalid request
}
PropfindType represents the type of PROPFIND request
struct Context #
struct Context {
veb.Context
}
fn (Context) error #
fn (mut ctx Context) error(err WebDAVError) veb.Result
struct LockResult #
struct LockResult {
pub:
token string // The lock token
is_new_lock bool // Whether this is a new lock or an existing one
}
LockResult represents the result of a lock operation
struct PropfindRequest #
struct PropfindRequest {
pub:
typ PropfindType
props []string // Property names if typ is prop
depth Depth // Depth of the request (0, 1, or -1 for infinity)
xml_content string // Original XML content
}
PropfindRequest represents a parsed PROPFIND request
struct PropfindResponse #
struct PropfindResponse {
pub:
href string
found_props []Property
not_found_props []Property
}
Response represents a WebDAV response for a resource
struct RunParams #
struct RunParams {
pub mut:
port int = 8088
background bool
}
struct Server #
struct Server {
veb.Middleware[Context]
pub mut:
lock_manager Locker
user_db map[string]string @[required]
vfs vfs.VFSImplementation
}
fn (Server) copy #
fn (mut server Server) copy(mut ctx Context, path string) veb.Result
fn (Server) delete #
fn (mut server Server) delete(mut ctx Context, path string) veb.Result
fn (Server) exists #
fn (mut server Server) exists(mut ctx Context, path string) veb.Result
fn (Server) get_file #
fn (mut server Server) get_file(mut ctx Context, path string) veb.Result
fn (Server) index #
fn (server &Server) index(mut ctx Context) veb.Result
fn (Server) lock #
fn (mut server Server) lock(mut ctx Context, path string) veb.Result
fn (Server) mkcol #
fn (mut server Server) mkcol(mut ctx Context, path string) veb.Result
fn (Server) move #
fn (mut server Server) move(mut ctx Context, path string) veb.Result
fn (Server) options #
fn (server &Server) options(mut ctx Context, path string) veb.Result
fn (Server) run #
fn (mut server Server) run(params RunParams)
fn (Server) unlock #
fn (mut server Server) unlock(mut ctx Context, path string) veb.Result
struct ServerArgs #
struct ServerArgs {
pub mut:
user_db map[string]string @[required]
vfs vfs.VFSImplementation
}