summaryrefslogtreecommitdiff
path: root/ucb
diff options
context:
space:
mode:
authorGiuseppe Castagno <giuseppe.castagno@acca-esse.eu>2016-09-12 20:59:09 +0200
committerMichael Stahl <michael.stahl@allotropia.de>2021-11-01 18:51:27 +0100
commit2afb51076c3f766ab39cbfc66d8469889a2b0a5c (patch)
tree811ba5b51fdceb68e103377c6c774d87e442b4a5 /ucb
parente3c2294c351892ca864f7dd5827dbe04cfcc8021 (diff)
ucb: webdav-curl: tdf#102499 (5): Deal with HTTP unofficial response status codes
A reference can be found here: <https://en.wikipedia.org/wiki/List_of_HTTP_status_codes> (retrieved 2016-09-13). Changes done: Add set of 'HEAD method not available' before using fall back GET method. Add new method in OPTIONS cache. Add response status code if fall-back GET didn't succeeded. Add copy-assignement operator to DAVOptions. Fix behaviour of GET fall back when HEAD missing. [ port of commit 16df731a30917a426df81d751a0bfd0ae5fcdd45 ] Change-Id: I4dbf4ead49f72617fad0a13f75b8e361d1a8dba7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123497 Tested-by: Michael Stahl <michael.stahl@allotropia.de> Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'ucb')
-rw-r--r--ucb/source/ucp/webdav-curl/DAVTypes.cxx77
-rw-r--r--ucb/source/ucp/webdav-curl/DAVTypes.hxx6
-rw-r--r--ucb/source/ucp/webdav-curl/webdavcontent.cxx100
3 files changed, 144 insertions, 39 deletions
diff --git a/ucb/source/ucp/webdav-curl/DAVTypes.cxx b/ucb/source/ucp/webdav-curl/DAVTypes.cxx
index ad39d0d46095..d16b7bacc3bd 100644
--- a/ucb/source/ucp/webdav-curl/DAVTypes.cxx
+++ b/ucb/source/ucp/webdav-curl/DAVTypes.cxx
@@ -36,7 +36,6 @@ DAVOptions::DAVOptions() :
{
}
-
DAVOptions::DAVOptions( const DAVOptions & rOther ) :
m_isClass1( rOther.m_isClass1 ),
m_isClass2( rOther.m_isClass2 ),
@@ -52,11 +51,25 @@ DAVOptions::DAVOptions( const DAVOptions & rOther ) :
{
}
-
DAVOptions::~DAVOptions()
{
}
+DAVOptions & DAVOptions::operator=( const DAVOptions& rOpts )
+{
+ m_isClass1 = rOpts.m_isClass1;
+ m_isClass2 = rOpts.m_isClass2;
+ m_isClass3 = rOpts.m_isClass3;
+ m_isLocked = rOpts.m_isLocked;
+ m_isHeadAllowed = rOpts.m_isHeadAllowed;
+ m_aAllowedMethods = rOpts.m_aAllowedMethods;
+ m_nStaleTime = rOpts.m_nStaleTime;
+ m_sURL = rOpts.m_sURL;
+ m_sRedirectedURL = rOpts.m_sRedirectedURL;
+ m_nHttpResponseStatusCode = rOpts.m_nHttpResponseStatusCode;
+ m_sHttpResponseStatusText = rOpts.m_sHttpResponseStatusText;
+ return *this;
+}
bool DAVOptions::operator==( const DAVOptions& rOpts ) const
{
@@ -81,12 +94,10 @@ DAVOptionsCache::DAVOptionsCache()
{
}
-
DAVOptionsCache::~DAVOptionsCache()
{
}
-
bool DAVOptionsCache::getDAVOptions( const OUString & rURL, DAVOptions & rDAVOptions )
{
osl::MutexGuard aGuard( m_aMutex );
@@ -115,7 +126,6 @@ bool DAVOptionsCache::getDAVOptions( const OUString & rURL, DAVOptions & rDAVOpt
}
}
-
void DAVOptionsCache::removeDAVOptions( const OUString & rURL )
{
osl::MutexGuard aGuard( m_aMutex );
@@ -130,7 +140,6 @@ void DAVOptionsCache::removeDAVOptions( const OUString & rURL )
}
}
-
void DAVOptionsCache::addDAVOptions( DAVOptions & rDAVOptions, const sal_uInt32 nLifeTime )
{
osl::MutexGuard aGuard( m_aMutex );
@@ -151,6 +160,39 @@ void DAVOptionsCache::addDAVOptions( DAVOptions & rDAVOptions, const sal_uInt32
m_aTheCache[ aEncodedUrl ] = rDAVOptions;
}
+void DAVOptionsCache::updateCachedOption( 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 );
+
+ // check if already cached
+ DAVOptionsMap::iterator it;
+ it = m_aTheCache.find( aEncodedUrl );
+ if ( it != m_aTheCache.end() )
+ {
+ DAVOptions &opts = (*it).second;
+ // exists, set new staletime, only if remaining time is higher
+ TimeValue t1;
+ osl_getSystemTime( &t1 );
+
+ if ( ( opts.getStaleTime() - t1.Seconds ) > nLifeTime )
+ {
+ opts.setStaleTime( t1.Seconds + nLifeTime );
+ }
+ // update relevant fields
+ opts.setHttpResponseStatusCode( rDAVOptions.getHttpResponseStatusCode() );
+ opts.setHttpResponseStatusText( rDAVOptions.getHttpResponseStatusText() );
+ }
+}
+
sal_uInt16 DAVOptionsCache::getHttpResponseStatusCode( const OUString & rURL, OUString & rHttpResponseStatusText )
{
osl::MutexGuard aGuard( m_aMutex );
@@ -176,6 +218,29 @@ sal_uInt16 DAVOptionsCache::getHttpResponseStatusCode( const OUString & rURL, OU
return 0;
}
+void DAVOptionsCache::setHeadAllowed( const OUString & rURL, const bool HeadAllowed )
+{
+ 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() )
+ {
+ // first check for stale
+ TimeValue t1;
+ osl_getSystemTime( &t1 );
+ if( (*it).second.getStaleTime() < t1.Seconds )
+ {
+ m_aTheCache.erase( it );
+ return;
+ }
+ // check if the resource was present on server
+ (*it).second.setHeadAllowed( HeadAllowed );
+ }
+}
+
bool DAVOptionsCache::isHeadAllowed( const OUString & rURL )
{
osl::MutexGuard aGuard( m_aMutex );
diff --git a/ucb/source/ucp/webdav-curl/DAVTypes.hxx b/ucb/source/ucp/webdav-curl/DAVTypes.hxx
index 6db2d2d6e048..e6062649663f 100644
--- a/ucb/source/ucp/webdav-curl/DAVTypes.hxx
+++ b/ucb/source/ucp/webdav-curl/DAVTypes.hxx
@@ -142,7 +142,7 @@ namespace http_dav_ucp
m_sHttpResponseStatusText.clear();
};
- DAVOptions & operator=( const DAVOptions& rOpts ) = default; //TODO -Werror=deprecated-copy
+ DAVOptions & operator=( const DAVOptions& rOpts );
bool operator==( const DAVOptions& rOpts ) const;
};
@@ -165,6 +165,8 @@ namespace http_dav_ucp
void removeDAVOptions( const OUString & rURL );
void addDAVOptions( DAVOptions & rDAVOptions, const sal_uInt32 nLifeTime );
+ void updateCachedOption( DAVOptions & rDAVOptions, const sal_uInt32 nLifeTime );
+
/** return the cached value of HTTP response status code
If the cached value is found stale, it is removed.
@@ -181,6 +183,8 @@ namespace http_dav_ucp
bool isHeadAllowed( const OUString & rURL );
+ void setHeadAllowed( const OUString & rURL, bool HeadAllowed = true );
+
private:
/// remove the last '/' in aUrl, if it exists
diff --git a/ucb/source/ucp/webdav-curl/webdavcontent.cxx b/ucb/source/ucp/webdav-curl/webdavcontent.cxx
index b541f2af5955..55a2e8fe35fe 100644
--- a/ucb/source/ucp/webdav-curl/webdavcontent.cxx
+++ b/ucb/source/ucp/webdav-curl/webdavcontent.cxx
@@ -1462,8 +1462,13 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues(
// PROPPATCH can change them
removeCachedPropertyNames( aTargetURL );
// test if HEAD allowed, if not, throw, will be catched immediately
- if ( !aDAVOptions.isHeadAllowed() )
+ // SC_GONE used internally by us, see comment below
+ // in the catch scope
+ if ( aDAVOptions.getHttpResponseStatusCode() != SC_GONE &&
+ !aDAVOptions.isHeadAllowed() )
+ {
throw DAVException( DAVException::DAV_HTTP_ERROR, "405 Not Implemented", 405 );
+ }
// if HEAD is enabled on this site
// check if there is a relevant HTTP response status code cached
if ( aDAVOptions.getHttpResponseStatusCode() != SC_NONE )
@@ -1517,6 +1522,7 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues(
aLastException.getStatus() == SC_NOT_FOUND )
{
SAL_WARN( "ucb.ucp.webdav", "HEAD probably not implemented: fall back to a partial GET" );
+ aStaticDAVOptionsCache.setHeadAllowed( aTargetURL, false );
lcl_sendPartialGETRequest( bError,
aLastException,
aMissingProps,
@@ -1530,10 +1536,27 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues(
if ( bError )
{
+ DAVOptions aDAVOptionsException;
+
+ aDAVOptionsException.setURL( aTargetURL );
+ // check if the error was SC_NOT_FOUND, meaning that the
+ // GET fall back didn't succeeded and the element is really missing
+ // we will consider the resource SC_GONE (410) for some time
+ // we use SC_GONE because has the same meaning of SC_NOT_FOUND (404)
+ // see:
+ // <https://tools.ietf.org/html/rfc7231#section-6.5.9> (retrieved 2016-10-09)
+ // apparently it's not used to mark the missing HEAD method (so far...)
+ sal_uInt16 ResponseStatusCode =
+ ( aLastException.getStatus() == SC_NOT_FOUND ) ?
+ SC_GONE :
+ aLastException.getStatus();
+ aDAVOptionsException.setHttpResponseStatusCode( ResponseStatusCode );
+ aDAVOptionsException.setHttpResponseStatusText( aLastException.getData() );
+ aStaticDAVOptionsCache.updateCachedOption( aDAVOptionsException,
+ m_nOptsCacheLifeNotFound );
+
if ( !shouldAccessNetworkAfterException( aLastException ) )
{
- // remove the cached OPTIONS and errors
- aStaticDAVOptionsCache.removeDAVOptions( aTargetURL );
cancelCommandExecution( aLastException, xEnv );
// unreachable
}
@@ -2219,6 +2242,7 @@ uno::Any Content::open(
}
catch ( DAVException const & e )
{
+ //TODO cache the http error if not yet cached
cancelCommandExecution( e, xEnv );
// Unreachable
}
@@ -3604,6 +3628,7 @@ uno::Any Content::MapDAVException( const DAVException & e, bool bWrite )
bool Content::shouldAccessNetworkAfterException( const DAVException & e )
{
if ( ( e.getStatus() == SC_NOT_FOUND ) ||
+ ( e.getStatus() == SC_GONE ) ||
( e.getError() == DAVException::DAV_HTTP_TIMEOUT ) ||
( e.getError() == DAVException::DAV_HTTP_LOOKUP ) ||
( e.getError() == DAVException::DAV_HTTP_CONNECT ) ||
@@ -3788,7 +3813,8 @@ Content::ResourceType Content::getResourceType(
{
rResAccess->resetUri();
- if ( aDAVOptions.getHttpResponseStatusCode() != SC_NOT_FOUND )
+ if ( aDAVOptions.getHttpResponseStatusCode() != SC_NOT_FOUND &&
+ aDAVOptions.getHttpResponseStatusCode() != SC_GONE ) // the cached OPTIONS can have SC_GONE
{
eResourceType = NON_DAV;
}
@@ -3796,8 +3822,7 @@ Content::ResourceType Content::getResourceType(
{
//resource doesn't exist
if ( networkAccessAllowed != nullptr )
- *networkAccessAllowed = false;
- }
+ *networkAccessAllowed = false; }
}
}
@@ -3867,22 +3892,23 @@ void Content::getResourceOptions(
{
OUString aRedirURL;
OUString aTargetURL = rResAccess->getURL();
+ DAVOptions aDAVOptions;
// first check if in cache, if not, then send method to server
- if ( !aStaticDAVOptionsCache.getDAVOptions( aTargetURL, rDAVOptions ) )
+ if ( !aStaticDAVOptionsCache.getDAVOptions( aTargetURL, aDAVOptions ) )
{
try
{
- rResAccess->OPTIONS( rDAVOptions, xEnv );
+ rResAccess->OPTIONS( aDAVOptions, xEnv );
// IMPORTANT:the correctly implemented server will answer without errors, even if the resource is not present
- sal_uInt32 nLifeTime = ( rDAVOptions.isClass1() ||
- rDAVOptions.isClass2() ||
- rDAVOptions.isClass3() ) ?
+ sal_uInt32 nLifeTime = ( aDAVOptions.isClass1() ||
+ aDAVOptions.isClass2() ||
+ aDAVOptions.isClass3() ) ?
m_nOptsCacheLifeDAV : // a WebDAV site
m_nOptsCacheLifeImplWeb; // a site implementing OPTIONS but
// it's not DAV
// if resource is locked, will use a
// different lifetime
- if( rDAVOptions.isLocked() )
+ if( aDAVOptions.isLocked() )
nLifeTime = m_nOptsCacheLifeDAVLocked;
// check if redirected
@@ -3892,9 +3918,9 @@ void Content::getResourceOptions(
aRedirURL.clear();
}
// cache this URL's option
- rDAVOptions.setURL( aTargetURL );
- rDAVOptions.setRedirectedURL( aRedirURL );
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
+ aDAVOptions.setURL( aTargetURL );
+ aDAVOptions.setRedirectedURL( aRedirURL );
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
nLifeTime );
}
catch ( DAVException const & e )
@@ -3903,8 +3929,8 @@ void Content::getResourceOptions(
aStaticDAVOptionsCache.removeDAVOptions( aTargetURL );
rResAccess->resetUri();
- rDAVOptions.setURL( aTargetURL );
- rDAVOptions.setRedirectedURL( aRedirURL );
+ aDAVOptions.setURL( aTargetURL );
+ aDAVOptions.setRedirectedURL( aRedirURL );
switch( e.getError() )
{
case DAVException::DAV_HTTP_TIMEOUT:
@@ -3937,16 +3963,20 @@ void Content::getResourceOptions(
{
SAL_WARN( "ucb.ucp.webdav","OPTIONS - SC_FORBIDDEN for URL <" << m_xIdentifier->getContentIdentifier() << ">" );
// cache it, so OPTIONS won't be called again, this URL does not support it
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
m_nOptsCacheLifeNotImpl );
}
break;
case SC_BAD_REQUEST:
+ case SC_INTERNAL_SERVER_ERROR:
{
- SAL_WARN( "ucb.ucp.webdav","OPTIONS - SC_BAD_REQUEST for URL <" << m_xIdentifier->getContentIdentifier() << ">" );
- // cache it, so OPTIONS won't be called again, this URL does not support it
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
- m_nOptsCacheLifeNotImpl );
+ SAL_WARN( "ucb.ucp.webdav","OPTIONS - SC_BAD_REQUEST or SC_INTERNAL_SERVER_ERROR for URL <" << m_xIdentifier->getContentIdentifier() << ">, HTTP error: "<< e.getStatus()
+ << ", '" << e.getData() << "'" );
+ // cache it, so OPTIONS won't be called again, this URL detect some problem while answering the method
+ aDAVOptions.setHttpResponseStatusCode( e.getStatus() );
+ aDAVOptions.setHttpResponseStatusText( e.getData() );
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
+ m_nOptsCacheLifeNotFound );
}
break;
case SC_NOT_IMPLEMENTED:
@@ -3954,9 +3984,10 @@ void Content::getResourceOptions(
{
// OPTIONS method must be implemented in DAV
// resource is NON_DAV, or not advertising it
- SAL_WARN( "ucb.ucp.webdav","OPTIONS - SC_NOT_IMPLEMENTED or SC_METHOD_NOT_ALLOWED for URL <" << m_xIdentifier->getContentIdentifier() << ">" );
+ SAL_WARN( "ucb.ucp.webdav","OPTIONS - SC_NOT_IMPLEMENTED or SC_METHOD_NOT_ALLOWED for URL <" << m_xIdentifier->getContentIdentifier() << ">, HTTP error: "<< e.getStatus()
+ << ", '" << e.getData() << "'" );
// cache it, so OPTIONS won't be called again, this URL does not support it
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
m_nOptsCacheLifeNotImpl );
}
break;
@@ -3966,22 +3997,26 @@ void Content::getResourceOptions(
// instead of SC_NOT_IMPLEMENTED or SC_METHOD_NOT_ALLOWED.
// So check if this is an available resource, or a real 'Not Found' event.
sal_uInt32 nLifeTime = m_nOptsCacheLifeNotFound;
- if( isResourceAvailable( xEnv, rResAccess, rDAVOptions ) )
+ if( isResourceAvailable( xEnv, rResAccess, aDAVOptions ) )
{
+ SAL_WARN( "ucb.ucp.webdav", "OPTIONS - Got an SC_NOT_FOUND, but the URL <" << m_xIdentifier->getContentIdentifier() << "> resource exists" );
nLifeTime = m_nOptsCacheLifeNotImpl;
}
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
+ else
+ SAL_WARN( "ucb.ucp.webdav", "OPTIONS - SC_NOT_FOUND for URL <" << m_xIdentifier->getContentIdentifier() << ">" );
+
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
nLifeTime );
- SAL_WARN( "ucb.ucp.webdav", "OPTIONS - SC_NOT_FOUND for URL <" << m_xIdentifier->getContentIdentifier() << ">" );
}
break;
default:
{
- SAL_WARN( "ucb.ucp.webdav", "OPTIONS - DAV_HTTP_ERROR, for URL <" << m_xIdentifier->getContentIdentifier() << ">, HTTP error: "<< e.getStatus() );
- rDAVOptions.setHttpResponseStatusCode( e.getStatus() );
- rDAVOptions.setHttpResponseStatusText( e.getData() );
+ SAL_WARN( "ucb.ucp.webdav", "OPTIONS - DAV_HTTP_ERROR, for URL <" << m_xIdentifier->getContentIdentifier() << ">, HTTP error: "<< e.getStatus()
+ << ", '" << e.getData() << "'" );
+ aDAVOptions.setHttpResponseStatusCode( e.getStatus() );
+ aDAVOptions.setHttpResponseStatusText( e.getData() );
// cache it, so OPTIONS won't be called again, this URL does not support it
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
m_nOptsCacheLifeNotImpl );
}
break;
@@ -3996,13 +4031,14 @@ void Content::getResourceOptions(
{
SAL_WARN( "ucb.ucp.webdav","OPTIONS - General DAVException (or max DAV_HTTP_REDIRECT reached) for URL <" << m_xIdentifier->getContentIdentifier() << ">, DAV ExceptionCode: "
<< e.getError() << ", HTTP error: "<< e.getStatus() );
- aStaticDAVOptionsCache.addDAVOptions( rDAVOptions,
+ aStaticDAVOptionsCache.addDAVOptions( aDAVOptions,
m_nOptsCacheLifeNotImpl );
}
break;
}
}
}
+ rDAVOptions = aDAVOptions;
}
//static