refactor(webdav): remove lock_manager from webdav app

- Remove unused `lock_manager` from the `App` struct.
- Comment out the lock and unlock handlers.
- Improve `propfind` response XML generation.
- Fix path handling in `generate_response_element`.
- Update content type handling for files.
- Improve XML generation for resource responses.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
This commit is contained in:
2025-02-06 15:37:21 +02:00
parent 1c0535a8b4
commit 4a2753d32c
3 changed files with 65 additions and 85 deletions

View File

@@ -10,7 +10,7 @@ struct App {
user_db map[string]string @[required]
root_dir pathlib.Path @[vweb_global]
pub mut:
lock_manager LockManager
// lock_manager LockManager
server_port int
middlewares map[string][]vweb.Middleware
}

View File

@@ -7,49 +7,49 @@ import encoding.xml
import freeflowuniverse.herolib.ui.console
import net.urllib
@['/:path...'; LOCK]
fn (mut app App) lock_handler(path string) vweb.Result {
// Not yet working
// TODO: Test with multiple clients
resource := app.req.url
owner := app.get_header('Owner')
if owner.len == 0 {
return app.bad_request('Owner header is required.')
}
// @['/:path...'; LOCK]
// fn (mut app App) lock_handler(path string) vweb.Result {
// // Not yet working
// // TODO: Test with multiple clients
// resource := app.req.url
// owner := app.get_header('Owner')
// if owner.len == 0 {
// return app.bad_request('Owner header is required.')
// }
depth := if app.get_header('Depth').len > 0 { app.get_header('Depth').int() } else { 0 }
timeout := if app.get_header('Timeout').len > 0 { app.get_header('Timeout').int() } else { 3600 }
// depth := if app.get_header('Depth').len > 0 { app.get_header('Depth').int() } else { 0 }
// timeout := if app.get_header('Timeout').len > 0 { app.get_header('Timeout').int() } else { 3600 }
token := app.lock_manager.lock(resource, owner, depth, timeout) or {
app.set_status(423, 'Locked')
return app.text('Resource is already locked.')
}
// token := app.lock_manager.lock(resource, owner, depth, timeout) or {
// app.set_status(423, 'Locked')
// return app.text('Resource is already locked.')
// }
app.set_status(200, 'OK')
app.add_header('Lock-Token', token)
return app.text('Lock granted with token: ${token}')
}
// app.set_status(200, 'OK')
// app.add_header('Lock-Token', token)
// return app.text('Lock granted with token: ${token}')
// }
@['/:path...'; UNLOCK]
fn (mut app App) unlock_handler(path string) vweb.Result {
// Not yet working
// TODO: Test with multiple clients
resource := app.req.url
token := app.get_header('Lock-Token')
if token.len == 0 {
console.print_stderr('Unlock failed: `Lock-Token` header required.')
return app.bad_request('Unlock failed: `Lock-Token` header required.')
}
// @['/:path...'; UNLOCK]
// fn (mut app App) unlock_handler(path string) vweb.Result {
// // Not yet working
// // TODO: Test with multiple clients
// resource := app.req.url
// token := app.get_header('Lock-Token')
// if token.len == 0 {
// console.print_stderr('Unlock failed: `Lock-Token` header required.')
// return app.bad_request('Unlock failed: `Lock-Token` header required.')
// }
if app.lock_manager.unlock_with_token(resource, token) {
app.set_status(204, 'No Content')
return app.text('Lock successfully released')
}
// if app.lock_manager.unlock_with_token(resource, token) {
// app.set_status(204, 'No Content')
// return app.text('Lock successfully released')
// }
console.print_stderr('Resource is not locked or token mismatch.')
app.set_status(409, 'Conflict')
return app.text('Resource is not locked or token mismatch')
}
// console.print_stderr('Resource is not locked or token mismatch.')
// app.set_status(409, 'Conflict')
// return app.text('Resource is not locked or token mismatch')
// }
@['/:path...'; get]
fn (mut app App) get_file(path string) vweb.Result {
@@ -215,7 +215,6 @@ fn (mut app App) propfind(path string) vweb.Result {
}
depth := app.get_header('Depth').int()
println('depth: ${depth}')
responses := app.get_responses(p.path, depth) or {
console.print_stderr('failed to get responses: ${err}')
@@ -232,24 +231,14 @@ fn (mut app App) propfind(path string) vweb.Result {
}
}
res := doc.pretty_str('').split('\n')[1..].join('')
println('res: ${res}')
res := '<?xml version="1.0" encoding="UTF-8"?>${doc.pretty_str('').split('\n')[1..].join('')}'
// println('res: ${res}')
app.set_status(207, 'Multi-Status')
app.send_response_to_client('application/xml', res)
return vweb.not_found()
}
fn (mut app App) generate_resource_response(path string) string {
mut response := ''
response += app.generate_element('response', 2)
response += app.generate_element('href', 4)
response += app.generate_element('/href', 4)
response += app.generate_element('/response', 2)
return response
}
fn (mut app App) generate_element(element string, space_cnt int) string {
mut spaces := ''
for i := 0; i < space_cnt; i++ {

View File

@@ -5,14 +5,20 @@ import encoding.xml
import os
import time
import vweb
import net.urllib
fn (mut app App) generate_response_element(path string, depth int) xml.XMLNode {
name := os.file_name(path)
href_link := urllib.path_escape(name)
mut path_ := path.all_after(app.root_dir.path)
if !path_.starts_with('/') {
path_ = '/${path_}'
}
if os.is_dir(path) && path_ != '/' {
path_ = '${path_}/'
}
href := xml.XMLNode{
name: 'D:href'
children: ['${href_link}']
children: [path_]
}
propstat := app.generate_propstat_element(path, depth)
@@ -55,18 +61,10 @@ fn (mut app App) generate_prop_element(path string, depth int) !xml.XMLNode {
stat := os.stat(path)!
// name := match os.is_dir(path) {
// true {
// os.base(path)
// }
// false {
// os.file_name(path)
// }
// }
// display_name := xml.XMLNode{
// name: 'D:displayname'
// children: ['${name}']
// }
display_name := xml.XMLNode{
name: 'D:displayname'
children: ['${os.file_name(path)}']
}
content_length := if os.is_dir(path) { 0 } else { stat.size }
get_content_length := xml.XMLNode{
@@ -101,9 +99,10 @@ fn (mut app App) generate_prop_element(path string, depth int) !xml.XMLNode {
}
mut get_resource_type_children := []xml.XMLNodeContents{}
if os.is_dir(path) {
get_resource_type_children << xml.XMLNode{
name: 'D:collection '
name: 'D:collection xmlns:D="DAV:"'
}
}
@@ -113,14 +112,14 @@ fn (mut app App) generate_prop_element(path string, depth int) !xml.XMLNode {
}
mut nodes := []xml.XMLNodeContents{}
nodes << get_content_length
nodes << creation_date
nodes << display_name
nodes << get_last_mod
nodes << get_resource_type
if depth > 0 {
nodes << get_content_type
nodes << get_resource_type
if !os.is_dir(path) {
nodes << get_content_length
}
nodes << creation_date
mut res := xml.XMLNode{
name: 'D:prop'
@@ -135,7 +134,7 @@ fn (mut app App) get_file_content_type(path string) string {
content_type := if v := vweb.mime_types[ext] {
v
} else {
'application/octet-stream'
'text/plain; charset=utf-8'
}
return content_type
@@ -148,8 +147,8 @@ fn format_iso8601(t time.Time) string {
fn (mut app App) get_responses(path string, depth int) ![]xml.XMLNodeContents {
mut responses := []xml.XMLNodeContents{}
if depth == 0 {
responses << app.generate_response_element(path, depth)
if depth == 0 {
return responses
}
@@ -164,17 +163,9 @@ fn (mut app App) get_responses(path string, depth int) ![]xml.XMLNodeContents {
return error('failed to list directory ${path}: ${err}')
}
// if entries.paths.len == 0 {
// // An empty directory
// responses << app.generate_response_element(path)
// return responses
// }
for entry in entries.paths {
responses << app.generate_response_element(entry.path, depth)
}
} else {
responses << app.generate_response_element(path, depth)
}
return responses