7ae0f28687
Change-Id: I82a97841d4d02d6d4388be17f5b3c87bbf0c325f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161470 Tested-by: Jenkins Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
566 lines
16 KiB
C++
566 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <memory>
|
|
#include <com/sun/star/util/DateTime.hpp>
|
|
#include "CurlUri.hxx"
|
|
#include "DAVResource.hxx"
|
|
#include "DAVProperties.hxx"
|
|
#include "DateTimeHelper.hxx"
|
|
#include "webdavprovider.hxx"
|
|
#include "ContentProperties.hxx"
|
|
#include <o3tl/string_view.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
using namespace http_dav_ucp;
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
Property Mapping
|
|
|
|
=============================================================================
|
|
HTTP (entity header) WebDAV (property) UCB (property)
|
|
=============================================================================
|
|
|
|
Allow
|
|
Content-Encoding
|
|
Content-Language getcontentlanguage
|
|
Content-Length getcontentlength Size
|
|
Content-Location
|
|
Content-MD5
|
|
Content-Range
|
|
Content-Type getcontenttype MediaType
|
|
Expires
|
|
Last-Modified getlastmodified DateModified
|
|
creationdate DateCreated
|
|
resourcetype IsFolder,IsDocument,ContentType
|
|
displayname
|
|
ETag (actually getetag
|
|
a response header )
|
|
lockdiscovery
|
|
supportedlock
|
|
source
|
|
Title (always taken from URI)
|
|
|
|
=============================================================================
|
|
|
|
Important: HTTP headers will not be mapped to DAV properties; only to UCB
|
|
properties. (Content-Length,Content-Type,Last-Modified)
|
|
*/
|
|
|
|
|
|
// ContentProperties Implementation.
|
|
|
|
|
|
// static member!
|
|
uno::Any ContentProperties::m_aEmptyAny;
|
|
|
|
ContentProperties::ContentProperties( const DAVResource& rResource )
|
|
: m_xProps( new PropertyValueMap ),
|
|
m_bTrailingSlash( false )
|
|
{
|
|
assert(!rResource.uri.isEmpty() &&
|
|
"ContentProperties ctor - Empty resource URI!");
|
|
|
|
// Title
|
|
try
|
|
{
|
|
CurlUri const aURI( rResource.uri );
|
|
m_aEscapedTitle = aURI.GetPathBaseName();
|
|
|
|
(*m_xProps)[ OUString( "Title" ) ]
|
|
= PropertyValue(
|
|
uno::Any( aURI.GetPathBaseNameUnescaped() ), true );
|
|
}
|
|
catch ( DAVException const & )
|
|
{
|
|
(*m_xProps)[ OUString( "Title" ) ]
|
|
= PropertyValue(
|
|
uno::Any(
|
|
OUString( "*** unknown ***" ) ),
|
|
true );
|
|
}
|
|
|
|
for ( const auto& rProp : rResource.properties )
|
|
{
|
|
addProperty( rProp );
|
|
}
|
|
|
|
if ( rResource.uri.endsWith("/") )
|
|
m_bTrailingSlash = true;
|
|
}
|
|
|
|
|
|
ContentProperties::ContentProperties(
|
|
const OUString & rTitle, bool bFolder )
|
|
: m_xProps( new PropertyValueMap ),
|
|
m_bTrailingSlash( false )
|
|
{
|
|
(*m_xProps)[ OUString( "Title" ) ]
|
|
= PropertyValue( uno::Any( rTitle ), true );
|
|
(*m_xProps)[ OUString( "IsFolder" ) ]
|
|
= PropertyValue( uno::Any( bFolder ), true );
|
|
(*m_xProps)[ OUString( "IsDocument" ) ]
|
|
= PropertyValue( uno::Any( bool( !bFolder ) ), true );
|
|
}
|
|
|
|
|
|
ContentProperties::ContentProperties( const OUString & rTitle )
|
|
: m_xProps( new PropertyValueMap ),
|
|
m_bTrailingSlash( false )
|
|
{
|
|
(*m_xProps)[ OUString( "Title" ) ]
|
|
= PropertyValue( uno::Any( rTitle ), true );
|
|
}
|
|
|
|
|
|
ContentProperties::ContentProperties()
|
|
: m_xProps( new PropertyValueMap ),
|
|
m_bTrailingSlash( false )
|
|
{
|
|
}
|
|
|
|
|
|
ContentProperties::ContentProperties( const ContentProperties & rOther )
|
|
: m_aEscapedTitle( rOther.m_aEscapedTitle ),
|
|
m_xProps( rOther.m_xProps
|
|
? new PropertyValueMap( *rOther.m_xProps )
|
|
: new PropertyValueMap ),
|
|
m_bTrailingSlash( rOther.m_bTrailingSlash )
|
|
{
|
|
}
|
|
|
|
|
|
bool ContentProperties::contains( const OUString & rName ) const
|
|
{
|
|
if ( get( rName ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
const uno::Any & ContentProperties::getValue(
|
|
const OUString & rName ) const
|
|
{
|
|
const PropertyValue * pProp = get( rName );
|
|
if ( pProp )
|
|
return pProp->value();
|
|
else
|
|
return m_aEmptyAny;
|
|
}
|
|
|
|
|
|
const PropertyValue * ContentProperties::get(
|
|
const OUString & rName ) const
|
|
{
|
|
PropertyValueMap::const_iterator it = m_xProps->find( rName );
|
|
const PropertyValueMap::const_iterator end = m_xProps->end();
|
|
|
|
if ( it == end )
|
|
{
|
|
it = std::find_if(m_xProps->cbegin(), end,
|
|
[&rName](const PropertyValueMap::value_type& rEntry) {
|
|
return rEntry.first.equalsIgnoreAsciiCase( rName );
|
|
});
|
|
if ( it != end )
|
|
return &(*it).second;
|
|
|
|
return nullptr;
|
|
}
|
|
else
|
|
return &(*it).second;
|
|
}
|
|
|
|
|
|
// static
|
|
void ContentProperties::UCBNamesToDAVNames(
|
|
const uno::Sequence< beans::Property > & rProps,
|
|
std::vector< OUString > & propertyNames )
|
|
{
|
|
|
|
// Assemble list of DAV properties to obtain from server.
|
|
// Append DAV properties needed to obtain requested UCB props.
|
|
|
|
|
|
// DAV UCB
|
|
// creationdate <- DateCreated
|
|
// getlastmodified <- DateModified
|
|
// getcontenttype <- MediaType
|
|
// getcontentlength <- Size
|
|
// resourcetype <- IsFolder, IsDocument, ContentType
|
|
// (taken from URI) <- Title
|
|
|
|
bool bCreationDate = false;
|
|
bool bLastModified = false;
|
|
bool bContentType = false;
|
|
bool bContentLength = false;
|
|
bool bResourceType = false;
|
|
|
|
sal_Int32 nCount = rProps.getLength();
|
|
for ( sal_Int32 n = 0; n < nCount; ++n )
|
|
{
|
|
const beans::Property & rProp = rProps[ n ];
|
|
|
|
if ( rProp.Name == "Title" )
|
|
{
|
|
// Title is always obtained from resource's URI.
|
|
continue;
|
|
}
|
|
else if ( rProp.Name == "DateCreated" ||
|
|
( rProp.Name == DAVProperties::CREATIONDATE ) )
|
|
{
|
|
if ( !bCreationDate )
|
|
{
|
|
propertyNames.push_back( DAVProperties::CREATIONDATE );
|
|
bCreationDate = true;
|
|
}
|
|
}
|
|
else if ( rProp.Name == "DateModified" ||
|
|
( rProp.Name == DAVProperties::GETLASTMODIFIED ) )
|
|
{
|
|
if ( !bLastModified )
|
|
{
|
|
propertyNames.push_back(
|
|
DAVProperties::GETLASTMODIFIED );
|
|
bLastModified = true;
|
|
}
|
|
}
|
|
else if ( rProp.Name == "MediaType" ||
|
|
( rProp.Name == DAVProperties::GETCONTENTTYPE ) )
|
|
{
|
|
if ( !bContentType )
|
|
{
|
|
propertyNames.push_back(
|
|
DAVProperties::GETCONTENTTYPE );
|
|
bContentType = true;
|
|
}
|
|
}
|
|
else if ( rProp.Name == "Size" ||
|
|
( rProp.Name == DAVProperties::GETCONTENTLENGTH ) )
|
|
{
|
|
if ( !bContentLength )
|
|
{
|
|
propertyNames.push_back(
|
|
DAVProperties::GETCONTENTLENGTH );
|
|
bContentLength = true;
|
|
}
|
|
}
|
|
else if ( rProp.Name == "ContentType" ||
|
|
rProp.Name == "IsDocument" ||
|
|
rProp.Name == "IsFolder" ||
|
|
( rProp.Name == DAVProperties::RESOURCETYPE ) )
|
|
{
|
|
if ( !bResourceType )
|
|
{
|
|
propertyNames.push_back( DAVProperties::RESOURCETYPE );
|
|
bResourceType = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
propertyNames.push_back( rProp.Name );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// static
|
|
void ContentProperties::UCBNamesToHTTPNames(
|
|
const uno::Sequence< beans::Property > & rProps,
|
|
std::vector< OUString > & propertyNames )
|
|
{
|
|
|
|
// Assemble list of HTTP header names to obtain from server.
|
|
// Append HTTP headers needed to obtain requested UCB props.
|
|
|
|
|
|
// HTTP UCB
|
|
// Last-Modified <- DateModified
|
|
// Content-Type <- MediaType
|
|
// Content-Length <- Size
|
|
|
|
sal_Int32 nCount = rProps.getLength();
|
|
for ( sal_Int32 n = 0; n < nCount; ++n )
|
|
{
|
|
const beans::Property & rProp = rProps[ n ];
|
|
|
|
if ( rProp.Name == "DateModified" )
|
|
{
|
|
propertyNames.emplace_back("Last-Modified");
|
|
}
|
|
else if ( rProp.Name == "MediaType" )
|
|
{
|
|
propertyNames.emplace_back("Content-Type");
|
|
}
|
|
else if ( rProp.Name == "Size" )
|
|
{
|
|
propertyNames.emplace_back("Content-Length");
|
|
}
|
|
else
|
|
{
|
|
propertyNames.emplace_back(rProp.Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool ContentProperties::containsAllNames(
|
|
const uno::Sequence< beans::Property >& rProps,
|
|
std::vector< OUString > & rNamesNotContained ) const
|
|
{
|
|
rNamesNotContained.clear();
|
|
|
|
sal_Int32 nCount = rProps.getLength();
|
|
for ( sal_Int32 n = 0; n < nCount; ++n )
|
|
{
|
|
const OUString & rName = rProps[ n ].Name;
|
|
if ( !contains( rName ) )
|
|
{
|
|
// Not found.
|
|
rNamesNotContained.push_back( rName );
|
|
}
|
|
}
|
|
|
|
return rNamesNotContained.empty();
|
|
}
|
|
|
|
|
|
void ContentProperties::addProperties(
|
|
const std::vector< OUString > & rProps,
|
|
const ContentProperties & rContentProps )
|
|
{
|
|
for ( const OUString & rName : rProps )
|
|
{
|
|
if ( !contains( rName ) ) // ignore duplicates
|
|
{
|
|
const PropertyValue * pProp = rContentProps.get( rName );
|
|
if ( pProp )
|
|
{
|
|
// Add it.
|
|
addProperty( rName, pProp->value(), pProp->isCaseSensitive() );
|
|
}
|
|
else
|
|
{
|
|
addProperty( rName, uno::Any(), false );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ContentProperties::addProperty( const DAVPropertyValue & rProp )
|
|
{
|
|
addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive );
|
|
}
|
|
|
|
|
|
void ContentProperties::addProperty( const OUString & rName,
|
|
const css::uno::Any & rValue,
|
|
bool bIsCaseSensitive )
|
|
{
|
|
if ( rName == DAVProperties::CREATIONDATE )
|
|
{
|
|
// Map DAV:creationdate to UCP:DateCreated
|
|
OUString aValue;
|
|
rValue >>= aValue;
|
|
util::DateTime aDate;
|
|
DateTimeHelper::convert( aValue, aDate );
|
|
|
|
(*m_xProps)[ OUString( "DateCreated" ) ]
|
|
= PropertyValue( uno::Any( aDate ), true );
|
|
}
|
|
// else if ( rName.equals( DAVProperties::DISPLAYNAME ) )
|
|
// {
|
|
// }
|
|
// else if ( rName.equals( DAVProperties::GETCONTENTLANGUAGE ) )
|
|
// {
|
|
// }
|
|
else if ( rName == DAVProperties::GETCONTENTLENGTH )
|
|
{
|
|
// Map DAV:getcontentlength to UCP:Size
|
|
OUString aValue;
|
|
rValue >>= aValue;
|
|
|
|
(*m_xProps)[ OUString( "Size" ) ]
|
|
= PropertyValue( uno::Any( aValue.toInt64() ), true );
|
|
}
|
|
else if ( rName.equalsIgnoreAsciiCase( "Content-Length" ) )
|
|
{
|
|
// Do NOT map Content-Length entity header to DAV:getcontentlength!
|
|
// Only DAV resources have this property.
|
|
|
|
// Map Content-Length entity header to UCP:Size
|
|
OUString aValue;
|
|
rValue >>= aValue;
|
|
|
|
(*m_xProps)[ OUString( "Size" ) ]
|
|
= PropertyValue( uno::Any( aValue.toInt64() ), true );
|
|
}
|
|
else if ( rName == DAVProperties::GETCONTENTTYPE )
|
|
{
|
|
// Map DAV:getcontenttype to UCP:MediaType (1:1)
|
|
(*m_xProps)[ OUString( "MediaType" ) ]
|
|
= PropertyValue( rValue, true );
|
|
}
|
|
else if ( rName.equalsIgnoreAsciiCase( "Content-Type" ) )
|
|
{
|
|
// Do NOT map Content-Type entity header to DAV:getcontenttype!
|
|
// Only DAV resources have this property.
|
|
|
|
// Map DAV:getcontenttype to UCP:MediaType (1:1)
|
|
(*m_xProps)[ OUString( "MediaType" ) ]
|
|
= PropertyValue( rValue, true );
|
|
}
|
|
// else if ( rName.equals( DAVProperties::GETETAG ) )
|
|
// {
|
|
// }
|
|
else if ( rName == DAVProperties::GETLASTMODIFIED )
|
|
{
|
|
// Map the DAV:getlastmodified entity header to UCP:DateModified
|
|
OUString aValue;
|
|
rValue >>= aValue;
|
|
util::DateTime aDate;
|
|
DateTimeHelper::convert( aValue, aDate );
|
|
|
|
(*m_xProps)[ OUString( "DateModified" ) ]
|
|
= PropertyValue( uno::Any( aDate ), true );
|
|
}
|
|
else if ( rName.equalsIgnoreAsciiCase( "Last-Modified" ) )
|
|
{
|
|
// Do not map Last-Modified entity header to DAV:getlastmodified!
|
|
// Only DAV resources have this property.
|
|
|
|
// Map the Last-Modified entity header to UCP:DateModified
|
|
OUString aValue;
|
|
rValue >>= aValue;
|
|
util::DateTime aDate;
|
|
DateTimeHelper::convert( aValue, aDate );
|
|
|
|
(*m_xProps)[ OUString( "DateModified" ) ]
|
|
= PropertyValue( uno::Any( aDate ), true );
|
|
}
|
|
// else if ( rName.equals( DAVProperties::LOCKDISCOVERY ) )
|
|
// {
|
|
// }
|
|
else if ( rName == DAVProperties::RESOURCETYPE )
|
|
{
|
|
OUString aValue;
|
|
rValue >>= aValue;
|
|
|
|
// Map DAV:resourcetype to UCP:IsFolder, UCP:IsDocument, UCP:ContentType
|
|
bool bFolder =
|
|
aValue.equalsIgnoreAsciiCase( "collection" );
|
|
|
|
(*m_xProps)[ OUString( "IsFolder" ) ]
|
|
= PropertyValue( uno::Any( bFolder ), true );
|
|
(*m_xProps)[ OUString( "IsDocument" ) ]
|
|
= PropertyValue( uno::Any( bool( !bFolder ) ), true );
|
|
(*m_xProps)[ OUString( "ContentType" ) ]
|
|
= PropertyValue( uno::Any( bFolder
|
|
? WEBDAV_COLLECTION_TYPE
|
|
: WEBDAV_CONTENT_TYPE ), true );
|
|
}
|
|
// else if ( rName.equals( DAVProperties::SUPPORTEDLOCK ) )
|
|
// {
|
|
// }
|
|
|
|
// Save property.
|
|
(*m_xProps)[ rName ] = PropertyValue( rValue, bIsCaseSensitive );
|
|
}
|
|
|
|
|
|
// CachableContentProperties Implementation.
|
|
|
|
|
|
namespace
|
|
{
|
|
bool isCachable( std::u16string_view rName, bool isCaseSensitive )
|
|
{
|
|
const OUString aNonCachableProps [] =
|
|
{
|
|
DAVProperties::LOCKDISCOVERY,
|
|
|
|
DAVProperties::GETETAG,
|
|
OUString( "ETag" ),
|
|
|
|
OUString( "DateModified" ),
|
|
OUString( "Last-Modified" ),
|
|
DAVProperties::GETLASTMODIFIED,
|
|
|
|
OUString( "Size" ),
|
|
OUString( "Content-Length" ),
|
|
DAVProperties::GETCONTENTLENGTH,
|
|
|
|
OUString( "Date" )
|
|
};
|
|
|
|
for ( sal_uInt32 n = 0;
|
|
n < ( sizeof( aNonCachableProps )
|
|
/ sizeof( aNonCachableProps[ 0 ] ) );
|
|
++n )
|
|
{
|
|
if ( isCaseSensitive )
|
|
{
|
|
if ( rName == aNonCachableProps[ n ] )
|
|
return false;
|
|
}
|
|
else
|
|
if ( o3tl::equalsIgnoreAsciiCase( rName, aNonCachableProps[ n ] ) )
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
CachableContentProperties::CachableContentProperties(
|
|
const ContentProperties & rProps )
|
|
{
|
|
addProperties( rProps );
|
|
}
|
|
|
|
|
|
void CachableContentProperties::addProperties(
|
|
const ContentProperties & rProps )
|
|
{
|
|
const std::unique_ptr< PropertyValueMap > & props = rProps.getProperties();
|
|
|
|
for ( const auto& rProp : *props )
|
|
{
|
|
if ( isCachable( rProp.first, rProp.second.isCaseSensitive() ) )
|
|
m_aProps.addProperty( rProp.first,
|
|
rProp.second.value(),
|
|
rProp.second.isCaseSensitive() );
|
|
}
|
|
}
|
|
|
|
|
|
void CachableContentProperties::addProperties(
|
|
const std::vector< DAVPropertyValue > & rProps )
|
|
{
|
|
for ( const auto& rProp : rProps )
|
|
{
|
|
if ( isCachable( rProp.Name, rProp.IsCaseSensitive ) )
|
|
m_aProps.addProperty( rProp );
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|