Skip to content

Latest commit

 

History

History
420 lines (333 loc) · 9.7 KB

File metadata and controls

420 lines (333 loc) · 9.7 KB

WebDAV Server - Project Summary

Overview

A production-ready WebDAV server implementation in pure C with UnQLite embedded database. Fully compliant with RFC 4918 and tested with real-world clients.

Key Achievements

✅ RFC Compliance

  • 100% litmus test pass rate (66/66 tests)
  • Full RFC 4918 implementation
  • RFC 2518 compliance
  • HTTP 100-continue support

✅ Robustness

  • Handles 150+ files in single directory
  • Dynamic XML buffer allocation (no crashes)
  • Binary file integrity guarantee
  • Thread-safe concurrent requests

✅ Cross-Platform

  • Native Linux/Unix support
  • Cosmopolitan binary (Linux, macOS, Windows)
  • No external dependencies

✅ Features

  • All WebDAV methods: GET, PUT, DELETE, MKCOL, COPY, MOVE, PROPFIND, PROPPATCH, LOCK, UNLOCK
  • HTTP Basic Authentication
  • Custom properties (PROPPATCH/PROPFIND)
  • Unicode/UTF-8 filename support
  • Depth header support (0, 1, infinity)

Technical Architecture

Storage Layer (UnQLite)

FILE:/path              → Binary content
META:/path              → JSON metadata
COLL:/path              → Directory marker
PROP:/path|ns|name      → Custom properties

Module Structure

src/
├── storage.c/h    # UnQLite storage layer
├── http.c/h       # HTTP server foundation
├── webdav.c/h     # WebDAV protocol implementation
└── main.c         # Entry point and CLI

Request Flow

HTTP Request → http.c (parse) → webdav.c (route) → storage.c (CRUD) → UnQLite DB

Critical Fixes Implemented

1. XML Buffer Overflow (Major Bug)

Problem: Fixed 32KB buffer crashed with 100+ files Solution: Dynamic allocation with auto-resizing Impact: Server now handles 150+ files without crashing

2. Binary File Truncation

Problem: Potential 8KB limit with binary files Solution: Proper HTTP body handling with size tracking Impact: 100KB+ files work perfectly

3. Duplicate Folder Listings

Problem: Missing duplicate check in storage_list_collection() Solution: Added exists() check for direct children Impact: Clean directory listings, no duplicates

4. Cosmopolitan Compatibility

Problem: sscanf doesn't handle JSON in Cosmopolitan Solution: Manual string parsing with strchr/strstr Impact: Full Unicode support in cross-platform builds

Test Results

Litmus Test Suite

Basic:      16/16 (100%)
Copymove:   13/13 (100%)
Props:      30/30 (100%)
Locks:       3/3 (100%)
Http:        4/4 (100%)
Total:      66/66 (100%)

Stress Tests

  • ✅ 150+ files in single directory
  • ✅ 86KB XML responses
  • ✅ 100KB binary file uploads
  • ✅ MD5 integrity verification
  • ✅ Unicode/Chinese filenames
  • ✅ Concurrent requests

Client Compatibility

  • ✅ Windows Explorer WebDAV
  • ✅ macOS Finder WebDAV
  • ✅ Linux davfs2
  • ✅ cadaver CLI
  • ✅ Any RFC 4918 client

Performance Metrics

Metric Value
Max files per directory 150+ (tested)
Max XML response size 86,973 bytes
Binary file limit 10MB (configurable)
Concurrent requests Thread-safe
Memory usage Dynamic allocation
Database size ~1KB per file

Build System

Standard Build

make                    # Standard Linux/Unix
make debug              # Debug with symbols
make coverage           # Coverage instrumentation

Cross-Platform Build

make cosmo              # Cosmopolitan binary

Modern Build (CMake)

mkdir build && cd build
cmake ..
make

Docker

docker build -t webdav-server .
docker-compose up -d

File Structure

.
├── src/                    # Source code
│   ├── main.c             # Entry point
│   ├── http.c/h           # HTTP server
│   ├── webdav.c/h         # WebDAV protocol
│   └── storage.c/h        # Database layer
├── unqlite/               # Embedded database
├── tests/                 # Test scripts
│   └── run_all_tests.sh   # Comprehensive tests
├── scripts/               # Utility scripts
│   └── quick_start.sh     # Quick start guide
├── .github/workflows/     # CI/CD
│   └── ci.yml             # GitHub Actions
├── docker-compose.yml     # Docker orchestration
├── Dockerfile             # Container image
├── CMakeLists.txt         # Modern build
├── Makefile               # Standard build
├── README.md              # Documentation
├── CONTRIBUTING.md        # Contributing guide
├── LICENSE                # MIT License
└── PROJECT_SUMMARY.md     # This file

Command Line Options

./webdav_server [OPTIONS]

Options:
  -p, --port PORT     Listen port (default: 8080)
  -d, --db PATH       Database file (default: webdav.db)
                     Use :mem: for in-memory
  -r, --root PATH     Root path prefix (default: /)
  -u, --user USERNAME HTTP Basic Auth username
  -P, --pass PASSWORD HTTP Basic Auth password
  -t, --test          Run test mode
  -h, --help          Show help

Usage Examples

Basic Operations

# Start server
./webdav_server -p 8080 --db webdav.db &

# Create directory
curl -X MKCOL http://localhost:8080/projects

# Upload file
echo "Hello" | curl -X PUT --data-binary @- http://localhost:8080/hello.txt

# List contents
curl -X PROPFIND http://localhost:8080/

# Download
curl http://localhost:8080/hello.txt

# Copy
curl -X COPY -H "Destination: http://localhost:8080/copy.txt" \
  http://localhost:8080/hello.txt

# Move/rename
curl -X MOVE -H "Destination: http://localhost:8080/renamed.txt" \
  http://localhost:8080/copy.txt

# Delete
curl -X DELETE http://localhost:8080/renamed.txt

Custom Properties

# Set property
curl -X PROPPATCH --data-binary \
  '<D:propertyupdate xmlns:D="DAV:" xmlns:custom="http://example.com/">
    <D:set><D:prop><custom:status>approved</custom:status></D:prop></D:set>
  </D:propertyupdate>' \
  http://localhost:8080/file.txt

# Query property
curl -X PROPFIND --data-binary \
  '<D:propfind xmlns:D="DAV:" xmlns:custom="http://example.com/">
    <D:prop><custom:status/></D:prop>
  </D:propfind>' \
  http://localhost:8080/file.txt

Authentication

# Start with auth
./webdav_server -p 8080 -u admin -P secret --db auth.db &

# Use credentials
curl -u admin:secret -X PROPFIND http://localhost:8080/

Development Workflow

  1. Make changes in src/
  2. Build: make clean && make
  3. Test: make test-all
  4. Verify: make test-litmus
  5. Check: make valgrind (memory leaks)

CI/CD Pipeline

GitHub Actions runs on every push/PR:

  • ✅ Linux build and tests
  • ✅ macOS build and tests
  • ✅ Cosmopolitan build
  • ✅ Code quality checks
  • ✅ Security scans
  • ✅ Documentation validation
  • ✅ Coverage reports

Deployment Options

1. Binary

./webdav_server -p 8080 --db /var/lib/webdav/data.db

2. Docker

docker-compose up -d

3. Systemd Service

[Unit]
Description=WebDAV Server
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/webdav_server -p 8080 --db /var/lib/webdav/data.db
Restart=always

[Install]
WantedBy=multi-user.target

4. Reverse Proxy (HTTPS)

server {
    listen 443 ssl;
    server_name webdav.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Security Considerations

✅ Implemented

  • Path traversal prevention
  • Request size limits
  • Authentication support
  • Input validation
  • Memory safety

⚠️ Known Limitations

  • No HTTPS (use reverse proxy)
  • No automatic lock expiration
  • No built-in rate limiting
  • No audit logging

Recommended Deployment

  1. Use HTTPS via reverse proxy
  2. Enable firewall rules
  3. Use strong authentication
  4. Regular database backups
  5. Monitor disk space

Performance Tuning

Database Optimization

  • Use SSD for database storage
  • Regular vacuuming (UnQLite auto-compaction)
  • Separate disk for database and logs

Memory Management

  • Monitor with valgrind
  • Adjust buffer sizes in code if needed
  • Use :mem: for testing only

Concurrent Access

  • Current design: Thread-per-request
  • Suitable for: 10-50 concurrent clients
  • For higher load: Consider connection pooling

Troubleshooting

Server won't start

# Check port availability
netstat -tlnp | grep 8080

# Check permissions
ls -l webdav.db

# Run in foreground
./webdav_server -p 8080 --db test.db

Database issues

# Check database integrity
# UnQLite is transactional, but you can verify:
./webdav_server --test

# Backup database
cp webdav.db webdav.db.backup

# Start fresh
rm webdav.db

Performance issues

# Monitor with top/htop
top -p $(pgrep webdav_server)

# Check memory usage
valgrind --tool=massif ./webdav_server ...

# Profile with strace
strace -c ./webdav_server --test

Future Enhancements

Planned

  • HTTPS built-in support
  • Web interface for management
  • Export/import functionality
  • Real-time sync support
  • File versioning
  • Activity logging
  • Rate limiting
  • Compression support

Community Contributions

See CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE file for details.

Contact & Support

  • Issues: GitHub Issues
  • Documentation: README.md
  • Contributing: CONTRIBUTING.md
  • Security: Please report privately

Acknowledgments

  • UnQLite: Embedded database by Symisc Systems
  • Cosmopolitan: Cross-platform C library by Justine Tunney
  • Apache litmus: WebDAV compliance test suite

Status: ✅ Production Ready Version: 1.0.0 Last Updated: 2025-12-21