12 KiB
WebDAV Enhanced Features Documentation
This document describes the critical WebDAV features that have been implemented to provide comprehensive WebDAV protocol support.
Table of Contents
- WebDAV File Locking (LOCK/UNLOCK)
- Partial Content/Resume Support
- Directory Operations (MKCOL)
- Enhanced Status Code Handling
WebDAV File Locking
Overview
WebDAV locking prevents concurrent modification issues by allowing clients to lock resources before modifying them. This implementation supports both exclusive and shared locks with configurable timeouts.
Features
- LOCK Method: Acquire exclusive or shared locks on resources
- UNLOCK Method: Release previously acquired locks
- Lock Tokens: Opaque lock tokens in the format
opaquelocktoken:UUID - Lock Refresh: Extend lock timeout before expiration
- Depth Support: Lock individual resources or entire directory trees
- Automatic Cleanup: Expired locks are automatically removed
Usage
Acquiring a Lock
use readur::services::webdav::{WebDAVService, LockScope};
// Acquire an exclusive lock
let lock_info = service.lock_resource(
"/documents/important.docx",
LockScope::Exclusive,
Some("user@example.com".to_string()), // owner
Some(3600), // timeout in seconds
).await?;
println!("Lock token: {}", lock_info.token);
Checking Lock Status
// Check if a resource is locked
if service.is_locked("/documents/important.docx").await {
println!("Resource is locked");
}
// Get all locks on a resource
let locks = service.get_lock_info("/documents/important.docx").await;
for lock in locks {
println!("Lock: {} (expires: {:?})", lock.token, lock.expires_at);
}
Refreshing a Lock
// Refresh lock before it expires
let refreshed = service.refresh_lock(&lock_info.token, Some(7200)).await?;
println!("Lock extended until: {:?}", refreshed.expires_at);
Releasing a Lock
// Release the lock when done
service.unlock_resource("/documents/important.docx", &lock_info.token).await?;
Lock Types
- Exclusive Lock: Only one client can hold an exclusive lock
- Shared Lock: Multiple clients can hold shared locks simultaneously
Error Handling
- 423 Locked: Resource is already locked by another process
- 412 Precondition Failed: Lock token is invalid or expired
- 409 Conflict: Lock conflicts with existing locks
Partial Content Support
Overview
Partial content support enables reliable downloads with resume capability, essential for large files or unreliable connections. The implementation follows RFC 7233 for HTTP Range Requests.
Features
- Range Headers: Support for byte-range requests
- 206 Partial Content: Handle partial content responses
- Resume Capability: Continue interrupted downloads
- Chunked Downloads: Download large files in manageable chunks
- Progress Tracking: Monitor download progress in real-time
Usage
Downloading a Specific Range
use readur::services::webdav::ByteRange;
// Download bytes 0-1023 (first 1KB)
let chunk = service.download_file_range(
"/videos/large_file.mp4",
0,
Some(1023)
).await?;
// Download from byte 1024 to end of file
let rest = service.download_file_range(
"/videos/large_file.mp4",
1024,
None
).await?;
Download with Resume Support
use std::path::PathBuf;
// Download with automatic resume on failure
let local_path = PathBuf::from("/downloads/large_file.mp4");
let content = service.download_file_with_resume(
"/videos/large_file.mp4",
local_path
).await?;
Monitoring Download Progress
// Get progress of a specific download
if let Some(progress) = service.get_download_progress("/videos/large_file.mp4").await {
println!("Downloaded: {} / {} bytes ({:.1}%)",
progress.bytes_downloaded,
progress.total_size,
progress.percentage_complete()
);
}
// List all active downloads
let downloads = service.list_active_downloads().await;
for download in downloads {
println!("{}: {:.1}% complete",
download.resource_path,
download.percentage_complete()
);
}
Canceling a Download
// Cancel an active download
service.cancel_download("/videos/large_file.mp4").await?;
Range Format
bytes=0-1023- First 1024 bytesbytes=1024-- From byte 1024 to endbytes=-500- Last 500 bytesbytes=0-500,1000-1500- Multiple ranges
Directory Operations
Overview
Comprehensive directory management using WebDAV-specific methods, including the MKCOL method for creating collections (directories).
Features
- MKCOL Method: Create directories with proper WebDAV semantics
- Recursive Creation: Create entire directory trees
- MOVE Method: Move or rename directories
- COPY Method: Copy directories with depth control
- DELETE Method: Delete directories recursively
- Directory Properties: Set custom properties on directories
Usage
Creating Directories
use readur::services::webdav::CreateDirectoryOptions;
// Create a single directory
let result = service.create_directory(
"/projects/new_project",
CreateDirectoryOptions::default()
).await?;
// Create with parent directories
let options = CreateDirectoryOptions {
create_parents: true,
fail_if_exists: false,
properties: None,
};
let result = service.create_directory(
"/projects/2024/january/reports",
options
).await?;
// Create entire path recursively
let results = service.create_directory_recursive(
"/projects/2024/january/reports"
).await?;
Checking Directory Existence
if service.directory_exists("/projects/2024").await? {
println!("Directory exists");
}
Listing Directory Contents
let contents = service.list_directory("/projects").await?;
for item in contents {
println!(" {}", item);
}
Moving Directories
// Move (rename) a directory
service.move_directory(
"/projects/old_name",
"/projects/new_name",
false // don't overwrite if exists
).await?;
Copying Directories
// Copy directory recursively
service.copy_directory(
"/projects/template",
"/projects/new_project",
false, // don't overwrite
Some("infinity") // recursive copy
).await?;
Deleting Directories
// Delete empty directory
service.delete_directory("/projects/old", false).await?;
// Delete directory and all contents
service.delete_directory("/projects/old", true).await?;
Status Code Handling
Overview
Enhanced error handling for WebDAV-specific status codes, providing detailed error information and automatic retry logic.
WebDAV Status Codes
Success Codes
- 207 Multi-Status: Response contains multiple status codes
- 208 Already Reported: Members already enumerated
Client Error Codes
- 422 Unprocessable Entity: Request contains semantic errors
- 423 Locked: Resource is locked
- 424 Failed Dependency: Related operation failed
Server Error Codes
- 507 Insufficient Storage: Server storage full
- 508 Loop Detected: Infinite loop in request
Error Information
Each error includes:
- Status code and description
- Resource path affected
- Lock token (if applicable)
- Suggested resolution action
- Retry information
- Server-provided details
Usage
Enhanced Error Handling
use readur::services::webdav::StatusCodeHandler;
// Perform operation with enhanced error handling
let response = service.authenticated_request_enhanced(
Method::GET,
&url,
None,
None,
&[200, 206] // expected status codes
).await?;
Smart Retry Logic
// Automatic retry with exponential backoff
let result = service.with_smart_retry(
|| Box::pin(async {
// Your operation here
service.download_file("/path/to/file").await
}),
3 // max attempts
).await?;
Error Details
match service.lock_resource(path, scope, owner, timeout).await {
Ok(lock) => println!("Locked: {}", lock.token),
Err(e) => {
// Error includes WebDAV-specific information:
// - Status code (e.g., 423)
// - Lock owner information
// - Suggested actions
// - Retry recommendations
println!("Lock failed: {}", e);
}
}
Retry Strategy
The system automatically determines if errors are retryable:
| Status Code | Retryable | Default Delay | Backoff |
|---|---|---|---|
| 423 Locked | Yes | 10s | Exponential |
| 429 Too Many Requests | Yes | 60s | Exponential |
| 503 Service Unavailable | Yes | 30s | Exponential |
| 409 Conflict | Yes | 5s | Exponential |
| 500-599 Server Errors | Yes | 30s | Exponential |
| 400-499 Client Errors | No | - | - |
Integration with Existing Code
All new features are fully integrated with the existing WebDAV service:
use readur::services::webdav::{
WebDAVService, WebDAVConfig,
LockManager, PartialContentManager,
CreateDirectoryOptions, ByteRange,
WebDAVStatusCode, WebDAVError
};
// Create service as usual
let config = WebDAVConfig { /* ... */ };
let service = WebDAVService::new(config)?;
// All new features are available through the service
// - Locking: service.lock_resource(), unlock_resource()
// - Partial: service.download_file_range(), download_file_with_resume()
// - Directories: service.create_directory(), delete_directory()
// - Errors: Automatic enhanced error handling
Testing
All features include comprehensive test coverage:
# Run all tests
cargo test --lib
# Run specific feature tests
cargo test locking_tests
cargo test partial_content_tests
cargo test directory_ops_tests
# Run integration tests (requires WebDAV server)
cargo test --ignored
Performance Considerations
- Lock Management: Locks are stored in memory with automatic cleanup of expired locks
- Partial Downloads: Configurable chunk size (default 1MB) for optimal performance
- Directory Operations: Batch operations use concurrent processing with semaphore control
- Error Handling: Smart retry with exponential backoff prevents server overload
Security Considerations
- Lock Tokens: Use cryptographically secure UUIDs
- Authentication: All operations use HTTP Basic Auth (configure HTTPS in production)
- Timeouts: Configurable timeouts prevent resource exhaustion
- Rate Limiting: Respect server rate limits with automatic backoff
Compatibility
The implementation follows these standards:
- RFC 4918 (WebDAV)
- RFC 7233 (HTTP Range Requests)
- RFC 2518 (WebDAV Locking)
Tested with:
- Nextcloud
- ownCloud
- Apache mod_dav
- Generic WebDAV servers
Migration Guide
For existing code using the WebDAV service:
- No Breaking Changes: All existing methods continue to work
- New Features Are Opt-In: Use new methods only when needed
- Enhanced Error Information: Errors now include more details but maintain backward compatibility
- Automatic Benefits: Some improvements (like better error handling) apply automatically
Troubleshooting
Lock Issues
- 423 Locked Error: Another client holds a lock. Wait or use lock token
- Lock Token Invalid: Lock may have expired. Acquire a new lock
- Locks Not Released: Implement proper cleanup in error paths
Partial Content Issues
- Server Doesn't Support Ranges: Falls back to full download automatically
- Resume Fails: File may have changed. Restart download
- Slow Performance: Adjust chunk size based on network conditions
Directory Operation Issues
- 409 Conflict: Parent directory doesn't exist. Use
create_parents: true - 405 Method Not Allowed: Directory may already exist or server doesn't support MKCOL
- 507 Insufficient Storage: Server storage full. Contact administrator
Future Enhancements
Potential future improvements:
- WebDAV SEARCH method support
- Advanced property management (PROPPATCH)
- Access control (WebDAV ACL)
- Versioning support (DeltaV)
- Collection synchronization (WebDAV Sync)