office-gobmx/ucb/source/ucp/webdav-curl/webdavresponseparser.cxx
Michael Stahl 65362d63b9 ucb: webdav-curl: fix handling of non-standard properties
Sharepoint uses properties like these:

"http://schemas.microsoft.com/repl/resourcetag"
"urn:schemas-microsoft-com:Win32CreationTime"

They aren't standard and don't match our own ucbprops namespace, and it
looks like they should be handled by an encoding to a name like
"<prop:Win32CreationTime xmlns:prop=\"urn:schemas-microsoft-com:\">"

Unfortunately WebDAVResponseParser::endElement() didn't do that when
handling a PROPFIND reply to get the property names.

This causes a crash when all properties are copied in
UniversalContentBroker::globalTransfer(), which is called by
SfxMedium::DoBackup_Impl() when the setting
"/org.openoffice.Office.Common/Save/Document/CreateBackup"
is in effect.

Change-Id: I2d6480bfd2f828b6e7fc431ba4b333d95ec12718
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133769
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
2022-05-04 10:22:06 +02:00

1001 lines
42 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 "webdavresponseparser.hxx"
#include "DAVProperties.hxx"
#include "UCBDeadPropertyValue.hxx"
#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/implbase.hxx>
#include <com/sun/star/xml/sax/Parser.hpp>
#include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <com/sun/star/ucb/LockEntry.hpp>
#include <com/sun/star/ucb/LockScope.hpp>
#include <com/sun/star/ucb/LockType.hpp>
#include <com/sun/star/ucb/Lock.hpp>
#include <map>
#include <unordered_map>
#include <rtl/ref.hxx>
#include <rtl/uri.hxx>
#include <sal/log.hxx>
#include <o3tl/string_view.hxx>
using namespace com::sun::star;
using namespace http_dav_ucp;
// WebDAVNamespace enum and StringToEnum converter
namespace
{
enum WebDAVNamespace
{
WebDAVNamespace_unknown = 0,
WebDAVNamespace_DAV,
WebDAVNamespace_ucb_openoffice_org_dav_props,
WebDAVNamespace_last
};
WebDAVNamespace StrToWebDAVNamespace(::std::u16string_view rStr)
{
if (rStr == u"DAV:")
{
return WebDAVNamespace_DAV;
}
else if (rStr == u"http://ucb.openoffice.org/dav/props/")
{
return WebDAVNamespace_ucb_openoffice_org_dav_props;
}
return WebDAVNamespace_unknown;
}
} // end of anonymous namespace
// WebDAVName enum and StringToEnum converter using unordered_map
namespace
{
enum WebDAVName
{
WebDAVName_unknown = 0,
WebDAVName_activelock,
WebDAVName_lockdiscovery,
WebDAVName_multistatus,
WebDAVName_response,
WebDAVName_href,
WebDAVName_propstat,
WebDAVName_prop,
WebDAVName_resourcetype,
WebDAVName_collection,
WebDAVName_getcontenttype,
WebDAVName_supportedlock,
WebDAVName_lockentry,
WebDAVName_lockscope,
WebDAVName_depth,
WebDAVName_locktoken,
WebDAVName_exclusive,
WebDAVName_locktype,
WebDAVName_owner,
WebDAVName_timeout,
WebDAVName_write,
WebDAVName_shared,
WebDAVName_status,
WebDAVName_getlastmodified,
WebDAVName_creationdate,
WebDAVName_getcontentlength,
WebDAVName_type,
WebDAVName_value,
WebDAVName_ucbprop,
WebDAVName_last
};
WebDAVName StrToWebDAVName(const OUString& rStr)
{
typedef std::unordered_map< OUString, WebDAVName > WebDAVNameMapper;
typedef std::pair< OUString, WebDAVName > WebDAVNameValueType;
static WebDAVNameMapper aWebDAVNameMapperList;
if(aWebDAVNameMapperList.empty())
{
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("activelock"), WebDAVName_activelock));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("lockdiscovery"), WebDAVName_lockdiscovery));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("multistatus"), WebDAVName_multistatus));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("response"), WebDAVName_response));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("href"), WebDAVName_href));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("propstat"), WebDAVName_propstat));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("prop"), WebDAVName_prop));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("resourcetype"), WebDAVName_resourcetype));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("collection"), WebDAVName_collection));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("getcontenttype"), WebDAVName_getcontenttype));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("supportedlock"), WebDAVName_supportedlock));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("lockentry"), WebDAVName_lockentry));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("lockscope"), WebDAVName_lockscope));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("depth"), WebDAVName_depth));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("locktoken"), WebDAVName_locktoken));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("exclusive"), WebDAVName_exclusive));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("locktype"), WebDAVName_locktype));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("owner"), WebDAVName_owner));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("timeout"), WebDAVName_timeout));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("write"), WebDAVName_write));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("shared"), WebDAVName_shared));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("status"), WebDAVName_status));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("getlastmodified"), WebDAVName_getlastmodified));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("creationdate"), WebDAVName_creationdate));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("getcontentlength"), WebDAVName_getcontentlength));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("type"), WebDAVName_type));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("value"), WebDAVName_value));
aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("ucbprop"), WebDAVName_ucbprop));
}
const WebDAVNameMapper::const_iterator aResult(aWebDAVNameMapperList.find(rStr));
if(aResult == aWebDAVNameMapperList.end())
{
return WebDAVName_unknown;
}
else
{
return aResult->second;
}
}
} // end of anonymous namespace
// WebDAVContext, holding information for each start/endElement pair
namespace
{
typedef std::map< OUString, OUString > NamespaceMap;
class WebDAVContext
{
private:
WebDAVContext* mpParent;
NamespaceMap maNamespaceMap;
OUString maWhiteSpace;
OUString maNamespace;
OUString maName;
WebDAVNamespace maWebDAVNamespace;
WebDAVName maWebDAVName;
// local helpers
void parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs);
OUString mapNamespaceToken(const OUString& rToken) const;
void splitName(const OUString& rSource);
public:
WebDAVContext(WebDAVContext* pParent, const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs);
WebDAVContext* getParent() const { return mpParent; }
OUString& getWhiteSpace() { return maWhiteSpace; }
void setWhiteSpace(const OUString& rNew) { maWhiteSpace = rNew; }
const OUString& getNamespace() const { return maNamespace; }
const OUString& getName() const { return maName; }
const WebDAVNamespace& getWebDAVNamespace() const { return maWebDAVNamespace; }
const WebDAVName& getWebDAVName() const { return maWebDAVName; }
};
void WebDAVContext::parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs)
{
const sal_Int16 nAttributes(xAttribs->getLength());
for(sal_Int16 a(0); a < nAttributes; a++)
{
const OUString aName(xAttribs->getNameByIndex(a));
const sal_Int32 nLen(aName.getLength());
if(nLen)
{
if(aName.startsWith("xmlns"))
{
const sal_Int32 nIndex(aName.indexOf(':', 0));
if(-1 != nIndex && nIndex + 1 < nLen)
{
const OUString aToken(aName.copy(nIndex + 1));
maNamespaceMap.emplace(aToken, xAttribs->getValueByIndex(a));
}
}
}
}
}
OUString WebDAVContext::mapNamespaceToken(const OUString& rToken) const
{
NamespaceMap::const_iterator iter = maNamespaceMap.find(rToken);
if(maNamespaceMap.end() == iter)
{
if(getParent())
{
return getParent()->mapNamespaceToken(rToken);
}
else
{
return rToken;
}
}
else
{
return (*iter).second;
}
}
void WebDAVContext::splitName(const OUString& rSource)
{
const sal_Int32 nLen(rSource.getLength());
maNamespace.clear();
maName = rSource;
if(nLen)
{
const sal_Int32 nIndex(rSource.indexOf(':', 0));
if(nIndex > 0 && ((nIndex + 1) < nLen))
{
maNamespace = mapNamespaceToken(rSource.copy(0, nIndex));
maName = rSource.copy(nIndex + 1);
}
}
}
WebDAVContext::WebDAVContext(WebDAVContext* pParent, const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs)
: mpParent(pParent),
maNamespaceMap(),
maWhiteSpace(),
maNamespace(),
maName(),
maWebDAVNamespace(WebDAVNamespace_unknown),
maWebDAVName(WebDAVName_unknown)
{
const sal_Int16 nAttributes(xAttribs->getLength());
if(nAttributes)
{
// parse evtl. namespace entries
parseForNamespaceTokens(xAttribs);
}
// split name to namespace and name
splitName(aName);
// evaluate enums for namespace and name
maWebDAVNamespace = StrToWebDAVNamespace(maNamespace);
maWebDAVName = StrToWebDAVName(maName);
}
} // end of anonymous namespace
// the Xml parser itself
namespace
{
enum WebDAVResponseParserMode
{
WebDAVResponseParserMode_PropFind = 0,
WebDAVResponseParserMode_PropName,
WebDAVResponseParserMode_Lock
};
class WebDAVResponseParser : public cppu::WeakImplHelper< css::xml::sax::XDocumentHandler >
{
private:
std::vector< ucb::Lock > maResult_Lock;
std::vector< http_dav_ucp::DAVResource > maResult_PropFind;
std::vector< http_dav_ucp::DAVResourceInfo > maResult_PropName;
WebDAVContext* mpContext;
OUString maHref;
OUString maStatus;
OUString m_UCBType;
OUString m_UCBValue;
std::vector< http_dav_ucp::DAVPropertyValue > maResponseProperties;
std::vector< http_dav_ucp::DAVPropertyValue > maPropStatProperties;
std::vector< OUString > maResponseNames;
std::vector< OUString > maPropStatNames;
uno::Sequence< ucb::LockEntry > maLockEntries;
ucb::LockScope maLockScope;
ucb::LockType maLockType;
ucb::Lock maLock;
WebDAVResponseParserMode meWebDAVResponseParserMode;
bool mbResourceTypeCollection : 1;
bool mbLockScopeSet : 1;
bool mbLockTypeSet : 1;
// local helpers
bool whitespaceIsAvailable() const
{
return mpContext && mpContext->getWhiteSpace().getLength();
}
bool hasParent(WebDAVName aWebDAVName) const
{
return mpContext && mpContext->getParent() && aWebDAVName == mpContext->getParent()->getWebDAVName();
}
bool propertyIsReady() const
{
return hasParent(WebDAVName_prop) && whitespaceIsAvailable();
}
bool isCollectingProperties() const
{
return WebDAVResponseParserMode_PropFind == meWebDAVResponseParserMode;
}
bool isCollectingPropNames() const
{
return WebDAVResponseParserMode_PropName == meWebDAVResponseParserMode;
}
bool collectThisPropertyAsName() const
{
return isCollectingPropNames() && hasParent(WebDAVName_prop);
}
void pop_context()
{
if(mpContext)
{
WebDAVContext* pTemp = mpContext;
mpContext = mpContext->getParent();
delete pTemp;
}
else
{
SAL_WARN( "ucb.ucp.webdav", "Parser context pop without context (!)");
}
}
public:
explicit WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode);
virtual ~WebDAVResponseParser() override;
// Methods XDocumentHandler
virtual void SAL_CALL startDocument( ) override;
virtual void SAL_CALL endDocument( ) override;
virtual void SAL_CALL startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) override;
virtual void SAL_CALL endElement( const OUString& aName ) override;
virtual void SAL_CALL characters( const OUString& aChars ) override;
virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override;
virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override;
virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) override;
const std::vector< ucb::Lock >& getResult_Lock() const { return maResult_Lock; }
const std::vector< http_dav_ucp::DAVResource >& getResult_PropFind() const { return maResult_PropFind; }
const std::vector< http_dav_ucp::DAVResourceInfo >& getResult_PropName() const { return maResult_PropName; }
};
WebDAVResponseParser::WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode)
: maResult_PropFind(),
maResult_PropName(),
mpContext(nullptr),
maHref(),
maStatus(),
maResponseProperties(),
maPropStatProperties(),
maResponseNames(),
maPropStatNames(),
maLockEntries(),
maLockScope(ucb::LockScope_EXCLUSIVE),
maLockType(ucb::LockType_WRITE),
meWebDAVResponseParserMode(eWebDAVResponseParserMode),
mbResourceTypeCollection(false),
mbLockScopeSet(false),
mbLockTypeSet(false)
{
}
WebDAVResponseParser::~WebDAVResponseParser()
{
SAL_WARN_IF(mpContext, "ucb.ucp.webdav", "Parser destructed with existing content (!)");
while(mpContext)
{
pop_context();
}
}
void SAL_CALL WebDAVResponseParser::startDocument( )
{
SAL_WARN_IF(mpContext, "ucb.ucp.webdav", "Parser start with existing content (!)");
}
void SAL_CALL WebDAVResponseParser::endDocument( )
{
SAL_WARN_IF(mpContext, "ucb.ucp.webdav", "Parser end with existing content (!)");
}
void SAL_CALL WebDAVResponseParser::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
{
const sal_Int32 nLen(aName.getLength());
if(nLen)
{
// create new context (push)
mpContext = new WebDAVContext(mpContext, aName, xAttribs);
if(collectThisPropertyAsName())
{
// When collecting property names and parent is prop there is no need
// to handle the content of this property deeper (evtl. preparations)
}
else
{
switch(mpContext->getWebDAVNamespace())
{
default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
{
break;
}
case WebDAVNamespace_DAV:
{
switch(mpContext->getWebDAVName())
{
default: // WebDAVName_unknown, WebDAVName_last or unhandled
{
break;
}
case WebDAVName_propstat:
{
// propstat start
if(isCollectingProperties())
{
// reset maPropStatProperties
maPropStatProperties.clear();
}
else
{
// when collecting properties reset maPropStatNames
maPropStatNames.clear();
}
break;
}
case WebDAVName_response:
{
// response start, reset Href and status and maResponseProperties
maHref.clear();
maStatus.clear();
if(isCollectingProperties())
{
// reset maResponseProperties
maResponseProperties.clear();
}
else
{
// reset maResponseNames when collecting properties
maResponseNames.clear();
}
break;
}
case WebDAVName_resourcetype:
{
// resourcetype start, reset collection
mbResourceTypeCollection = false;
break;
}
case WebDAVName_supportedlock:
{
// supportedlock start, reset maLockEntries
maLockEntries.realloc(0);
break;
}
case WebDAVName_lockentry:
{
// lockentry start, reset maLockEntries
mbLockScopeSet = false;
mbLockTypeSet = false;
break;
}
case WebDAVName_activelock:
{
maLock = ucb::Lock();
break;
}
}
break;
}
case WebDAVNamespace_ucb_openoffice_org_dav_props:
{
break;
}
}
}
}
}
OUString MakePropertyName(WebDAVContext const& rContext)
{
OUString ret;
OString const name(OUStringToOString(rContext.getName(), RTL_TEXTENCODING_UTF8));
OString const nameSpace(OUStringToOString(rContext.getNamespace(), RTL_TEXTENCODING_UTF8));
DAVProperties::createUCBPropName(nameSpace.getStr(), name.getStr(), ret);
return ret;
}
void SAL_CALL WebDAVResponseParser::endElement( const OUString& aName )
{
const sal_Int32 nLen(aName.getLength());
SAL_WARN_IF(!mpContext, "ucb.ucp.webdav", "Parser EndElement without content (!)");
if(mpContext && nLen)
{
if(collectThisPropertyAsName())
{
// name must be encoded as expected by createSerfPropName()
OUString const name(MakePropertyName(*mpContext));
maPropStatNames.emplace_back(name);
}
else
{
switch(mpContext->getWebDAVNamespace())
{
default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
{
break;
}
case WebDAVNamespace_DAV:
{
switch(mpContext->getWebDAVName())
{
default: // WebDAVName_unknown, WebDAVName_last or unhandled
{
break;
}
case WebDAVName_href:
{
// href end, save it if we have whitespace
if(whitespaceIsAvailable())
{
// Sharepoint 2016 workaround: apparently
// the result is an IRI (RFC 3987 possibly?)
// so try to encode the non-ASCII chars
// without changing anything else
maHref = ::rtl::Uri::encode(mpContext->getWhiteSpace(),
rtl_UriCharClassUric, rtl_UriEncodeKeepEscapes,
RTL_TEXTENCODING_UTF8);
}
break;
}
case WebDAVName_status:
{
// status end, save it if we have whitespace
if(whitespaceIsAvailable())
{
maStatus = mpContext->getWhiteSpace();
}
break;
}
case WebDAVName_getlastmodified:
{
// getlastmodified end, safe if content is correct
if(propertyIsReady())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:getlastmodified";
aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_creationdate:
{
// creationdate end, safe if content is correct
if(propertyIsReady())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:creationdate";
aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_collection:
{
// collection end, check and set
if(hasParent(WebDAVName_resourcetype))
{
mbResourceTypeCollection = true;
}
break;
}
case WebDAVName_resourcetype:
{
// resourcetype end, check for collection
if(hasParent(WebDAVName_prop))
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:resourcetype";
aDAVPropertyValue.Value <<= (mbResourceTypeCollection ? OUString("collection") : OUString());
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_getcontentlength:
{
// getcontentlength end, safe if content is correct
if(propertyIsReady())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:getcontentlength";
aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_getcontenttype:
{
// getcontenttype end, safe if content is correct
if(propertyIsReady())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:getcontenttype";
aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_supportedlock:
{
// supportedlock end
if(hasParent(WebDAVName_prop) && maLockEntries.hasElements())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:supportedlock";
aDAVPropertyValue.Value <<= maLockEntries;
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_lockentry:
{
// lockentry end
if(hasParent(WebDAVName_supportedlock) && (mbLockScopeSet && mbLockTypeSet))
{
const sal_Int32 nLength(maLockEntries.getLength());
ucb::LockEntry aEntry;
aEntry.Scope = maLockScope;
aEntry.Type = maLockType;
maLockEntries.realloc(nLength + 1);
maLockEntries.getArray()[nLength] = aEntry;
}
break;
}
case WebDAVName_owner:
{
maLock.Owner <<= mpContext->getWhiteSpace();
break;
}
case WebDAVName_timeout:
{
const OUString sTimeout(mpContext->getWhiteSpace());
if (sTimeout == "Infinite")
maLock.Timeout = -1;
else if (sTimeout.startsWith("Second-"))
maLock.Timeout = o3tl::toInt64(sTimeout.subView(7));
break;
}
case WebDAVName_locktoken:
{
const OUString sLockToken(maHref);
SAL_WARN_IF(!sLockToken.startsWith("opaquelocktoken:"), "ucb.ucp.webdav",
"Parser error: wrong 'locktoken' value.");
const sal_Int32 nLength(maLock.LockTokens.getLength());
maLock.LockTokens.realloc(nLength+1);
maLock.LockTokens.getArray()[nLength] = sLockToken;
break;
}
case WebDAVName_exclusive:
{
// exclusive lockscope end
if(hasParent(WebDAVName_lockscope))
{
maLockScope = ucb::LockScope_EXCLUSIVE;
mbLockScopeSet = true;
}
break;
}
case WebDAVName_shared:
{
// shared lockscope end
if(hasParent(WebDAVName_lockscope))
{
maLockScope = ucb::LockScope_SHARED;
mbLockScopeSet = true;
}
break;
}
case WebDAVName_write:
{
// write locktype end
if(hasParent(WebDAVName_locktype))
{
maLockType = ucb::LockType_WRITE;
mbLockTypeSet = true;
}
break;
}
case WebDAVName_depth:
{
OUString const chars(mpContext->getWhiteSpace());
if (chars == "0")
{
maLock.Depth = ucb::LockDepth_ZERO;
}
else if (chars == "1")
{
maLock.Depth = ucb::LockDepth_ONE;
}
else if (chars == "infinity")
{
maLock.Depth = ucb::LockDepth_INFINITY;
}
break;
}
case WebDAVName_activelock:
{
maLock.Type = maLockType;
maLock.Scope = maLockScope;
maResult_Lock.push_back(maLock);
break;
}
case WebDAVName_lockdiscovery:
{
// lockdiscovery may be requested via PROPFIND,
// in addition to LOCK! so return it 2 ways
if (isCollectingProperties())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = "DAV:lockdiscovery";
aDAVPropertyValue.Value <<= ::comphelper::containerToSequence(maResult_Lock);
maPropStatProperties.push_back(aDAVPropertyValue);
}
break;
}
case WebDAVName_propstat:
{
// propstat end, check status
if(maStatus.getLength())
{
if(maStatus == "HTTP/1.1 200 OK")
{
if(isCollectingProperties())
{
if(!maPropStatProperties.empty())
{
// append to maResponseProperties if okay
maResponseProperties.insert(maResponseProperties.end(), maPropStatProperties.begin(), maPropStatProperties.end());
}
}
else
{
if(!maPropStatNames.empty())
{
// when collecting properties append to
maResponseNames.insert(maResponseNames.end(), maPropStatNames.begin(), maPropStatNames.end());
}
}
}
}
break;
}
case WebDAVName_response:
{
// response end
if(maHref.getLength())
{
if(isCollectingProperties())
{
// create DAVResource when we have content
if(!maResponseProperties.empty())
{
http_dav_ucp::DAVResource aDAVResource;
aDAVResource.uri = maHref;
aDAVResource.properties = maResponseProperties;
maResult_PropFind.push_back(aDAVResource);
}
}
else
{
// when collecting properties add them to result when there are some
if(!maResponseNames.empty())
{
http_dav_ucp::DAVResourceInfo aDAVResourceInfo;
aDAVResourceInfo.properties = maResponseNames;
maResult_PropName.push_back(aDAVResourceInfo);
}
}
}
break;
}
}
break;
}
case WebDAVNamespace_ucb_openoffice_org_dav_props:
{
switch(mpContext->getWebDAVName())
{
case WebDAVName_type:
{
m_UCBType = mpContext->getWhiteSpace();
break;
}
case WebDAVName_value:
{
m_UCBValue = mpContext->getWhiteSpace();
break;
}
case WebDAVName_ucbprop:
{
if (!m_UCBType.isEmpty()
&& isCollectingProperties())
{
http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
aDAVPropertyValue.Name = MakePropertyName(*mpContext->getParent());
if (UCBDeadPropertyValue::createFromXML(m_UCBType, m_UCBValue, aDAVPropertyValue.Value))
{
maPropStatProperties.push_back(aDAVPropertyValue);
}
else
{
SAL_INFO("ucb.ucp.webdav.curl", "cannot parse property value");
}
}
m_UCBType.clear();
m_UCBValue.clear();
break;
}
default:
break;
}
break;
}
}
}
// destroy last context (pop)
pop_context();
}
}
void SAL_CALL WebDAVResponseParser::characters( const OUString& aChars )
{
// collect whitespace over evtl. several calls in mpContext
SAL_WARN_IF(!mpContext, "ucb.ucp.webdav", "Parser characters without content (!)");
const sal_Int32 nLen(aChars.getLength());
if(mpContext && nLen)
{
// remove leading/trailing blanks and CRLF
const OUString aTrimmedChars(aChars.trim());
if(aTrimmedChars.getLength())
{
OUString aNew(mpContext->getWhiteSpace());
if(aNew.getLength())
{
// add one char when appending (see html1.1 spec)
aNew += " ";
}
aNew += aTrimmedChars;
mpContext->setWhiteSpace(aNew);
}
}
}
void SAL_CALL WebDAVResponseParser::ignorableWhitespace( const OUString& /*aWhitespaces*/ )
{
}
void SAL_CALL WebDAVResponseParser::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ )
{
}
void SAL_CALL WebDAVResponseParser::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ )
{
}
} // end of anonymous namespace
// wrapper for various calls to the parser
namespace
{
template<typename T>
void parseWebDAVResponse(
const uno::Reference< io::XInputStream >& xInputStream,
std::vector< T >& rResult,
WebDAVResponseParserMode eWebDAVResponseParserMode,
std::vector<T> const & (WebDAVResponseParser::* fn)() const)
{
if(xInputStream.is())
{
try
{
// prepare ParserInputSource
xml::sax::InputSource myInputSource;
myInputSource.aInputStream = xInputStream;
// get parser
uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(
comphelper::getProcessComponentContext() );
// create parser; connect parser and filter
rtl::Reference<WebDAVResponseParser> const pWebDAVResponseParser(
new WebDAVResponseParser(eWebDAVResponseParserMode));
uno::Reference< xml::sax::XDocumentHandler > xWebDAVHdl(pWebDAVResponseParser);
xParser->setDocumentHandler(xWebDAVHdl);
// finally, parse the stream
xParser->parseStream(myInputSource);
// get result
rResult = (pWebDAVResponseParser.get()->*fn)();
}
catch(uno::Exception&)
{
SAL_WARN("ucb.ucp.webdav", "WebDAV Parse error (!)");
}
}
}
} // end of anonymous namespace
// helper to parse a XML WebDAV response
namespace http_dav_ucp
{
std::vector< ucb::Lock > parseWebDAVLockResponse(const uno::Reference< io::XInputStream >& xInputStream)
{
std::vector< ucb::Lock > aResult;
parseWebDAVResponse< ucb::Lock >(xInputStream, aResult, WebDAVResponseParserMode_Lock, &WebDAVResponseParser::getResult_Lock);
return aResult;
}
std::vector< DAVResource > parseWebDAVPropFindResponse(const uno::Reference< io::XInputStream >& xInputStream)
{
std::vector< DAVResource > aResult;
parseWebDAVResponse< DAVResource >(xInputStream, aResult, WebDAVResponseParserMode_PropFind, &WebDAVResponseParser::getResult_PropFind);
return aResult;
}
std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const uno::Reference< io::XInputStream >& xInputStream)
{
std::vector< DAVResourceInfo > aResult;
parseWebDAVResponse< DAVResourceInfo >(xInputStream, aResult, WebDAVResponseParserMode_PropName, &WebDAVResponseParser::getResult_PropName);
return aResult;
}
} // namespace http_dav_ucp
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */