// -*- mode: c++; indent-tabs-mode: nil -*-

/*  WebDavHandler module Copyright 2019 - 2021 Qore Technologies, s.r.o.

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/


//! Main public WebDavHandler namespace
namespace WebDavHandler {
//! Filesystem WebDavHandler inteface class
class FsWebDavHandler : public AbstractWebDavHandler {

public:
protected:
        //! The root directory for serving files
        string basePath;
        bool debug;

        //! Default block size for chunked sends (32KiB)
        const BlockSize = 32 * 1024;

        //! Default I/O timeout
        const IoTimeout = 30s;

public:

    //! Creates the object with an empty logger and an in-memory property handler
/** @param path the path on the local filesystem for WebDAV file handline
        @param auth the authentication object to use to authenticate connections
    */
    constructor(string path, __7_ HttpServer::AbstractAuthenticator auth) ;


    //! Creates the object with the given argument and an in-memory property handler
/** @param path the path on the local filesystem for WebDAV file handline
        @param auth the authentication object to use to authenticate connections
        @param virtual_relative_path_base the virtual base path for WebDavHandler requests; this path will be
        stripped from requests internally when serving WebDavHandler resources
    */
    constructor(string path, __7_ HttpServer::AbstractAuthenticator auth, string virtual_relative_path_base)
 ;


    //! Creates the object with the given arguments
/** @param path the path on the local filesystem for WebDAV file handline
        @param auth the authentication object to use to authenticate connections
        @param property_handler to handle properties
        @param virtual_relative_path_base the virtual base path for WebDavHandler requests; this path will be
        stripped from requests internally when serving WebDavHandler resources
    */
constructor(string path, __7_ HttpServer::AbstractAuthenticator auth, AbstractWebDavPropertyHandler property_handler, string virtual_relative_path_base = '/') ;


    //! Creates the object with the given arguments
/** @param path the path on the local filesystem for WebDAV file handline
        @param auth the authentication object to use to authenticate connections
        @param logger the logger
        @param property_handler to handle properties
        @param virtual_relative_path_base the virtual base path for WebDavHandler requests; this path will be
        stripped from requests internally when serving WebDavHandler resources
    */
constructor(string path, __7_ HttpServer::AbstractAuthenticator auth, Logger logger, AbstractWebDavPropertyHandler property_handler = new InMemoryWebDavPropertyHandler(), string virtual_relative_path_base = '/') ;


    //! Common constructor initialization
protected:
     init(string path);
public:


    //! Converts a request path to a normalized real path on the filesystem in the root WebDavHandler directory
/** @throw WEBDAVHANDLER-FORBIDDEN if the path is not valid
    */
protected:
     string getRealPath(string raw_path);
public:


    //! Returns the content type for the file based on its extension
protected:
     __7_ string getContentType(string filePath);
public:


    //! Returns resources for use in a PROPFIND request based on a StatInfo hash
protected:
     hash<auto> hstat2Resource(string path, string displayname, hash<StatInfo> h);
public:


    //! Returns responses for each relevant resource
private:
 list<hash<auto>> preparePropFindResponse(hash<auto> cx, string depth = 'infinity', hash<StatInfo> h, bool all_props, *hash<string, hash<string, bool>> additional_props);
public:


private:
     string getETag(string path);
public:


private:
 hash<HttpResponseInfo> internalGet(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body, bool get = True);
public:


private:
     __7_ string getDirectoryList(string path);
public:


    //! Handles HTTP GET requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the HTTP request
    */
protected:
     hash<HttpResponseInfo> handleGetImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles HTTP HEAD requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by
          @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys
        will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the HTTP request
    */
protected:
     hash<HttpResponseInfo> handleHeadImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles HTTP POST requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by
          @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys
        will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the HTTP request
    */
protected:
     hash<HttpResponseInfo> handlePostImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles HTTP PUT requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the HTTP request
    */
protected:
     hash<HttpResponseInfo> handlePutImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles HTTP DELETE requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the HTTP request
    */
protected:
     hash<HttpResponseInfo> handleDeleteImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles WebDavHandler COPY requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the WebDavHandler request
    */
protected:
     hash<HttpResponseInfo> handleCopyImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles WebDavHandler MOVE requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the WebDavHandler request
    */
protected:
     hash<HttpResponseInfo> handleMoveImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles WebDavHandler LOCK requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the WebDavHandler request
    */
protected:
     hash<HttpResponseInfo> handleLockImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


protected:
     string getLockToken();
public:


    //! Handles WebDavHandler UNLOCK requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the WebDavHandler request
    */
protected:
     hash<HttpResponseInfo> handleUnlockImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles WebDavHandler MKCOL requests for WebDavHandler resources
/**  @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the WebDavHandler request
    */
protected:
     hash<HttpResponseInfo> handleMkcolImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Handles WebDavHandler PROPFIND requests for WebDavHandler resources; reetrieves properties from WebDavHandler resources
/**
        @param cx call context hash; this hash will have the following keys:
        - \c header-info: a hash of information about the request header with the following keys:
          - \c accept-charset: this key will be set to an appropriate value from any \c "Accept-Charset" header; if
            any of \c "*", \c "utf8", or \c "utf-8" are present, then this will be set to \c "utf8", otherwise it will
            be set to the first requested character encoding in the list
          - \c accept-encoding: a hash where keys are values from any \c "Accept-Encoding" header and the values are
            @ref True
          - \c body-content-type: this is the \c "Content-Type" header without any charset declaration
          - \c charset: if there is a charset declaration in the \c "Content-Type" header, the value is returned in
            this key
          - \c client-cert: if the server is configured to capture remote client certificates, and the client supplied
            a certificate, this key will be populated with the @ref Qore::SSLCertificate "SSLCertificate" for the client
          - \c close: set to @ref True "True" if the connection should be closed after responding,
            @ref False "False" if not (as derived from the request header)
          - \c headers-raw: a hash of raw request headers without any case conversions or other processing
          - \c request-uri: gives the request URI in an HTTP request
        - \c socket: the bind address used to bind the listener (\c "socket-info" provides more detailed information)
        - \c socket-info: a hash of socket information for the listening socket (as returned by
          @ref Qore::Socket::getSocketInfo())
        - \c peer-info: a hash of socket information for the remote socket (as returned by @ref Qore::Socket::getPeerInfo())
        - \c url: a hash of broken-down URL information (as returned from @ref Qore::parse_url())
        - \c id: the unique HTTP connection ID
        - \c ssl: @ref True "True" if the request was encrypted with HTTPS, @ref False "False" if not
        - \c listener-id: the HTTP server listener ID (see HttpServer::getListenerInfo())
        - \c user: the current RBAC username (if any)
        - \c root_path: the root URL path matched if the request was matched by a URL prefix
        @param hdr incoming header hash; all keys will be converted to lower-case, additionally the following keys will be present:
        - \c method: the HTTP method received (ie \c "GET", \c "POST", etc)
        - \c path: the HTTP path given in the request, after processing by @ref Qore::decode_uri_request()
        - \c http_version: the HTTP version number in the request (either \c "1.0" or \c "1.1")
        @param body message body, if any

        @return the response to the WebDavHandler request
    */
protected:
     hash<HttpResponseInfo> handlePropfindImpl(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body);
public:


    //! Internal method for handling PROPPATCH requests
/** Create, change and delete one or more properties on a resource in a single atomic action

        @param cx the HTTP call context
        @param hdr as hash HTTP headers
        @param request_xml the parsed XML in the request
        @param actions a list of set and remove actions to execute on the given properties

        @return a status map of HTTP code -> namespace -> property -> True

        @throw WEBDAVHANDLER-ERROR an error occured
    */
protected:
 __7_ hash<string, hash<string, hash<string, bool>>> handleProppatchImpl(reference<string> href, hash<auto> cx, hash<auto> hdr, *hash<auto> request_xml, *list<hash<PropPatchActionInfo>> actions);
public:


    //! Verifies that all property updates can be performed before executing them
protected:
     __7_ hash<string, hash<string, hash<string, bool>>> verifyPropertyUpdates(string path, __7_ list<hash<PropPatchActionInfo>> actions);
public:


    //! Process copy and moves (without deletion) internally including properties (properties are moved, files are copied)
private:
     hash<HttpResponseInfo> doCopyMoveIntern(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body, bool copy_props);
public:


    //! Copy or move the file and any properties
private:
     internalCopyMove(Socket s, hash<auto> cx, hash<auto> hdr, __7_ data body, bool copy_props);
public:

}; // class FsWebDavHandler
}; // namespace WebDavHandler
