Sat, 24 Jan 2026 13:56:19 +0100
integrate wsgidav into test suite
| test/Makefile | file | annotate | diff | comparison | revisions | |
| test/main.c | file | annotate | diff | comparison | revisions | |
| test/webdav.c | file | annotate | diff | comparison | revisions | |
| test/webdav.h | file | annotate | diff | comparison | revisions | |
| test/webdav_resource.c | file | annotate | diff | comparison | revisions | |
| test/webdav_resource.h | file | annotate | diff | comparison | revisions | |
| test/wsgidav.c | file | annotate | diff | comparison | revisions | |
| test/wsgidav.h | file | annotate | diff | comparison | revisions | |
| test/wsgidav/testrepo/hello.txt | file | annotate | diff | comparison | revisions | |
| test/wsgidav/wsgidav.yaml | file | annotate | diff | comparison | revisions |
--- a/test/Makefile Fri Jan 23 17:38:59 2026 +0100 +++ b/test/Makefile Sat Jan 24 13:56:19 2026 +0100 @@ -29,9 +29,12 @@ include ../config.mk TEST_SRC = main.c +TEST_SRC += wsgidav.c TEST_SRC += base64.c TEST_SRC += crypto.c TEST_SRC += utils.c +TEST_SRC += webdav.c +TEST_SRC += webdav_resource.c TEST_OBJ = $(TEST_SRC:%.c=../build/test/%$(OBJ_EXT))
--- a/test/main.c Fri Jan 23 17:38:59 2026 +0100 +++ b/test/main.c Sat Jan 24 13:56:19 2026 +0100 @@ -29,10 +29,15 @@ #include <stdio.h> #include <stdlib.h> +#include "wsgidav.h" + #include "base64.h" #include "crypto.h" #include "utils.h" +#include "webdav.h" +#include "webdav_resource.h" + #include <cx/test.h> int test_main(int argc, char **argv); @@ -47,11 +52,18 @@ } #endif -int test_main(int argc, char **argv) { - printf("libidav tests\n"); - printf("-------------\n\n"); +int test_main(int argc, char **argv) { + int dav_client_tests = wsgidav_is_available(); + if(!dav_client_tests) { + printf("wsgidav not available: skipping some libidav webdav tests\n"); + } else { + if(wsgidav_start()) { + printf("Error: wsgidav_start failed: skipping some libidav webdav tests\n"); + dav_client_tests = 0; + } + } - CxTestSuite* suite = cx_test_suite_new("libidav"); + CxTestSuite* suite = cx_test_suite_new("libidav basic"); cx_test_register(suite, test_util_base64decode); cx_test_register(suite, test_util_base64decode_len); @@ -70,9 +82,22 @@ cx_test_register(suite, test_util_path_normalize); cx_test_register(suite, test_util_parent_path); + CxTestSuite* suite_webdav = cx_test_suite_new("libidav webdav"); + test_webdav_init(); + if(dav_client_tests) { + cx_test_register(suite_webdav, test_dav_load_webdav); + } + cx_test_run_stdout(suite); cx_test_suite_free(suite); + cx_test_run_stdout(suite_webdav); + cx_test_suite_free(suite_webdav); + + if(dav_client_tests) { + wsgidav_stop(); + } + return 0; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/webdav.c Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,40 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "webdav.h" + +static DavContext *test_webdav_context; + +void test_webdav_init(void) { + test_webdav_context = dav_context_new(); +} + +DavSession* get_test_webdav_session(void) { + DavSession *sn = dav_session_new_auth(test_webdav_context, "http://localhost:8182/", "dav", "testdavutils"); + return sn; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/webdav.h Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,48 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_WEBDAV_H +#define TEST_WEBDAV_H + +#include <cx/test.h> +#include <libidav/webdav.h> + +#ifdef __cplusplus +extern "C" { +#endif + +void test_webdav_init(void); +DavSession* get_test_webdav_session(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_WEBDAV_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/webdav_resource.c Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "webdav.h" +#include "webdav_resource.h" + +CX_TEST(test_dav_load_webdav) { + CX_TEST_DO { + DavSession *sn = get_test_webdav_session(); + DavResource *res = dav_resource_new(sn, "/hello.txt"); + CX_TEST_ASSERT(res); + int ret = dav_load(res); + CX_TEST_ASSERT(ret == 0); + CX_TEST_ASSERT(res->contentlength > 0); + CX_TEST_ASSERT(res->creationdate > 0); + CX_TEST_ASSERT(res->lastmodified > 0); + CX_TEST_ASSERT(res->exists); + CX_TEST_ASSERT(res->contenttype); + CX_TEST_ASSERT(!res->iscollection); + CX_TEST_ASSERT(res->href); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/webdav_resource.h Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,46 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_WEBDAV_RESOURCE_H +#define TEST_WEBDAV_RESOURCE_H + +#include <cx/test.h> + +#ifdef __cplusplus +extern "C" { +#endif + +CX_TEST(test_dav_load_webdav); + + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_WEBDAV_RESOURCE_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/wsgidav.c Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,306 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "wsgidav.h" + +#include <stdio.h> +#include <stdlib.h> + +//ifndef _WIN32 + +#include <unistd.h> +#include <sys/fcntl.h> + +#include <spawn.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include <cx/string.h> +#include <cx/buffer.h> +#include <cx/streams.h> +#include <cx/printf.h> + + +// -------------------------- Process Utils -------------------------------- + +typedef struct { + pid_t pid; + int in; + int out; + int err; +} Process; + +static Process process_spawn(const char *exec, char **args) { + Process proc = { 0 }; + + int pin[2]; + int pout[2]; + int perr[2]; + + // child process stdin/stdout pipes + if(pipe(pin)) { + perror("pipe"); + return proc; + } + if(pipe(pout)) { + perror("pipe"); + close(pin[0]); + close(pin[1]); + } + if(pipe(perr)) { + perror("pipe"); + close(pin[0]); + close(pin[1]); + close(pout[0]); + close(pout[1]); + } + + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_init(&actions); + posix_spawn_file_actions_adddup2(&actions, pin[0], 0); + posix_spawn_file_actions_adddup2(&actions, pout[1], 1); + posix_spawn_file_actions_adddup2(&actions, perr[1], 2); + + // child environment variables + char *path = getenv("PATH"); + if(!path) { + path = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"; + } + + cxmutstr env_path = cx_asprintf("PATH=%s", path); + + char *env[10]; + env[0] = "LC_ALL=C"; + env[1] = env_path.ptr; + env[2] = NULL; // array must be null-terminated + + // execute posix_spawn to create a child process + pid_t child; + int ret = posix_spawn( + &child, + exec, + &actions, + NULL, // attributes + args, + env); + posix_spawn_file_actions_destroy(&actions); + + close(pin[0]); + close(pout[1]); + close(perr[1]); + + if(ret) { + // posix spawn failed + perror("posix_spawn"); + // close remaining pipe fds + close(pin[1]); + close(pout[0]); + close(perr[0]); + } else { + proc.pid = child; + proc.in = pin[1]; + proc.out = pout[0]; + proc.err = perr[0]; + } + + return proc; +} + +int process_close(Process *p) { + if(p->pid == 0) { + return -1; + } + close(p->in); + close(p->out); + int status = -1; + waitpid(p->pid, &status, 0); + return status; +} + +size_t process_read(void *buf, size_t size, size_t n, Process *p) { + ssize_t r = read(p->out, buf, size*n); + return r > 0 ? r : 0; +} + +size_t process_err_read(void *buf, size_t size, size_t n, Process *p) { + ssize_t r = read(p->err, buf, size*n); + return r > 0 ? r : 0; +} + +static cxmutstr read_str(Process *p, cx_read_func readf) { + if(p->pid == 0) { + return CX_NULLSTR; + } + CxBuffer buffer; + cxBufferInit(&buffer, NULL, NULL, 1024, CX_BUFFER_AUTO_EXTEND); + cx_stream_copy(p, &buffer, readf, (cx_write_func)cxBufferWrite); + cxBufferTerminate(&buffer); + return cx_mutstrn(buffer.space, buffer.size); +} + +cxmutstr process_read_string(Process *p) { + return read_str(p, (cx_read_func)process_read); +} + +cxmutstr process_err_read_string(Process *p) { + return read_str(p, (cx_read_func)process_err_read); +} + + +// ------------------------------ wsgidav exec ----------------------------- + +static char *wsgidav_exec_path; +static Process wsgidav_process; +static int runtest_root_dir = 0; + +int wsgidav_is_available(void) { + // check if the wsgidava binary is available + char *args[] = { + "which", + "wsgidav", + NULL + }; + Process p = process_spawn("/usr/bin/which", args); + if(p.pid == 0) { + return 0; + } + + cxmutstr path = process_read_string(&p); + int status = process_close(&p); + if(status == 0) { + wsgidav_exec_path = cx_strdup(cx_strtrim(path)).ptr; + } + + free(path.ptr); + + if(status != 0) { + return 0; + } + + // check if the wsgidav config file is available + struct stat s; + if(!stat("test/wsgidav/wsgidav.yaml", &s)) { + runtest_root_dir = 1; // dav root directory + } else { + if(!stat("../test/wsgidav/wsgidav.yaml", &s)) { + runtest_root_dir = 2; // build directory + } else { + fprintf(stderr, "Error: wsgidav found, but the config file wsgidav.yaml was not found\nTry running the tests from the dav root directory\n"); + return 0; + } + } + + if(runtest_root_dir == 1) { + if(!stat("build", &s)) { + if(!S_ISDIR(s.st_mode)) { + fprintf(stderr, "Error: build is not a directory: wsgidav disabled\n"); + return 0; + } + } else { + fprintf(stderr, "Error: build directory not found: wsgidav disabled\n"); + return 0; + } + } + + return 1; +} + +int wsgidav_start(void) { + if(!wsgidav_exec_path) { + return 1; // wsgidav_start called but wsgidav_is_available return 0 + } + + if(runtest_root_dir == 1) { + if(chdir("build")) { + perror("chdir"); + return 1; + } + } + + // delete previous testrepo directory + char *args1[] = { "rm", "-Rf", "testrepo", NULL }; + Process p_rm = process_spawn("/bin/rm", args1); + cxmutstr err = process_err_read_string(&p_rm); + if(process_close(&p_rm) != 0) { + cxmutstr s = cx_strtrim(err); + fprintf(stderr, "rm failed: %.*s\n", (int)s.length, s.ptr); + return 1; + } + free(err.ptr); + + // copy testrepo to the build directory + char *args2[] = { "cp", "-R", "../test/wsgidav/testrepo", "testrepo", NULL }; + Process p_cp = process_spawn("/bin/cp", args2); + err = process_err_read_string(&p_cp); + if(process_close(&p_cp) != 0) { + cxmutstr s = cx_strtrim(err); + fprintf(stderr, "cp failed: %.*s\n", (int)s.length, s.ptr); + return 1; + } + free(err.ptr); + + // start wsgidav + char *args3[] = { "wsgidav", "-c", "../test/wsgidav/wsgidav.yaml", NULL }; + wsgidav_process = process_spawn(wsgidav_exec_path, args3); + + // TODO: parse log or try to connect to localhost + sleep(1); + + return 0; +} + +int wsgidav_stop(void) { + if(wsgidav_process.pid == 0) { + return 0; + } + kill(wsgidav_process.pid, SIGKILL); + (void)process_close(&wsgidav_process); + //if(status > 2) { + // printf("wsgidav exit: %d\n", status); + //} + return 0; +} + +/* +#else + +int wsgidav_is_available(void) { + return 0; +} + +int wsgidav_start(void) { + return 1; +} + +int wsgidav_stop(void) { + return 1; +} + +#endif + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/wsgidav.h Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,46 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WSGIDAV_H +#define WSGIDAV_H + +#ifdef __cplusplus +extern "C" { +#endif + +int wsgidav_is_available(void); +int wsgidav_start(void); +int wsgidav_stop(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* WSGIDAV_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/wsgidav/testrepo/hello.txt Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,1 @@ +Hello World!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/wsgidav/wsgidav.yaml Sat Jan 24 13:56:19 2026 +0100 @@ -0,0 +1,360 @@ +# WsgiDAV configuration file +# +# 1. Rename this file to `wsgidav.yaml`. +# 2. Adjust settings as appropriate. +# 3. Run `wsgidav` from the same directory or pass file path with `--config` option. +# +# See https://wsgidav.readthedocs.io/en/latest/user_guide_configure.html +# +# ============================================================================ +# SERVER OPTIONS + +#: Run WsgiDAV inside this WSGI server. +#: Supported servers: +#: cheroot, ext-wsgiutils, gevent, gunicorn, paste, uvicorn, wsgiref +#: 'wsgiref' and 'ext_wsgiutils' are simple builtin servers that should *not* be +#: used in production. +#: All other servers must have been installed before, e.g. `pip install cheroot`. +#: (The binary MSI distribution already includes 'cheroot'.) +#: NOTE: Using 'gunicorn' with more than 1 worker can cause problems with the +#: in-memory and shelve-based lock storage as both are not safe for concurrent +#: access. (see issue #332) Instead, you can use 'gunicorn' with multiple `threads` +#: or try the 'redis' based lock storage (#186). +#: Default: 'cheroot', use the `--server` command line option to change this. + +server: cheroot + +#: Server specific arguments, passed to the server. For example cheroot: +#: https://cheroot.cherrypy.dev/en/latest/pkg/cheroot.wsgi.html#cheroot.wsgi.Server +# server_args: +# max: -1 +# numthreads: 10 +# request_queue_size: 5 +# shutdown_timeout: 5 +# timeout: 10 + +# Server hostname (default: localhost, use --host on command line) +host: 127.0.0.1 + +# Server port (default: 8080, use --port on command line) +port: 8182 + +# Transfer block size in bytes +block_size: 8192 + +#: Add the MS-Author-Via Response Header to OPTIONS command to allow editing +#: with Microsoft Office (default: true) +add_header_MS_Author_Via: true + +hotfixes: + #: Handle Microsoft's Win32LastModifiedTime property. + #: This is useful only in the case when you copy files from a Windows + #: client into a WebDAV share. Windows sends the "last modified" time of + #: the file in a Microsoft extended property called "Win32LastModifiedTime" + #: instead of the standard WebDAV property "getlastmodified". So without + #: this config option set to "True", the "last modified" time of the copied + #: file will be "now" instead of its original value. + #: The proper solution for dealing with the Windows WebDAV client is to use + #: a persistent property manager. This setting is merely a work-around. + #: NOTE: Works with Win10, can't work with Win7. Other versions untested. + emulate_win32_lastmod: false + #: Re-encode PATH_INFO using UTF-8 (falling back to ISO-8859-1). + #: This seems to be wrong, since per PEP 3333 PATH_INFO is always ISO-8859-1 + #: encoded (see https://www.python.org/dev/peps/pep-3333/#unicode-issues). + #: However it also seems to resolve errors when accessing resources with + #: Chinese characters, for example (see issue #73). + re_encode_path_info: true + #: Force unquoting of PATH_INFO. This should already be done by the WSGI + #: Framework, so this setting should only be used to fix unexpected problems + #: there (false fixes issue #8, true fixes issue #228). + unquote_path_info: false + #: Hotfix for WinXP / Vista: accept 'OPTIONS /' for a 'OPTIONS *' + #: (default: false) + treat_root_options_as_asterisk: false + + +# ---------------------------------------------------------------------------- +# SSL Support + +#: The certificate should match the servers hostname, so the bogus certs will +#: not work in all scenarios. +#: (Paths can be absolute or relative to this config file.) + +# ssl_certificate: 'wsgidav/server/sample_bogo_server.crt' +# ssl_private_key: 'wsgidav/server/sample_bogo_server.key' +# ssl_certificate_chain: null + +#: Cheroot server supports 'builtin' and 'pyopenssl' (default: 'builtin') +# ssl_adapter: 'pyopenssl' + +# ---------------------------------------------------------------------------- + +#: Modify to customize the WSGI application stack. +#: See here for an example how to add custom middlewares: +#: https://wsgidav.readthedocs.io/en/latest/user_guide_configure.html#middleware-stack +middleware_stack: + - wsgidav.mw.cors.Cors + # - wsgidav.mw.debug_filter.WsgiDavDebugFilter + - wsgidav.error_printer.ErrorPrinter + - wsgidav.http_authenticator.HTTPAuthenticator + # - wsgidav.mw.impersonator.Impersonator + - wsgidav.dir_browser.WsgiDavDirBrowser + - wsgidav.request_resolver.RequestResolver # this must be the last middleware item + +# ============================================================================== +# SHARES + +#: Application root, applied before provider mapping shares, e.g. +#: <mount_path>/<share_name>/<res_path> +#: Set this to the mount point (aka location) when WsgiDAV is running behind a +#: reverse proxy. +#: If set, the mount path must have a leading (but not trailing) slash. +mount_path: null + +#: Route share paths to DAVProvider instances +#: By default a writable `FilesystemProvider` is assumed, but can be forced +#: to read-only. +#: Note that a DomainController may still restrict access completely or prevent +#: editing depending on authentication. +#: +#: The following syntax variants are supported to use FilesystemProvider: +#: <share_path>: <folder_path> +#: or +#: <share_path>: { 'root': <folder_path>, 'readonly': <bool> } +#: +#: or instantiate an arbitrary custom class: +#: +#: <share_path>: { 'class': <class_path>, args: [<arg>, ...], kwargs: {<arg>: <val>, ...} } + +provider_mapping: + '/': 'testrepo' + +#: Additional configuration passed to `FilesystemProvider(..., fs_opts)` +fs_dav_provider: + #: Mapping from request URL to physical file location, e.g. + #: make sure that a `/favicon.ico` URL is resolved, even if a `*.html` + #: or `*.txt` resource file was opened using the DirBrowser + # shadow_map: + # '/favicon.ico': 'file_path/to/favicon.ico' + + #: Serve symbolic link files and folders (default: false) + follow_symlinks: false + +# ============================================================================== +# AUTHENTICATION +http_authenticator: + #: Allow basic authentication + accept_basic: true + #: Allow digest authentication + accept_digest: true + #: true (default digest) or false (default basic) + default_to_digest: true + #: Header field that will be accepted as authorized user. + #: Including quotes, for example: trusted_auth_header = 'REMOTE_USER' + trusted_auth_header: null + #: Domain controller that is used to resolve realms and authorization. + #: Default null: which uses SimpleDomainController and the + #: `simple_dc.user_mapping` option below. + #: (See http://wsgidav.readthedocs.io/en/latest/user_guide_configure.html + #: for details.) + domain_controller: null + # domain_controller: wsgidav.dc.simple_dc.SimpleDomainController + # domain_controller: wsgidav.dc.pam_dc.PAMDomainController + # domain_controller: wsgidav.dc.nt_dc.NTDomainController + + +# Additional options for SimpleDomainController only: +simple_dc: + # Access control per share. + # These routes must match the provider mapping. + # NOTE: Provider routes without a matching entry here, are inaccessible. + user_mapping: + '*': # default (used for all shares that are not explicitly listed) + 'dav': + password: 'testdavutils' + # Optional: passed to downstream middleware as environ["wsgidav.auth.roles"] + # roles: ['editor'] + +# Additional options for NTDomainController only: +nt_dc: + preset_domain: null + preset_server: null + +# Additional options for PAMDomainController only: +pam_dc: + service: 'login' + encoding: 'utf-8' + resetcreds: true + + +# ---------------------------------------------------------------------------- +# User/Group Impersonating +# (Requires `wsgidav.mw.impersonator.Impersonator`, which is disabled by default.) +impersonator: + # enabling impersonating + enable: false + + # custom map WebDAV (HTTP) usernames to Unix usernames + # custom_user_mapping: + # leonlee: leo + # jenifer: jenny + + # or, use WebDAV (HTTP) usernames as is + custom_user_mapping: null + + +# ---------------------------------------------------------------------------- +# CORS +# (Requires `wsgidav.mw.cors.Cors`, which is enabled by default.) +cors: + #: List of allowed Origins or '*' + #: Default: false, i.e. prevent CORS + allow_origin: null + # allow_origin: '*' + # allow_origin: + # - 'https://example.com' + # - 'https://localhost:8081' + + #: List or comma-separated string of allowed methods (returned as + #: response to preflight request) + allow_methods: + # allow_methods: POST,HEAD + #: List or comma-separated string of allowed header names (returned as + #: response to preflight request) + allow_headers: + # - X-PINGOTHER + #: List or comma-separated string of allowed headers that JavaScript in + #: browsers is allowed to access. + expose_headers: + #: Set to true to allow responses on requests with credentials flag set + allow_credentials: false + #: Time in seconds for how long the response to the preflight request can + #: be cached (default: 5) + max_age: 600 + #: Add custom response headers (dict of header-name -> header-value items) + #: (This is not related to CORS or required to implement CORS functionality) + add_always: + # 'X-Foo-Header: 'qux' + +# ---------------------------------------------------------------------------- +# Property Manager +# null: (default) no support for dead properties +# true: Use wsgidav.prop_man.property_manager.PropertyManager +# which is an in-memory property manager (NOT persistent) +# +# Example: Use persistent shelve based property manager +# property_manager: +# class: wsgidav.prop_man.property_manager.ShelvePropertyManager +# kwargs: +# storage_path: 'wsgidav-props.shelve' + +property_manager: null + +#: Optional additional live property modification +#: Note: by default live properties like file size and last-modified time are +#: read-only, but that can be overridden here if the underlying DAV provider +#: supports it. For now only the FileSystemProvider supports it and only namely +#: changes to the last-modified timestamp. Enable it with the mutable_live_props +#: list as below to allow clients to use the utime system call or e.g. the +#: touch or cp / rsync commands with the preserve-timestamp flags on a mounted +#: DAV share. +#: Please note that the timestamp is set on the actual file or directory, so it +#: is persistent even for in-memory property managers. It should also be noted +#: that mutable last-modified may not be compliant with the RFC 4918. +mutable_live_props: + # Enable to allow clients to use e.g. the touch or cp / rsync commands with the + # preserve-timestamp flags in a mounted DAV share (may be RFC4918 incompliant) + - '{DAV:}getlastmodified' + + +# ---------------------------------------------------------------------------- +# Lock Manager Storage +# +# null: No lock support +# true: (default) shortcut for +# lock_storage: wsgidav.lock_man.lock_storage.LockStorageDict +# +# Note that the default LockStorageDict works in-memory, so it is +# NOT persistent. +# +# Example: Use persistent shelve based lock storage: +# lock_storage: +# class: wsgidav.lock_man.lock_storage.LockStorageShelve +# kwargs: +# storage_path: /path/to/wsgidav_locks.shelve +# +# Check the documentation on how to develop custom lock storage. + +lock_storage: true + + +# ============================================================================== +# DEBUGGING + +#: Set verbosity level (can be overridden by -v or -q arguments) +verbose: 3 + +#: Suppress version info in HTTP response headers and error responses +suppress_version_info: false + +logging: + #: Enable logging when using wsgidav in library mode (always on, when running as CLI) + enable: null + #: Set logging output format + #: (see https://docs.python.org/3/library/logging.html#logging.Formatter) + logger_date_format: '%H:%M:%S' + logger_format: '%(asctime)s.%(msecs)03d - %(levelname)-8s: %(message)s' + # Example: Add date,thread id, and logger name: + # logger_date_format: '%Y-%m-%d %H:%M:%S' + # logger_format: '%(asctime)s.%(msecs)03d - <%(thread)05d> %(name)-27s %(levelname)-8s: %(message)s' + + #: Enable specific module loggers + #: E.g. ['lock_manager', 'property_manager', 'http_authenticator', ...] + # enable_loggers: ['http_authenticator', ] + + # Enable max. logging for certain http methods + # E.g. ['COPY', 'DELETE', 'GET', 'HEAD', 'LOCK', 'MOVE', 'OPTIONS', 'PROPFIND', 'PROPPATCH', 'PUT', 'UNLOCK'] + debug_methods: [] + + # Enable max. logging during litmus suite tests that contain certain strings + # E.g. ['lock_excl', 'notowner_modify', 'fail_cond_put_unlocked', ...] + debug_litmus: [] + + +# ---------------------------------------------------------------------------- +# WsgiDavDirBrowser + +dir_browser: + enable: true + #: List of fnmatch patterns that will be hidden in the directory listing + ignore: + - '.DS_Store' # macOS folder meta data + - 'Thumbs.db' # Windows image previews + - '._*' # macOS hidden data files + #: Add a trailing slash to directory URLs (by generating a 301 redirect) + directory_slash: true + #: Display WsgiDAV icon in header + icon: true + #: Raw HTML code, appended as footer (true: use a default trailer) + response_trailer: true + #: Display the name and realm of the authenticated user (or 'anomymous') + show_user: true + show_logout: true + #: Send <dm:mount> response if request URL contains '?davmount' + #: (See https://tools.ietf.org/html/rfc4709) + davmount: true + #: Add a 'Mount' link at the top of the listing + davmount_links: false + #: Invoke MS Office documents for editing using WebDAV by adding a JavaScript + #: click handler. + #: - For IE 11 and below invokes the SharePoint ActiveXObject("SharePoint.OpenDocuments") + #: - If the custom legacy Firefox plugin is available, it will be used + #: https://docs.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ff407576(v%3Doffice.14) + #: - Otherwise the Office URL prefix is used (e.g. 'ms-word:ofe|u|http://server/path/file.docx') + ms_sharepoint_support: true + #: Invoke Libre Office documents for editing using WebDAV + libre_office_support: true + #: The path to the directory that contains template.html and associated + #: assets. + #: The default is the htdocs directory within the dir_browser directory. + htdocs_path: null