ucb: webdav-curl: tdf#101094 (8) OPTIONS: Add options check in Content::resourceTypeForLocks
[ port of commit 6ab2cabeae02b6beb3c33238773ba075f41c4bb9 ]
Change-Id: I10f928fb5484738553769f54353ca7637e0780ce
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123290
Tested-by: Michael Stahl <michael.stahl@allotropia.de>
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
diff --git a/ucb/source/ucp/webdav-curl/webdavcontent.cxx b/ucb/source/ucp/webdav-curl/webdavcontent.cxx
index 96ac6dd..706f3a0 100644
--- a/ucb/source/ucp/webdav-curl/webdavcontent.cxx
+++ b/ucb/source/ucp/webdav-curl/webdavcontent.cxx
@@ -2825,7 +2825,8 @@ void Content::destroy( bool bDeletePhysical )
// returns the resource type, to be checked for locks
Content::ResourceType Content::resourceTypeForLocks(
const uno::Reference< ucb::XCommandEnvironment >& Environment )
const uno::Reference< ucb::XCommandEnvironment >& Environment,
const std::unique_ptr< DAVResourceAccess > & rResAccess)
{
ResourceType eResourceTypeForLocks = UNKNOWN;
{
@@ -2857,98 +2858,128 @@ Content::ResourceType Content::resourceTypeForLocks(
if ( eResourceTypeForLocks == UNKNOWN )
{
// resource type for lock/unlock operations still unknown, need to ask the server
std::unique_ptr< DAVResourceAccess > xResAccess;
xResAccess.reset( new DAVResourceAccess(
m_xContext,
m_rSessionFactory,
rURL ) );
{
try
//{
DAVOptions aDAVOptions;
getResourceOptions( Environment, aDAVOptions, rResAccess );
if( aDAVOptions.isClass1() ||
aDAVOptions.isClass2() ||
aDAVOptions.isClass3() )
{
// we need only DAV:supportedlock
std::vector< DAVResource > resources;
std::vector< OUString > aPropNames;
uno::Sequence< beans::Property > aProperties( 1 );
aProperties[ 0 ].Name = DAVProperties::SUPPORTEDLOCK;
ContentProperties::UCBNamesToDAVNames( aProperties, aPropNames );
xResAccess->PROPFIND( DAVZERO, aPropNames, resources, Environment );
// only one resource should be returned
if ( resources.size() == 1 )
// this is at least a DAV, lock to be confirmed
// class 2 is needed for full lock support
// see
// <https://tools.ietf.org/html/rfc4918#section-18.2>
eResourceTypeForLocks = DAV_NOLOCK;
if( aDAVOptions.isClass2() )
{
// we may have received a bunch of other properties
// (some servers seems to do so)
// but we need only supported lock for this check
// all returned properties are in
// resources.properties[n].Name/.Value
std::vector< DAVPropertyValue >::iterator it;
for ( it = resources[0].properties.begin();
it != resources[0].properties.end(); it++)
// ok, possible lock, check for it
try
{
if ( (*it).Name == DAVProperties::SUPPORTEDLOCK )
// we need only DAV:supportedlock
std::vector< DAVResource > resources;
std::vector< OUString > aPropNames;
uno::Sequence< beans::Property > aProperties( 1 );
aProperties[ 0 ].Name = DAVProperties::SUPPORTEDLOCK;
ContentProperties::UCBNamesToDAVNames( aProperties, aPropNames );
rResAccess->PROPFIND( DAVZERO, aPropNames, resources, Environment );
bool wasSupportedlockFound = false;
// only one resource should be returned
if ( resources.size() == 1 )
{
uno::Sequence< ucb::LockEntry > aSupportedLocks;
if ( (*it).Value >>= aSupportedLocks )
// we may have received a bunch of other properties
// (some servers seems to do so)
// but we need only supported lock for this check
// all returned properties are in
// resources.properties[n].Name/.Value
std::vector< DAVPropertyValue >::iterator it;
for ( it = resources[0].properties.begin();
it != resources[0].properties.end(); ++it)
{
// this is at least a DAV, no lock confirmed yet
eResourceTypeForLocks = DAV_NOLOCK;
for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n )
if ( (*it).Name == DAVProperties::SUPPORTEDLOCK )
{
if ( aSupportedLocks[ n ].Scope == ucb::LockScope_EXCLUSIVE &&
aSupportedLocks[ n ].Type == ucb::LockType_WRITE )
wasSupportedlockFound = true;
uno::Sequence< ucb::LockEntry > aSupportedLocks;
if ( (*it).Value >>= aSupportedLocks )
{
// requested locking mode is supported
eResourceTypeForLocks = DAV;
SAL_INFO( "ucb.ucp.webdav", "resourceTypeForLocks - URL: <"
<< m_xIdentifier->getContentIdentifier() << ">, DAV lock/unlock supported");
for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n )
{
// TODO: if the lock type is changed from 'exclusive write' to 'shared write'
// e.g. to implement 'Calc shared file feature', the ucb::LockScope_EXCLUSIVE
// value should be checked as well, adaptation the code may be needed
if ( aSupportedLocks[ n ].Scope == ucb::LockScope_EXCLUSIVE &&
aSupportedLocks[ n ].Type == ucb::LockType_WRITE )
{
// requested locking mode is supported
eResourceTypeForLocks = DAV;
SAL_INFO( "ucb.ucp.webdav", "resourceTypeForLocks - URL: <"
<< m_xIdentifier->getContentIdentifier() << ">, DAV lock/unlock supported");
break;
}
}
break;
}
}
break;
}
}
// check if this is still only a DAV_NOLOCK
// a fallback for resources that do not have DAVProperties::SUPPORTEDLOCK property
// we check for the returned OPTION if LOCK is allowed on the resource
if ( !wasSupportedlockFound && eResourceTypeForLocks == DAV_NOLOCK )
{
SAL_INFO( "ucb.ucp.webdav", "This WebDAV server has no supportedlock property, check for allowed LOCK method in OPTIONS" );
// ATTENTION: if the lock type is changed from 'exclusive write' to 'shared write'
// e.g. to implement 'Calc shared file feature' on WebDAV directly, and we arrive to this fallback
// and the LOCK is allowed, we should assume that only exclusive write lock is available
// this is just a reminder...
if ( aDAVOptions.isLockAllowed() )
eResourceTypeForLocks = DAV;
}
}
catch ( DAVException const & e )
{
rResAccess->resetUri();
//grab the error code
switch( e.getStatus() )
{
case SC_NOT_FOUND:
SAL_WARN( "ucb.ucp.webdav", "resourceTypeForLocks() - URL: <"
<< m_xIdentifier->getContentIdentifier() << "> was not found. ");
eResourceTypeForLocks = NOT_FOUND;
break;
// some servers returns SC_FORBIDDEN, instead
// TODO: probably remove it, when OPTIONS implemented
// the meaning of SC_FORBIDDEN is, according to <http://tools.ietf.org/html/rfc7231#section-6.5.3>:
// The 403 (Forbidden) status code indicates that the server understood
// the request but refuses to authorize it
case SC_FORBIDDEN:
// Errors SC_NOT_IMPLEMENTED and SC_METHOD_NOT_ALLOWED are
// part of base http 1.1 RFCs
case SC_NOT_IMPLEMENTED: // <http://tools.ietf.org/html/rfc7231#section-6.6.2>
case SC_METHOD_NOT_ALLOWED: // <http://tools.ietf.org/html/rfc7231#section-6.5.5>
// they all mean the resource is NON_DAV
SAL_WARN( "ucb.ucp.webdav", "resourceTypeForLocks() DAVException (SC_FORBIDDEN, SC_NOT_IMPLEMENTED or SC_METHOD_NOT_ALLOWED) - URL: <"
<< m_xIdentifier->getContentIdentifier() << ">, DAV error: " << e.getError() << ", HTTP error: " << e.getStatus() );
eResourceTypeForLocks = NON_DAV;
break;
default:
//fallthrough
SAL_WARN( "ucb.ucp.webdav", "resourceTypeForLocks() DAVException - URL: <"
<< m_xIdentifier->getContentIdentifier() << ">, DAV error: " << e.getError() << ", HTTP error: " << e.getStatus() );
eResourceTypeForLocks = UNKNOWN;
}
}
}
}
catch ( DAVException const & e )
{
xResAccess->resetUri();
//grab the error code
switch( e.getStatus() )
{
case SC_NOT_FOUND:
SAL_WARN( "ucb.ucp.webdav", "resourceTypeForLocks() - URL: <"
<< m_xIdentifier->getContentIdentifier() << "> was not found. ");
eResourceTypeForLocks = NOT_FOUND;
break;
// some servers returns SC_FORBIDDEN, instead
// TODO: probably remove it, when OPTIONS implemented
// the meaning of SC_FORBIDDEN is, according to <http://tools.ietf.org/html/rfc7231#section-6.5.3>:
// The 403 (Forbidden) status code indicates that the server understood
// the request but refuses to authorize it
case SC_FORBIDDEN:
// Errors SC_NOT_IMPLEMENTED and SC_METHOD_NOT_ALLOWED are
// part of base http 1.1 RFCs
case SC_NOT_IMPLEMENTED: // <http://tools.ietf.org/html/rfc7231#section-6.6.2>
case SC_METHOD_NOT_ALLOWED: // <http://tools.ietf.org/html/rfc7231#section-6.5.5>
// they all mean the resource is NON_DAV
SAL_WARN( "ucb.ucp.webdav", "resourceTypeForLocks() DAVException (SC_FORBIDDEN, SC_NOT_IMPLEMENTED or SC_METHOD_NOT_ALLOWED) - URL: <"
<< m_xIdentifier->getContentIdentifier() << ">, DAV error: " << e.getError() << ", HTTP error: " << e.getStatus() );
eResourceTypeForLocks = NON_DAV;
break;
default:
//fallthrough
SAL_WARN( "ucb.ucp.webdav", "resourceTypeForLocks() DAVException - URL: <"
<< m_xIdentifier->getContentIdentifier() << ">, DAV error: " << e.getError() << ", HTTP error: " << e.getStatus() );
eResourceTypeForLocks = UNKNOWN;
}
}
}
else
eResourceTypeForLocks = NON_DAV;
//}
}
osl::MutexGuard g(m_aMutex);
if (m_eResourceTypeForLocks == UNKNOWN)
@@ -2967,6 +2998,21 @@ Content::ResourceType Content::resourceTypeForLocks(
return m_eResourceTypeForLocks;
}
Content::ResourceType Content::resourceTypeForLocks(
const uno::Reference< ucb::XCommandEnvironment >& Environment )
{
std::unique_ptr< DAVResourceAccess > xResAccess;
{
osl::MutexGuard aGuard( m_aMutex );
xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
}
Content::ResourceType ret = resourceTypeForLocks( Environment, xResAccess );
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
}
return ret;
}
void Content::lock(
const uno::Reference< ucb::XCommandEnvironment >& Environment )
@@ -3020,7 +3066,7 @@ void Content::lock(
// this exception is mapped directly to the ucb correct one, without
// going into the cancelCommandExecution() user interaction
// this exception should be managed by the issuer of 'lock' command
switch(e.getError())
switch( e.getError() )
{
case DAVException::DAV_LOCKED:
{
diff --git a/ucb/source/ucp/webdav-curl/webdavcontent.hxx b/ucb/source/ucp/webdav-curl/webdavcontent.hxx
index f5a74bd..209f435 100644
--- a/ucb/source/ucp/webdav-curl/webdavcontent.hxx
+++ b/ucb/source/ucp/webdav-curl/webdavcontent.hxx
@@ -173,7 +173,11 @@ private:
static bool shouldAccessNetworkAfterException( const DAVException & e );
ResourceType resourceTypeForLocks(
const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment );
const css::uno::Reference< css::ucb::XCommandEnvironment >& rEnvironment,
const std::unique_ptr< DAVResourceAccess > & rResAccess );
ResourceType resourceTypeForLocks(
const css::uno::Reference< css::ucb::XCommandEnvironment >& rEnvironment );
// XPropertyContainer replacement
/// @throws css::beans::PropertyExistException