Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: Write so as to be able to add on to existing configuration #1

Open
VA1DER opened this issue Aug 14, 2023 · 20 comments
Open

Comments

@VA1DER
Copy link

VA1DER commented Aug 14, 2023

Thanks for this fantastic configuration! It was extremely helpful getting a nice WebDAV interface on my OpenWrt router.

The Wiki for OpenWrt has a /very/ basic configuration which requires a copy of webdav-js for each served folder. My intention is to update the wiki with an adaptation of your solution (with attribution). It has to, however, play nicely with other configurations since lighttpd is also serving up my router's UI.

In the short term, I was able to get it to play nicely by surrounding the WebDAV configuration with a $SERVER directive. I then added in some basic auth and proceeded with an adaptation of your config...

$SERVER["socket"] == "192.168.11.1:8080" {

  auth.backend = "plain"
  auth.backend.plain.userfile = "/etc/lighttpd/webdav.shadow"
  auth.require = (
    "/" => ("method" => "basic", "realm" => "disk", "require" => "valid-user")
  )
  auth.cache = ("max-age" => "3600")

  #Directory to be served over WebDAV
  server.document-root = "/mnt/trunk/"
  #Enable/disable read-only access
  webdav.is-readonly = "disable"

  ...

I wanted to suggest that your solution would be much more universal if it was designed as drop-in configuration to tack onto existing configurations by adding, say, a 50-weddav.conf file into /etc/lighttpd/conf.d and was written such that it complements existing setups. So it could be set to work with address/webdav/ and address/webdav/basic/. As is stands, it assumes it will be all that lighttp is doing.

In any case, thanks again for doing this. It has been a great help.

@Code-Otto
Copy link
Owner

Hello! You welcome, really glad this configuration sample was helpful in your neat router setup 😃

Modularizing the core webdav-related config for users to plug into their existing setups sounds like a great idea. I'll get to work on it and keep you updated
However I recall some issues while trying to get it to work under a subpath (like address/webdav/) which will require some further lighttpd config tricks, since webdav-js is unaware of the subpath /webdav/ in the URL not being part of the current directory path and includes it in its WebDAV queries to server

For now, I'll keep these as the first goals:

  • Modularize the webdav-js 'magic' into a drop-in config include
  • Separate the README.md guide in two sections: 'Integrating into an already set up lighttpd server' and 'Setting up lighttpd from scrath'

Then the tricky one:

  • Getting the web UI to work under user-chosen subpaths

As of adding this config to the OpenWrt wiki, it's pretty much welcome. I published this snippet here to hopefully be of help to others working out a very lightweight WebDAV server with a nice web UI but this repo is quite a lost spot nowhere in the internet. In the OpenWrt wiki it could sure get more visibility and help a lot more people

@Code-Otto
Copy link
Owner

Hello, a small update:
I got the serving of assets and basic indexes working under a subpath thanks to introducing some new tricks with mod_alias, however mod_webdav appears to handle file operations on its own not fully acknowledging the mod_alias aliases:
https://github.com/lighttpd/lighttpd1.4/blob/854503631ddcc1d6636dce8e11d46111ba5e8bed/src/mod_webdav.c#L5074-L5075
which is causing lots of trouble and I'm afraid doing the WebDAV URL remapping server side is a lost cause

As a brief, the problem is:
Let's say your document root is at /foo/bar/ and you enable WebDAV under the http://server/dav/ prefix.
If you GET a file at http://server/dav/myfile, the server will return you what's at /foo/bar/dav/myfile instead of /foo/bar/myfile, because the URL is /dav/myfile, after all
Lighttpd haves a neat module called mod_alias which lets you remap the document root for URL prefixes. So you can tell it: remap me URL /dav/ into directory /foo/bar/, please!
And now if you GET a file under http://server/dav/myfile, the server will return you what's at /foo/bar/myfile thanks to the aliasing magic
However, mod_webdav handles several WebDAV-specific HTTP methods on its own without taking mod_alias into consideration, so even if you cat now GET http://server/dav/myfile and receive what's at /foo/bar/myfile, if you use a WebDAV method like PROPFIND http://server/dav/myfile it will unfortunately still try to reach /foo/bar/dav/myfile

As lighttpd and mod_webdav seem unreliable at doing this, only left option (beyond source patching, of course) is setting up the path remapping at a lower level, like at filesystem level via symlinks.
I'll keep working on this and document the procedure on how to set that up

@Code-Otto
Copy link
Owner

Sorry for the big delay, been dealing with some life stuff lately. @VA1DER are you still checking on here and interested?
Symlinks aren't an option either as for some safety reasons related to the inner workings of WebDAV the lighttpd developers have chosen mod_webdav not to follow them

So last resort... bind mounts! Things gets uglier 😆

@gstrauss
Copy link

gstrauss commented Oct 2, 2023

@Code-Otto Hi! I am the lighttpd developer who wrote the current lighttpd mod_webdav.

If the client side is unable to handle a WebDAV folder root with URL path /dav/ (as in https://example.org/dav/) then I think the quickest solution may be to symlink /foo/bar/dav -> . in the /foo/bar/ directory. (Or to symlink /var/www/dav to /foo/bar if /var/www/ is the document root for the website.)

Using lighttpd mod_alias to remap the URL path to the filesystem does not work well with WebDAV methods COPY or MOVE which include the "Destination" request header, which is not modified by other lighttpd modules, such as mod_alias.

Instead of using lighttpd mod_alias, you might try setting in the lighttpd config:
$HTTP[url] =^ "/dav/" { server.document-root = "/foo/bar" }
The lighttpd.conf probably already has a condition for /dav/ with webdav.activate = "enable" and changing the document root there is the way to go. Note that lighttpd will still look for "/foo/bar/dav/" since the document root is the document root and the URL is still /dav/.... Still, this solution gives you a different folder for WebDAV, separate from the top-level document-root.


Alternatively, you could enable lighttpd mod_webdav in the URL root /, and then use mod_alias to map lighttpd-webdavjs-conf assets elsewhere (top-level index.html and /dav-assets/ webdav-min.js style-min.css). Or you could tell lighttpd mod_webdav to keep those assets read-only.

Lots of options. Feel free to ask me questions. I may not understand exactly what you're trying to do.

RFE: add lighttpd mod_deflate to reduce the size of files sent to clients.

@gstrauss
Copy link

gstrauss commented Oct 2, 2023

Why is this in the sample config?

#Workaround for mod_webdav returning 403 on MOVE
#Haves the unfortunate side effect of moving always clobbering existing files
server.modules += ("mod_setenv")
$HTTP["request-method"] == "MOVE" {
	setenv.set-request-header = ("Overwrite" => "")
}

The default is Overwrite: t if the request header is not provided. If provided, lighttpd expects Overwrite: t or Overwrite: f or Overwrite: T or Overwrite: F or else returns 400 Bad Request. What is happening that you are getting 403 on MOVE? You should probably get the same behavior from COPY, too. There is something else going on with the request if you are getting 403 Forbidden.

@gstrauss
Copy link

gstrauss commented Oct 2, 2023

@Code-Otto
(sorry for getting off-topic; lmk if you want me to open a separate issue for discussion)
Where did you get the list in the sample config for mimetype.assign?

.apk is better known as application/vnd.android.package-archive, not application/zip.

I ask because lighttpd 1.4.71 and later provide a default for mimetype.assign if one is not provided, and I aim for the defaults to have a reasonable (not unabridged) set of common mime types for common web resources, including multimedia types for audio and video.

How common are the following multimedia types? These are not currently part of the defaults provided by lighttpd, but I might be convinced to add them:

        ".asf"          =>      "video/x-ms-asf",
        ".asx"          =>      "video/x-ms-asf",
        ".dvi"          =>      "application/x-dvi",
        ".m3u"          =>      "audio/x-mpegurl",
        ".mkv"          =>      "video/x-matroska",
        ".mpg"          =>      "video/mpeg",
        ".ps"           =>      "application/postscript",
        ".swf"          =>      "application/x-shockwave-flash",
        ".wax"          =>      "audio/x-ms-wax",
        ".wma"          =>      "audio/x-ms-wma",
        ".wmv"          =>      "video/x-ms-wmv",

@gstrauss
Copy link

gstrauss commented Oct 2, 2023

FYI: I submitted a PR to upstream to add a lighttpd example: dom111/webdav-js#130

In the PR, instead of playing tricks with mod_dirlisting or mod_indexfile, I wrote a little lua script to overlay and provide the page to use webdav-js to generate the index for WebDAV collections.

@Code-Otto
Copy link
Owner

Hello @gstrauss! Nice to have you around 😃
Thanks for all your insights into possible solutions, this will be extremely helpful

I've not yet published the configuration drop-in I've been working on so it should be hard for you to understand what we are trying to achieve. Let's solve it... 😉

# Warning: This configuration file is a work in progress and is completely broken!
----------------------------------------------------------------------------------

#Lighttpd WebDAV + webdav-js quickstart config
#This configuration include file is intended for integrating a WebDAV server
#into an already setup lighttpd instance.

server.modules += (
	"mod_alias",
	"mod_webdav",
	"mod_rewrite",
	"mod_setenv"
)

### WebDAV configuration ###
#==========================#

#URL prefix to offer WebDAV access under
#For example, use "/dav" for accessing WebDAV under http://hostname/dav/
var.webdav-prefix = "/dav"

#Directory with the WebDAV trampoline
#This directory should contain a directory named like the WebDAV URL prefix with
#a bind mount (or symlink????) to the desired WebDAV server root directory
var.webdav-document-root = "/path/to/my/stash/"
#Please check this issue as for why this is needed:
#https://github.com/Code-Otto/lighttpd-webdavjs-conf/issues/1#issuecomment-1685316445

#Directory containing the dav-assets subdirectory with webdav-js assets
#May be any path outside the WebDAV-served directory
var.index-assets-dir = "/path/to/webav-js/"

$HTTP["url"] =~ "^" + webdav-prefix + "/" {

#Enable/disable read-only access
webdav.is-readonly = "disable"

#URL prefix to serve plain file indexes over
var.plainindex-prefix = "/basic/"
#Path where mod_webdav can store a temp file
webdav.sqlite-db-name = "/tmp/webdav_lock.db"

################################################
# You're all set configuring at this file now! #
################################################
#Dragons be here from this line on

server.document-root := webdav-document-root

dir-listing.activate = "enable"
dir-listing.encoding = "utf-8"
dir-listing.hide-dotfiles = "disable"
webdav.activate = "disable"

$HTTP["url"] !~ "^" + webdav-prefix + plainindex-prefix {
	webdav.activate = "enable"
	$HTTP["request-method"] == "GET" {
		url.rewrite-once = ( "\/$" => webdav-prefix + "/dav-assets/index.html" )
		$HTTP["url"] =~ "^" + webdav-prefix + "\/dav-assets\/" {
			dir-listing.activate := "disable"
		}
	}
}

#Workaround for mod_webdav returning 403 on MOVE
#Haves the unfortunate side effect of moving always clobbering existing files
$HTTP["request-method"] == "MOVE" {
	setenv.set-request-header = ("Overwrite" => "")
}

}

What we were trying to work out is:

  • Drop-in configuration file you can include into an existing Lighttpd config file (For example, VA1DER here wants to sneak in a WebDAV server into their OpenWrt router's lighttpd instance which is already set up by the distro maintainers for other tasks like serving the router config panels)
  • Runs non-intrusively below a subpath
  • Easy to set up by just editing a few variables:
    • The subpath WebDAV should be served under (IE, /dav/)
    • The directory to serve over WebDAV (IE, /path/to/my/files/, preferably in a manner that does not require a /path/to/my/files/dav/ directory to exist. In the current state of the configuration provided above I've given up on this)
    • The directory containing webdav-js assets, which should be served readonly as static files without any WebDAV access (IE, /path/to/webav-js/)

However I've been unsuccessful at getting mod_webdav to map /dav/ URLS to / as described in the issue above #1 (comment)

Instead of using lighttpd mod_alias, you might try setting in the lighttpd config:
$HTTP[url] =^ "/dav/" { server.document-root = "/foo/bar" }
The lighttpd.conf probably already has a condition for /dav/ with webdav.activate = "enable" and changing the document root there is the way to go

Yes, thanks for the confirmation. This is the approach I've been heading for.

If the client side is unable to handle a WebDAV folder root with URL path /dav/ (as in https://example.org/dav/) then I think the quickest solution may be to symlink /foo/bar/dav -> . in the /foo/bar/ directory.

That was my original idea, however this piece of information about symlinks in the mod_webdav wiki documentation suggested they won't be followed for security reasons and discourages their use within a WebDAV document root, hence why I discarded the option and considered bind mounts (albeit an even uglier hack): https://redmine.lighttpd.net/projects/lighttpd/repository/14/revisions/6bf0b577876b3e6d5e84239c8c134d436ed29b1b
So this means that solution will actually work despite the wiki claims?

RFE: add lighttpd mod_deflate to reduce the size of files sent to clients.

Noted, thanks! Will add it

Why is this in the sample config?

That's an issue I came across only alongside the webdav-js client, may probably be an issue on its side.
I don't recall the exact details anymore but should be quick to reproduce again by setting up my config file (The one at the repo) and removing the workaround

(sorry for getting off-topic; lmk if you want me to open a separate issue for discussion)

It's fine 😃

Where did you get the list in the sample config for mimetype.assign?

It's based off Debian/Ubuntu defaults with some custom additions of mine

How common are the following multimedia types? These are not currently part of the defaults provided by lighttpd, but I might be convinced to add them:

Most these are obsolete formats or things that do not anyways benefit from rich previews under any browser. However .mkv is a pretty popular and widespread any-codec media container which I've found out some smart TVs refuse to play unless provided with the correct mimetype, so could you add just one to lighttpd defaults, this should be it in my opinion.

In the PR, instead of playing tricks with mod_dirlisting or mod_indexfile, I wrote a little lua script to overlay and provide the page to use webdav-js to generate the index for WebDAV collections.

Thanks a lot! I'll check out your approach there

@gstrauss
Copy link

gstrauss commented Oct 7, 2023

lighttpd 1.4.72 was just released this evening; I did not get your response until now. :/ I may consider .mkv for the future.

I made a mistake above and need to correct myself regarding symlinking dav/ in the document root. Recent discussions around a top-level symlink for the dav root are here: https://redmine.lighttpd.net/boards/2/topics/11067 and there is a commit that is part of lighttpd 1.4.72: https://redmine.lighttpd.net/projects/lighttpd/repository/14/revisions/9673dab01fa384e48dd1a25ab463c26cb2cf1ef1 It requires both
webdav.opts += ("unsafe-propfind-follow-symlink" => "enable")
webdav.is-readonly = "enable"
so will not work when you want the dav tree to be writable (not read-only).

The directory to serve over WebDAV (IE, /path/to/my/files/, preferably in a manner that does not require a /path/to/my/files/dav/ directory to exist. In the current state of the configuration provided above I've given up on this)

FYI: lighttpd.conf allows include files and include_shell. If you were to put a file in a Debian-based /etc/lighttpd/conf-enabled/99-webdav.conf and inside that had include_shell "/path/to/setup-script.sh", then setup-script.sh could mkdir -p /path/to/my/files/dav/ and set appropriate permissions at lighttpd startup. lighttpd mod_webdav expects that target WebDAV collection root to exist and be appropriate permissioned, where the end-user chooses what constitutes appropriate permissions.

However I've been unsuccessful at getting mod_webdav to map /dav/ URLS to / as described in the issue above #1 (comment)

I do not understand. You stated above that you wanted the dav to be in a subpath ("/dav") ("Runs non-intrusively below a subpath") and at the same time are trying to map "/dav/" to "/"? This combination does not make sense to me. I can only assume it relates to your attempts to use lighttpd mod_alias to map webdav-js files elsewhere.

However, mod_webdav handles several WebDAV-specific HTTP methods on its own without taking mod_alias into consideration, so even if you cat now GET http://server/dav/myfile and receive what's at /foo/bar/myfile, if you use a WebDAV method like PROPFIND http://server/dav/myfile it will unfortunately still try to reach /foo/bar/dav/myfile

lighttpd mod_webdav expects that the filesystem tree is a single tree for the top-level dav collection. For example, a WebDAV MOVE command would not have coherent results if you MOVE /dav/foo to /dav/bar, but also had mod_alias map /dav/foo/other/ to some place outside the tree. The files under /dav/foo/other would not end up moving to the MOVE target /dav/bar/other. (You might say that this does not affect your specific use, but I am explaining why lighttpd mod_webdav expects to manage a single filesystem tree for coherent results.) The reason the GET works in your case using mod_alias is that lighttpd mod_webdav allows other modules to handle GET, so that GET might result in lighttpd mod_fastcgi running the target instead of returning the file contents, based on whether or not Translate: t or Translate: f was provided in the request headers. (That is a Microsoft-ism that may be supported in a future lighttpd mod_webdav release.) The short answer is that you should not use lighttpd mod_alias with paths under lighttpd mod_webdav tree. I'll add a note to the documentation to call that out.

lighttpd mod_magnet with a short custom lua script -- as I mocked up (in the PR I linked above) -- is a clean way IMHO to overlay webdav-js in the way that you want, without trying to play tricks with lighttpd mod_indexfile or lighttpd mod_dirlisting, and at the same time not affecting the rest of the site that is not under the /dav/ subpath.

@gstrauss
Copy link

gstrauss commented Oct 7, 2023

This might be a useful template (untested by me) for what you want to achieve, using the lua script in PR dom111/webdav-js#130

server.modules += (
  "mod_alias",
  "mod_magnet", 
  "mod_webdav", 
)

# TODO: modify to set webdav-js git repository checkout location
var.webdav_js = "/var/www/webdav-js"
alias.url += ("/webdav-js" => var.webdav_js)

# TODO: if WebDAV files are in a separate location; not under document root
var.webdav_root = "/path/to/my/files/dav"

$HTTP["url"] =~ "/dav(?:/|$)" {
  alias.url = ("/dav" => var.webdav_root)

  webdav.activate = "enable"
  webdav.is-readonly = "disable"
  webdav.opts += ("propfind-depth-infinity" => "enable")
  # TODO: uncomment to enable WebDAV LOCK,UNLOCK and WebDAV PROPPATCH
  # Prefer to change path to a persistent location,
  # e.g. under /var/cache/lighttpd/webdav
  #webdav.sqlite-db-name = "/var/tmp/webdav.example.com.db"
  
  magnet.attract-physical-path-to = (
    var.webdav_js + "/examples/lighttpd/index.lua"
  )
} 

You could add include_shell to a script which sets up "/path/to/my/files/dav" with mkdir -p and sets appropriate permissions, and also creates directory for webdav.sqlite-db-name. (lighttpd mod_webdav will create the sqlite database, but the directory needs to exist.)

@Code-Otto
Copy link
Owner

I do not understand. You stated above that you wanted the dav to be in a subpath ("/dav") ("Runs non-intrusively below a subpath") and at the same time are trying to map "/dav/" to "/"? This combination does not make sense to me. I can only assume it relates to your attempts to use lighttpd mod_alias to map webdav-js files elsewhere.

I explained myself quite poorly there indeed, sorry:
I'd like the WebDAV server root to be served under a http(s)://example.com/dav/ subpath of the URL, where should the document root be /my/files/, both WebDAV and basic HTTP operations to URL http(s)://example.com/dav/file.txt would affect the file at /my/files/file.txt and not /my/files/dav/file.txt

For example let's say I'd like my personal Pi-powered cloud running many different web services at home to serve the contents of a external disk I've plugged at it. The disk is automounted at a fixed path at system boot, let's say at /media/long/ugly/path/to/disk/. Sometimes I may also want to take the disk out for working on other affairs directly with my computer.
Having to move all the contents at the root of my disk (/media/long/ugly/path/to/disk/*) to /media/long/ugly/path/to/disk/dav/ everytime I want to serve its contents would be a big inconvenience.

lighttpd mod_webdav expects that the filesystem tree is a single tree for the top-level dav collection. For example, a WebDAV MOVE command would not have coherent results if you MOVE /dav/foo to /dav/bar, but also had mod_alias map /dav/foo/other/ to some place outside the tree. The files under /dav/foo/other would not end up moving to the MOVE target /dav/bar/other. (You might say that this does not affect your specific use, but I am explaining why lighttpd mod_webdav expects to manage a single filesystem tree for coherent results.)

This seems reasonable, I understand mod_alias offers much more flexibility than what mod_webdav can handle hence why the limitations.
Would it be possible for mod_webdav to analyze the aliases at mod_alias and support the workable-out use cases like the one we're after while erroring out when impossible remappings under the WebDAV root filesystem are done? Sounds like a complex issue given how aliases can be dynamically changed with conditions at the config file. The analysis would have to be performed for each request. Curious about what you think anyways 😉

lighttpd mod_magnet with a short custom lua script -- as I mocked up (in the PR I linked above) -- is a clean way IMHO to overlay webdav-js in the way that you want, without trying to play tricks with lighttpd mod_indexfile or lighttpd mod_dirlisting, and at the same time not affecting the rest of the site that is not under the /dav/ subpath.

I've just taken a look at it and its definitely such a more elegant solution. Didn't know about mod_magnet but it looks extremely powerful so will look into learning more about it, thanks for the pointer.

@gstrauss
Copy link

gstrauss commented Oct 7, 2023

Curious about what you think anyways

Hard no. If you have a large tree containing 100,000 files, you're asking lighttpd to look at every single one to see if something else mapped things differently. Hard no. Handling symlinks is similar. unix-style symlinks are not part of the WebDAV standard. lighttpd does not analyze those 100,000 files to see if any is a symlink, and if it is a relative symlink, and then does not update that symlink if it is a relative symlink and the symlink is under a tree that has COPY or MOVE applied.

lighttpd modules are generally independent of one another, since the use of each module is optional. One could also write a custom lighttpd module, and lighttpd mod_webdav would not magically know what that custom module does.

I'd like the WebDAV server root to be served under a http(s)://example.com/dav/ subpath of the URL, where should the document root be /my/files/, both WebDAV and basic HTTP operations to URL http(s)://example.com/dav/file.txt would affect the file at /my/files/file.txt and not /my/files/dav/file.txt

Untested, but as posted above, I think this might work:

var.webdav_root = "/path/to/my/files/dav"

$HTTP["url"] =~ "^/dav(?:/|$)" {
  alias.url = ("/dav" => var.webdav_root)
  ...
}

That should work with a read-only WebDAV root.
It might not work for a modifiable WebDAV root. In that case, the paths could be trivially remapped by adding a couple lines of lua near the top of examples/lighttpd/index.lua
(Specifically, test COPY and MOVE with "Destination" request header, which also needs to be remapped in filesystem, and which mod_alias does not know about)

@gstrauss
Copy link

gstrauss commented Oct 7, 2023

FYI: I took a quick look in the lighttpd mod_webdav code and it looks like lighttpd mod_webdav will handle using mod_alias to map the WebDAV root of a writable collection, e.g. with alias.url = ("/dav" => var.webdav_root)

Please test and report what you find.

@gstrauss
Copy link

gstrauss commented Oct 7, 2023

BTW, I think one of your original misunderstandings may have been this:
$HTTP["url"] =~ "^" + webdav-prefix + "/" {
instead of this

$HTTP["url"] =~ "^" + webdav-prefix + "(?:/|$)" {
  alias.url = (var.webdav-prefix => var.webdav_root)
...
}

@Code-Otto
Copy link
Owner

Thanks for all the insights, now it's time I do my homework 😄
Will get back to you with the results

@gstrauss
Copy link

gstrauss commented Oct 8, 2023

This appears to work fine: (alternative to the PR using mod_magnet, which also works)

server.modules += ( "mod_alias", "mod_webdav" )
$HTTP["url"] =~ "^/dav(?:/|$)" {
  index-file.names = ("/index.webdav-js.html")
  alias.url = ("/dav" => "/path/to/my/files")
  webdav.activate = "enable"
  webdav.is-readonly = "disable"
  webdav.opts += ("propfind-depth-infinity" => "enable")
}

with /index.webdav-js.html containing:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/dom111/webdav-js/assets/css/style-min.css">
</head>
<body>
<script src="https://cdn.jsdelivr.net/gh/dom111/webdav-js/src/webdav-min.js"></script>
</body>
</html>

If you had to do that without using regular expressions, you could instead:

server.modules += ( "mod_redirect", "mod_alias", "mod_webdav" )
$HTTP["url"] =^ "/dav/" {
  index-file.names = ("/index.webdav-js.html")
  alias.url = ("/dav" => "/path/to/my/files")
  webdav.activate = "enable"
  webdav.is-readonly = "disable"
  webdav.opts += ("propfind-depth-infinity" => "enable")
}
else $HTTP["url"] == "/dav" {
  url.redirect = ("" => "/dav/")
  url.redirect-code = 308
}

The target "/path/to/my/files" still needs to exist and be properly permissioned.

lighttpd-git pushed a commit to lighttpd/lighttpd1.4 that referenced this issue Oct 21, 2023
@Code-Otto
Copy link
Owner

Hey @gstrauss, I'm getting hold of mod_magnet and it seems to expose enough lighttpd wizardry internals for me to eventually achieve the goal from this issue 😄

Currently writing a Lua script to handle the physical path as I please, and two questions arised (hope you're fine with me asking around here):

  • Is there any way I can read variables from my config file (like var.webdav-prefix) from the Lua script?
    currently I have to duplicate their definitions both at the config file and the Lua script
  • What's the difference between lighty.r.req_attr["physical.doc-root"] and lighty.r.req_attr["physical.basedir"]?
    in the test requests I've done so far both seem to be always equal

@Code-Otto
Copy link
Owner

Code-Otto commented Oct 22, 2023

I came across a showstopper unfortunately :c

From within my Lighttpd conf file I call the Lua script with:
magnet.attract-physical-path-to = ("./lighttpd-webdavjs.lua")
And with the Lua script just containing:

local method = lighty.env["request.method"]
print("Method is: " .. method)
return 0

I've noticed WebDAV HTTP methods cannot be handled with mod_magnet. Here's a log of me doing some WebDAV operations with webdav-js:

connections.c.800) fd: 6 request-len: 506\nGET /dav/ HTTP/1.1\r\nHost: localhost:8080\r\n\r\n
mod_magnet.c.287) (lua-print) Method is: GET
connections.c.800) fd: 6 request-len: 412\nHEAD /dav/ HTTP/1.1\r\nHost: localhost:8080\r\nReferer: http://localhost:8080/dav/\r\n\r\n
mod_magnet.c.287) (lua-print) Method is: HEAD
connections.c.800) fd: 6 request-len: 457\nPROPFIND /dav/ HTTP/1.1\r\nHost: localhost:8080\r\nReferer: http://localhost:8080/dav/\r\nDepth: 1\r\nOrigin: http://localhost:8080\r\n\r\n
connections.c.800) fd: 6 request-len: 451\nMKCOL /dav/newdir/ HTTP/1.1\r\nHost: localhost:8080\r\nReferer: http://localhost:8080/dav/\r\nOrigin: http://localhost:8080\r\n\r\n
connections.c.800) fd: 6 request-len: 518\nMOVE /dav/image2.gif HTTP/1.1\r\nHost: localhost:8080\r\nReferer: http://localhost:8080/dav/\r\nDestination: http://localhost:8080/dav/image3.gif\r\nOverwrite: F\r\nOrigin: http://localhost:8080\r\n\r\n
connections.c.800) fd: 6 request-len: 422\nHEAD /dav/image3.gif HTTP/1.1\r\nHost: localhost:8080\r\nReferer: http://localhost:8080/dav/\r\n\r\n
mod_magnet.c.287) (lua-print) Method is: HEAD
connections.c.800) fd: 6 request-len: 446\nGET /dav/image3.gif HTTP/1.1\r\nHost: localhost:8080\r\nReferer: http://localhost:8080/dav/\r\n\r\n
mod_magnet.c.287) (lua-print) Method is: GET

Notice how the Lua code is not executing for PROPFIND, MKCOL or MOVE requests, the ones I need to mess with the more.
Have also tried attract-raw-url-to instead of attract-physical-path-to without any luck

(tested both with Lighty 1.4.59 and a freshly compiled 1.4.72)

@gstrauss
Copy link

  • Is there any way I can read variables from my config file (like var.webdav-prefix) from the Lua script?
    currently I have to duplicate their definitions both at the config file and the Lua script

No. lighttpd config file parsing is isolated from everything else in lighttpd.

However, you can use mod_setenv and configure lighttpd.conf to set an environment variable using your var.webdav-prefix value that is visible from the lua environment. Accessing an environment variable in mod_magnet lua script does trigger mod_magnet environment generation for every request, which is a bit of extra work in lighttpd and can be avoided if you do not need to do it. (It is an optimization to avoid it unless needed) However, webdav filesystem actions are much more work and so you probably won't notice the slight additional overhead.

Recommendation:
magnet.attract-physical-path-to = ("./lighttpd-webdavjs.lua")
I recommend using absolute paths rather than relative paths (above).

  • What's the difference between lighty.r.req_attr["physical.doc-root"] and lighty.r.req_attr["physical.basedir"]?
    in the test requests I've done so far both seem to be always equal

The document root is the original document root, e.g. for the virtual host. basedir can change depending on mod_alias, mod_userdir, and others. As you noticed, if basedir is not changed by another module, it matches doc-root.

I came across a showstopper unfortunately :c

No, not a showstopper in lighttpd. You must be doing something incorrectly.

Here's my hunch based on the limited information you have provided: lighttpd module load order matters, as that is the order that modules are given the change to handle requests (for a given module-registered lighttpd hook in request handling). "mod_magnet" should be listed in server.modules before "mod_webdav" if you want mod_magnet to get a chance to modify the request before mod_webdav handles the request.

@Code-Otto
Copy link
Owner

However, you can use mod_setenv and configure lighttpd.conf to set an environment variable using your var.webdav-prefix value that is visible from the lua environment. Accessing an environment variable in mod_magnet lua script does trigger mod_magnet environment generation for every request, which is a bit of extra work in lighttpd and can be avoided if you do not need to do it.

Understood, I'll live without it for now then.

Recommendation:
magnet.attract-physical-path-to = ("./lighttpd-webdavjs.lua")
I recommend using absolute paths rather than relative paths (above).

Oh yes, I've already found out myself why that's a bad idea 😅 thanks for pointing out

Here's my hunch based on the limited information you have provided: lighttpd module load order matters

Hrrrrmmmmm I think you quite caught me! Changed the modules order and the script is working as desired, thank you!
It would be nice to leave a warning line about this around the mod_magnet wiki page so unwary readers like me don't get confused when stumbling upon this behavior

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants