ucb: webdav-curl: tdf#101094 (10) OPTIONS: Add a simple options cache class

Added behavioral unit tests as well.

[ port of commit b641d83bb9f8adba1a487ca0e04d7151f96c3eea ]

Change-Id: Ie8867aeb45dcc8d343b156608e8a30970f76f6f5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123292
Tested-by: Michael Stahl <michael.stahl@allotropia.de>
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
diff --git a/ucb/source/ucp/webdav-curl/DAVTypes.cxx b/ucb/source/ucp/webdav-curl/DAVTypes.cxx
index b71f61a..bddbe50 100644
--- a/ucb/source/ucp/webdav-curl/DAVTypes.cxx
+++ b/ucb/source/ucp/webdav-curl/DAVTypes.cxx
@@ -10,6 +10,7 @@

#include "DAVTypes.hxx"

#include "CurlUri.hxx"
#include "../inc/urihelper.hxx"

#include <osl/time.h>
@@ -18,7 +19,7 @@
using namespace http_dav_ucp;
using namespace com::sun::star;

// DAVCapabilities implementation
// DAVOptions implementation

DAVOptions::DAVOptions() :
    m_isResourceFound( false ),
@@ -65,4 +66,82 @@ bool DAVOptions::operator==( const DAVOptions& rOpts ) const
}


// DAVOptionsCache implementation

DAVOptionsCache::DAVOptionsCache()
{
}


DAVOptionsCache::~DAVOptionsCache()
{
}


bool DAVOptionsCache::getDAVOptions( const OUString & rURL, DAVOptions & rDAVOptions )
{
    osl::MutexGuard aGuard( m_aMutex );
    OUString aEncodedUrl( ucb_impl::urihelper::encodeURI( DecodeURI(rURL) ) );
    normalizeURLLastChar( aEncodedUrl );

    // search the URL in the static map
    DAVOptionsMap::iterator it;
    it = m_aTheCache.find( aEncodedUrl );
    if ( it == m_aTheCache.end() )
        return false;
    else
    {
        // check if the capabilities are stale, before restoring
        TimeValue t1;
        osl_getSystemTime( &t1 );
        if ( (*it).second.getStaleTime() < t1.Seconds )
        {
            // if stale, remove from cache, do not restore
            removeDAVOptions( rURL );
            return false;
            // return false instead
        }
        rDAVOptions = (*it).second;
        return true;
    }
}


void DAVOptionsCache::removeDAVOptions( const OUString & rURL )
{
    osl::MutexGuard aGuard( m_aMutex );
    OUString aEncodedUrl( ucb_impl::urihelper::encodeURI( DecodeURI(rURL) ) );
    normalizeURLLastChar( aEncodedUrl );

    DAVOptionsMap::iterator it;
    it = m_aTheCache.find( aEncodedUrl );
    if ( it != m_aTheCache.end() )
    {
        m_aTheCache.erase( it );
    }
}


void DAVOptionsCache::addDAVOptions( DAVOptions & rDAVOptions, const sal_uInt32 nLifeTime )
{
    osl::MutexGuard aGuard( m_aMutex );

    OUString aURL( rDAVOptions.getURL() );

    OUString aEncodedUrl( ucb_impl::urihelper::encodeURI( DecodeURI(aURL) ) );
    normalizeURLLastChar( aEncodedUrl );
    rDAVOptions.setURL( aEncodedUrl );

// unchanged, it may be used to access a server
    OUString aRedirURL( rDAVOptions.getRedirectedURL() );
    rDAVOptions.setRedirectedURL( aRedirURL );

    TimeValue t1;
    osl_getSystemTime( &t1 );
    rDAVOptions.setStaleTime( t1.Seconds + nLifeTime );

    m_aTheCache[ aEncodedUrl ] = rDAVOptions;
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/ucb/source/ucp/webdav-curl/DAVTypes.hxx b/ucb/source/ucp/webdav-curl/DAVTypes.hxx
index e1d5390..a4180c6 100644
--- a/ucb/source/ucp/webdav-curl/DAVTypes.hxx
+++ b/ucb/source/ucp/webdav-curl/DAVTypes.hxx
@@ -123,10 +123,35 @@ namespace http_dav_ucp
            m_sRedirectedURL.clear();
        };

        DAVOptions & operator=( const DAVOptions& rOpts ) = default; //TODO -Werror=deprecated-copy
        bool operator==( const DAVOptions& rOpts ) const;

    };

    typedef std::map< OUString, DAVOptions > DAVOptionsMap;

    class DAVOptionsCache
    {
        DAVOptionsMap m_aTheCache;
        osl::Mutex         m_aMutex;
    public:
        explicit DAVOptionsCache();
        ~DAVOptionsCache();

        bool getDAVOptions( const OUString & rURL, DAVOptions & rDAVOptions );
        void removeDAVOptions( const OUString & rURL );
        void addDAVOptions( DAVOptions & rDAVOptions, const sal_uInt32 nLifeTime );

    private:

        /// remove the last '/' in aUrl, if it exists
        static void normalizeURLLastChar( OUString& aUrl ) {
            if ( aUrl.getLength() > 1 &&
                 ( ( aUrl.lastIndexOf( '/' ) + 1 ) == aUrl.getLength() ) )
                aUrl = aUrl.copy(0, aUrl.getLength() - 1 );
        };
    };

    enum Depth { DAVZERO = 0, DAVONE = 1, DAVINFINITY = -1 };

    enum ProppatchOperation { PROPSET = 0, PROPREMOVE = 1 };