diff options
Diffstat (limited to 'ucb')
-rw-r--r-- | ucb/source/ucp/webdav-curl/webdavcontent.cxx | 271 | ||||
-rw-r--r-- | ucb/source/ucp/webdav-curl/webdavcontentcaps.cxx | 9 |
2 files changed, 172 insertions, 108 deletions
diff --git a/ucb/source/ucp/webdav-curl/webdavcontent.cxx b/ucb/source/ucp/webdav-curl/webdavcontent.cxx index 974867e78685..75f9d0ca2ae9 100644 --- a/ucb/source/ucp/webdav-curl/webdavcontent.cxx +++ b/ucb/source/ucp/webdav-curl/webdavcontent.cxx @@ -1260,6 +1260,45 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues( return uno::Reference<sdbc::XRow>(xRow); } +namespace { +void GetPropsUsingHeadRequest(DAVResource& resource, + const std::unique_ptr< DAVResourceAccess >& xResAccess, + const std::vector< OUString >& aHTTPNames, + const uno::Reference< ucb::XCommandEnvironment >& xEnv) +{ + if (!aHTTPNames.empty()) + { + DAVOptions aDAVOptions; + OUString aTargetURL = xResAccess->getURL(); + // retrieve the cached options if any + aStaticDAVOptionsCache.getDAVOptions(aTargetURL, aDAVOptions); + + // clean cached value of PROPFIND property names + // PROPPATCH can change them + Content::removeCachedPropertyNames(aTargetURL); + // test if HEAD allowed, if not, throw, should be catched immediately + // SC_GONE used internally by us, see comment in Content::getPropertyValues + // in the catch scope + if (aDAVOptions.getHttpResponseStatusCode() != SC_GONE && + !aDAVOptions.isHeadAllowed()) + { + throw DAVException(DAVException::DAV_HTTP_ERROR, "405 Not Implemented", SC_METHOD_NOT_ALLOWED); + } + // if HEAD is enabled on this site + // check if there is a relevant HTTP response status code cached + if (aDAVOptions.getHttpResponseStatusCode() != SC_NONE) + { + // throws exception as if there was a server error, a DAV exception + throw DAVException(DAVException::DAV_HTTP_ERROR, + aDAVOptions.getHttpResponseStatusText(), + aDAVOptions.getHttpResponseStatusCode()); + // Unreachable + } + + xResAccess->HEAD(aHTTPNames, resource, xEnv); + } +} +} uno::Reference< sdbc::XRow > Content::getPropertyValues( const uno::Sequence< beans::Property >& rProperties, @@ -1449,117 +1488,89 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues( aHeaderNames.push_back( "Content-Type" ); } - if ( !aHeaderNames.empty() ) + if (!aHeaderNames.empty()) try { - DAVOptions aDAVOptions; - OUString aTargetURL = xResAccess->getURL(); - // retrieve the cached options if any - aStaticDAVOptionsCache.getDAVOptions( aTargetURL, aDAVOptions ); - try - { - DAVResource resource; - // clean cached value of PROPFIND property names - // PROPPATCH can change them - removeCachedPropertyNames( aTargetURL ); - // test if HEAD allowed, if not, throw, will be catched immediately - // 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", SC_METHOD_NOT_ALLOWED ); - } - // if HEAD is enabled on this site - // check if there is a relevant HTTP response status code cached - if ( aDAVOptions.getHttpResponseStatusCode() != SC_NONE ) - { - // throws exception as if there was a server error, a DAV exception - throw DAVException( DAVException::DAV_HTTP_ERROR, - aDAVOptions.getHttpResponseStatusText(), - aDAVOptions.getHttpResponseStatusCode() ); - // Unreachable - } - - xResAccess->HEAD( aHeaderNames, resource, xEnv ); - m_bDidGetOrHead = true; + DAVResource resource; + GetPropsUsingHeadRequest(resource, xResAccess, aHeaderNames, xEnv); + m_bDidGetOrHead = true; - if (xProps) - xProps->addProperties( - aMissingProps, - ContentProperties( resource ) ); - else - xProps.reset ( new ContentProperties( resource ) ); + if (xProps) + xProps->addProperties( + aMissingProps, + ContentProperties( resource ) ); + else + xProps.reset ( new ContentProperties( resource ) ); - if ( m_eResourceType == NON_DAV ) - xProps->addProperties( aMissingProps, - ContentProperties( - aUnescapedTitle, - false ) ); - } - catch ( DAVException const & e ) + if (m_eResourceType == NON_DAV) + xProps->addProperties(aMissingProps, + ContentProperties( + aUnescapedTitle, + false)); + } + catch ( DAVException const & e ) + { + // non "general-purpose servers" may not support HEAD requests + // see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 + // In this case, perform a partial GET only to get the header info + // vid. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 + // WARNING if the server does not support partial GETs, + // the GET will transfer the whole content + bool bError = true; + DAVException aLastException = e; + OUString aTargetURL = xResAccess->getURL(); + + if ( e.getError() == DAVException::DAV_HTTP_ERROR ) { - // non "general-purpose servers" may not support HEAD requests - // see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 - // In this case, perform a partial GET only to get the header info - // vid. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 - // WARNING if the server does not support partial GETs, - // the GET will transfer the whole content - bool bError = true; - DAVException aLastException = e; - - if ( e.getError() == DAVException::DAV_HTTP_ERROR ) + // According to the spec. the origin server SHOULD return + // * 405 (Method Not Allowed): + // the method is known but not allowed for the requested resource + // * 501 (Not Implemented): + // the method is unrecognized or not implemented + // * 404 (SC_NOT_FOUND) + // is for google-code server and for MS IIS 10.0 Web server + // when only GET is enabled + if ( aLastException.getStatus() == SC_NOT_IMPLEMENTED || + aLastException.getStatus() == SC_METHOD_NOT_ALLOWED || + aLastException.getStatus() == SC_NOT_FOUND ) { - // According to the spec. the origin server SHOULD return - // * 405 (Method Not Allowed): - // the method is known but not allowed for the requested resource - // * 501 (Not Implemented): - // the method is unrecognized or not implemented - // * 404 (SC_NOT_FOUND) - // is for google-code server and for MS IIS 10.0 Web server - // when only GET is enabled - if ( aLastException.getStatus() == SC_NOT_IMPLEMENTED || - aLastException.getStatus() == SC_METHOD_NOT_ALLOWED || - 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, - aHeaderNames, - xResAccess, - xProps, - xEnv ); - m_bDidGetOrHead = !bError; - } + SAL_WARN( "ucb.ucp.webdav", "HEAD probably not implemented: fall back to a partial GET" ); + aStaticDAVOptionsCache.setHeadAllowed( aTargetURL, false ); + lcl_sendPartialGETRequest( bError, + aLastException, + aMissingProps, + aHeaderNames, + xResAccess, + xProps, + xEnv ); + m_bDidGetOrHead = !bError; } + } - 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.addDAVOptions( aDAVOptionsException, - m_nOptsCacheLifeNotFound ); + 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.addDAVOptions( aDAVOptionsException, + m_nOptsCacheLifeNotFound ); - if ( !shouldAccessNetworkAfterException( aLastException ) ) - { - cancelCommandExecution( aLastException, xEnv ); - // unreachable - } + if ( !shouldAccessNetworkAfterException( aLastException ) ) + { + cancelCommandExecution( aLastException, xEnv ); + // unreachable } } } @@ -1642,6 +1653,22 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues( uno::makeAny( aDate ), true ); } + // If WebDAV didn't return the resource type, assume default + // This happens e.g. for lists exported by SharePoint + else if ( (*it) == "IsFolder" ) + { + xProps->addProperty( + (*it), + uno::makeAny( false ), + true ); + } + else if ( (*it) == "IsDocument" ) + { + xProps->addProperty( + (*it), + uno::makeAny( true ), + true ); + } } } @@ -2981,8 +3008,6 @@ Content::ResourceType Content::resourceTypeForLocks( std::unique_ptr< ContentProperties > xProps; if (m_xCachedProps) { - std::unique_ptr< ContentProperties > xCachedProps; - xCachedProps.reset( new ContentProperties(*m_xCachedProps) ); uno::Sequence< ucb::LockEntry > aSupportedLocks; if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK ) >>= aSupportedLocks ) //get the cached value for supportedlock @@ -3073,6 +3098,42 @@ Content::ResourceType Content::resourceTypeForLocks( } } } + else + { + // PROPFIND failed; check if HEAD contains Content-Disposition: attachment (RFC1806, HTTP/1.1 19.5.1), + // which supposedly means no lock for the resource (happens e.g. with SharePoint exported lists) + OUString sContentDisposition; + // First, check cached properties + if (m_xCachedProps) + { + if ((m_xCachedProps->getValue("Content-Disposition") >>= sContentDisposition) + && sContentDisposition.startsWithIgnoreAsciiCase("attachment")) + { + eResourceTypeForLocks = DAV_NOLOCK; + wasSupportedlockFound = true; + } + } + // If no data in cache, try HEAD request + if (sContentDisposition.isEmpty() && !m_bDidGetOrHead) try + { + DAVResource resource; + GetPropsUsingHeadRequest(resource, rResAccess, {"Content-Disposition"}, Environment); + m_bDidGetOrHead = true; + for (const auto& it : resource.properties) + { + if (it.Name.equalsIgnoreAsciiCase("Content-Disposition")) + { + if ((it.Value >>= sContentDisposition) && sContentDisposition.equalsIgnoreAsciiCase("attachment")) + { + eResourceTypeForLocks = DAV_NOLOCK; + wasSupportedlockFound = true; + } + break; + } + } + } + catch (...){} + } // 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 diff --git a/ucb/source/ucp/webdav-curl/webdavcontentcaps.cxx b/ucb/source/ucp/webdav-curl/webdavcontentcaps.cxx index e3ece1b3d8fc..f4bef01c631b 100644 --- a/ucb/source/ucp/webdav-curl/webdavcontentcaps.cxx +++ b/ucb/source/ucp/webdav-curl/webdavcontentcaps.cxx @@ -319,10 +319,13 @@ uno::Sequence< beans::Property > Content::getProperties( props = aPropsNames.getPropertiesNames(); } - // Note: vector always contains exactly one resource info, because + // Note: vector should contain exactly one resource info, because // we used a depth of DAVZERO for PROPFIND. - aPropSet.insert( (*props.begin()).properties.begin(), - (*props.begin()).properties.end() ); + if (props.size() == 1) + { + aPropSet.insert( (*props.begin()).properties.begin(), + (*props.begin()).properties.end() ); + } } catch ( DAVException const & ) { |