jrodjpl jrodjpl - 7 months ago 11
Python Question

Is there a way for mod_wsgi/Flask and mod_dav to coexist?

I'm working on a website that's basically a file repository for a bunch of data.

I need people to be able to traverse the directories and download files both via WebDAV and their browser (i.e. mod_autoindex).

This works fine using just mod_autoindex and mod_dav. But I wanted to use mod_wsgi/Flask to customize and serve the directory listing pages instead of the fairly inflexible mod_autoindex, using the Flask-AutoIndex plugin.

The problem is that this seems to then interfere with the DAV requests. I get a

The URL contains extraneous path components. The resource could not be identified.
errors when I try to connect with a DAV client.

Is there a way I can make mod_wsgi ignore all requests with WebDAV-specific headers so that they can be handled correctly by mod_dav?

EDIT:

Here's my Apache config:

LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
DavLockDB "/var/lib/urs_test/dav/DavLock"
LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias / /urs_test/webdav_info /usr/local/apache2/htdocs/urs_test/app.wsgi
WSGIDaemonProcess test processes=2 threads=15
WSGIProcessGroup test


<Directory /usr/local/apache2/htdocs/urs_test>
AuthType UrsOAuth2
require valid-user
Dav On
Options +ExecCGI
AddHandler cgi-script .cgi .pl
</Directory>


ANOTHER EDIT:

So I think I've figured out what's up here. It has to do with the WSGIScriptAlias tag, which is being appended to the request path.

A WebDAV request for
/urs_test/files
is modified to
/usr/local/apache2/htdocs/urs_test/app.wsgi/files
by the time it reaches mod_dav.

So I need to figure out a way to selectively apply that alias directive to certain HTTP methods (i.e. PROPFIND) and not to others (i.e. GET).

Answer

Came back to this a while later, and I've found something that appears to work.

Basically, I'm using mod_rewrite to redirect requests that I don't want mod_wsgi/Flask to handle.

So, if my Flask app is being served under /endpoint, and I want my WebDAV repo to be available under /endpoint/dav, my config is:

RewriteCond %{REQUEST_URI} ^/endpoint/dav
RewriteCond %{REQUEST_METHOD} ^(PROPFIND|OPTIONS|PROPPATCH)$
RewriteRule ^/endpoint/dav /local_path_to_dav_repo/$1 [L]

RewriteCond %{REQUEST_URI} ^/endpoint/dav
RewriteCond %{REQUEST_METHOD} =GET
RewriteCond /local_path_to_dav_repo/$1 !-d
RewriteRule ^/endpoint/dav(.*) /local_path_to_dav_repo/$1 [L]

WSGIScriptAlias /endpoint /my_wsgi_dir/flask.wsgi

<Directory /local_path_to_dav_repo>
Dav On
</Directory>

The first 3 lines grab any DAV-specific method (the read-only ones, for now) and redirect them to the local path of the DAV repo. Because mod_wsgi is only grabbing requests for the /endpoint URI, this request never reaches Flask and goes straight to mod_dav.

The next 4 lines grab any GET requests for specific files and redirect them to the specific location of that file in the local filesystem. Once again, this request doesn't reach Flask. From what I understand, it's faster to have Apache serve the file directly than to have Flask do it.

So the result is that only GET requests for directories in the DAV repo make it to mod_wsgi, so I can build a nice-looking directory index and serve it via Flask.

Comments