nss: upgrade to release 3.73
[LibreOffice.git] / ucb / source / ucp / webdav / webdavcontent.cxx
blob4cf298bdf47172d621a12acc000cc9d38d4ffab6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
22 #include <cppuhelper/queryinterface.hxx>
23 #include <rtl/uri.hxx>
24 #include <sal/log.hxx>
25 #include <ucbhelper/contentidentifier.hxx>
26 #include <ucbhelper/macros.hxx>
27 #include <ucbhelper/propertyvalueset.hxx>
28 #include <ucbhelper/simpleinteractionrequest.hxx>
29 #include <ucbhelper/cancelcommandexecution.hxx>
31 #include <com/sun/star/beans/IllegalTypeException.hpp>
32 #include <com/sun/star/beans/NotRemoveableException.hpp>
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/beans/PropertyExistException.hpp>
35 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
36 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/io/XActiveDataSink.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/lang/IllegalAccessException.hpp>
41 #include <com/sun/star/lang/IllegalArgumentException.hpp>
42 #include <com/sun/star/sdbc/SQLException.hpp>
43 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp>
44 #include <com/sun/star/ucb/CommandEnvironment.hpp>
45 #include <com/sun/star/ucb/CommandFailedException.hpp>
46 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
47 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
48 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
49 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
50 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
51 #include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
52 #include <com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp>
53 #include <com/sun/star/ucb/InteractiveLockingNotLockedException.hpp>
54 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
55 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
56 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
57 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
58 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
59 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
60 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
61 #include <com/sun/star/ucb/NameClash.hpp>
62 #include <com/sun/star/ucb/NameClashException.hpp>
63 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
64 #include <com/sun/star/ucb/OpenMode.hpp>
65 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
66 #include <com/sun/star/ucb/PropertyCommandArgument.hpp>
67 #include <com/sun/star/ucb/TransferInfo.hpp>
68 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
69 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
70 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
71 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
72 #include <com/sun/star/ucb/XCommandInfo.hpp>
73 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
74 #include <com/sun/star/uno/XComponentContext.hpp>
76 #include "webdavcontent.hxx"
77 #include "webdavprovider.hxx"
78 #include "webdavresultset.hxx"
79 #include "ContentProperties.hxx"
80 #include "SerfUri.hxx"
81 #include "UCBDeadPropertyValue.hxx"
82 #include "DAVException.hxx"
83 #include "DAVProperties.hxx"
85 using namespace com::sun::star;
86 using namespace http_dav_ucp;
88 namespace
90 void lcl_sendPartialGETRequest( bool &bError,
91 DAVException &aLastException,
92 const std::vector< OUString >& rProps,
93 std::vector< OUString > &aHeaderNames,
94 const std::unique_ptr< DAVResourceAccess > &xResAccess,
95 std::unique_ptr< ContentProperties > &xProps,
96 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
98 DAVResource aResource;
99 DAVRequestHeaders aPartialGet;
100 aPartialGet.push_back(
101 DAVRequestHeader(
102 OUString( "Range" ),
103 OUString( "bytes=0-0" )));
105 bool bIsRequestSize = std::any_of(aHeaderNames.begin(), aHeaderNames.end(),
106 [](const OUString& rHeaderName) { return rHeaderName == "Content-Length"; });
108 if ( bIsRequestSize )
110 // we need to know if the server accepts range requests for a resource
111 // and the range unit it uses
112 aHeaderNames.push_back( OUString( "Accept-Ranges" ) );
113 aHeaderNames.push_back( OUString( "Content-Range" ) );
117 uno::Reference< io::XInputStream > xIn = xResAccess->GET( aPartialGet,
118 aHeaderNames,
119 aResource,
120 xEnv );
121 bError = false;
123 if ( bIsRequestSize )
125 // the ContentProperties maps "Content-Length" to the UCB "Size" property
126 // This would have an unrealistic value of 1 byte because we did only a partial GET
127 // Solution: if "Content-Range" is present, map it with UCB "Size" property
128 OUString aAcceptRanges, aContentRange, aContentLength;
129 std::vector< DAVPropertyValue > &aResponseProps = aResource.properties;
130 for ( const auto& rResponseProp : aResponseProps )
132 if ( rResponseProp.Name == "Accept-Ranges" )
133 rResponseProp.Value >>= aAcceptRanges;
134 else if ( rResponseProp.Name == "Content-Range" )
135 rResponseProp.Value >>= aContentRange;
136 else if ( rResponseProp.Name == "Content-Length" )
137 rResponseProp.Value >>= aContentLength;
140 sal_Int64 nSize = 1;
141 if ( aContentLength.getLength() )
143 nSize = aContentLength.toInt64();
146 // according to http://tools.ietf.org/html/rfc2616#section-3.12
147 // the only range unit defined is "bytes" and implementations
148 // MAY ignore ranges specified using other units.
149 if ( nSize == 1 &&
150 aContentRange.getLength() &&
151 aAcceptRanges == "bytes" )
153 // Parse the Content-Range to get the size
154 // vid. http://tools.ietf.org/html/rfc2616#section-14.16
155 // Content-Range: <range unit> <bytes range>/<size>
156 sal_Int32 nSlash = aContentRange.lastIndexOf( '/' );
157 if ( nSlash != -1 )
159 OUString aSize = aContentRange.copy( nSlash + 1 );
160 // "*" means that the instance-length is unknown at the time when the response was generated
161 if ( aSize != "*" )
163 auto it = std::find_if(aResponseProps.begin(), aResponseProps.end(),
164 [](const DAVPropertyValue& rProp) { return rProp.Name == "Content-Length"; });
165 if (it != aResponseProps.end())
167 it->Value <<= aSize;
174 if ( xProps.get() )
175 xProps->addProperties(
176 rProps,
177 ContentProperties( aResource ) );
178 else
179 xProps.reset ( new ContentProperties( aResource ) );
181 catch ( DAVException const & ex )
183 aLastException = ex;
189 // Content Implementation.
192 // ctr for content on an existing webdav resource
193 Content::Content(
194 const uno::Reference< uno::XComponentContext >& rxContext,
195 ContentProvider* pProvider,
196 const uno::Reference< ucb::XContentIdentifier >& Identifier,
197 rtl::Reference< DAVSessionFactory > const & rSessionFactory )
198 : ContentImplHelper( rxContext, pProvider, Identifier ),
199 m_eResourceType( UNKNOWN ),
200 m_pProvider( pProvider ),
201 m_bTransient( false ),
202 m_bLocked( false ),
203 m_bCollection( false ),
204 m_bDidGetOrHead( false )
208 m_xResAccess.reset( new DAVResourceAccess(
209 rxContext,
210 rSessionFactory,
211 Identifier->getContentIdentifier() ) );
213 SerfUri aURI( Identifier->getContentIdentifier() );
214 m_aEscapedTitle = aURI.GetPathBaseName();
216 catch ( DAVException const & )
218 throw ucb::ContentCreationException();
223 // ctr for content on a non-existing webdav resource
224 Content::Content(
225 const uno::Reference< uno::XComponentContext >& rxContext,
226 ContentProvider* pProvider,
227 const uno::Reference< ucb::XContentIdentifier >& Identifier,
228 rtl::Reference< DAVSessionFactory > const & rSessionFactory,
229 bool isCollection )
230 : ContentImplHelper( rxContext, pProvider, Identifier ),
231 m_eResourceType( UNKNOWN ),
232 m_pProvider( pProvider ),
233 m_bTransient( true ),
234 m_bLocked( false ),
235 m_bCollection( isCollection ),
236 m_bDidGetOrHead( false )
240 m_xResAccess.reset( new DAVResourceAccess(
241 rxContext, rSessionFactory, Identifier->getContentIdentifier() ) );
243 catch ( DAVException const & )
245 throw ucb::ContentCreationException();
248 // Do not set m_aEscapedTitle here! Content::insert relays on this!!!
252 // virtual
253 Content::~Content()
255 if (m_bLocked)
256 unlock(uno::Reference< ucb::XCommandEnvironment >());
260 // XInterface methods.
263 // virtual
264 void SAL_CALL Content::acquire()
265 throw( )
267 ContentImplHelper::acquire();
271 // virtual
272 void SAL_CALL Content::release()
273 throw( )
275 ContentImplHelper::release();
279 // virtual
280 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
282 // Note: isFolder may require network activities! So call it only
283 // if it is really necessary!!!
284 uno::Any aRet = cppu::queryInterface(
285 rType,
286 static_cast< ucb::XContentCreator * >( this ) );
287 if ( aRet.hasValue() )
291 uno::Reference< beans::XPropertySet > const xProps(
292 m_xContext, uno::UNO_QUERY_THROW );
293 uno::Reference< uno::XComponentContext > xCtx;
294 xCtx.set( xProps->getPropertyValue( "DefaultContext" ),
295 uno::UNO_QUERY_THROW );
297 uno::Reference< task::XInteractionHandler > xIH(
298 task::PasswordContainerInteractionHandler::create( xCtx ) );
300 // Supply a command env to isFolder() that contains an interaction
301 // handler that uses the password container service to obtain
302 // credentials without displaying a password gui.
304 uno::Reference< ucb::XCommandEnvironment > xCmdEnv(
305 ucb::CommandEnvironment::create(
306 xCtx,
307 xIH,
308 uno::Reference< ucb::XProgressHandler >() ) );
310 return isFolder( xCmdEnv ) ? aRet : uno::Any();
312 catch ( uno::RuntimeException const & )
314 throw;
316 catch ( uno::Exception const & )
318 return uno::Any();
321 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
325 // XTypeProvider methods.
328 XTYPEPROVIDER_COMMON_IMPL( Content );
331 // virtual
332 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
334 bool bFolder = false;
337 bFolder
338 = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
340 catch ( uno::RuntimeException const & )
342 throw;
344 catch ( uno::Exception const & )
348 if ( bFolder )
350 static cppu::OTypeCollection s_aFolderTypes(
351 CPPU_TYPE_REF( lang::XTypeProvider ),
352 CPPU_TYPE_REF( lang::XServiceInfo ),
353 CPPU_TYPE_REF( lang::XComponent ),
354 CPPU_TYPE_REF( ucb::XContent ),
355 CPPU_TYPE_REF( ucb::XCommandProcessor ),
356 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
357 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
358 CPPU_TYPE_REF( beans::XPropertyContainer ),
359 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
360 CPPU_TYPE_REF( container::XChild ),
361 CPPU_TYPE_REF( ucb::XContentCreator ) );
363 return s_aFolderTypes.getTypes();
365 else
367 static cppu::OTypeCollection s_aDocumentTypes(
368 CPPU_TYPE_REF( lang::XTypeProvider ),
369 CPPU_TYPE_REF( lang::XServiceInfo ),
370 CPPU_TYPE_REF( lang::XComponent ),
371 CPPU_TYPE_REF( ucb::XContent ),
372 CPPU_TYPE_REF( ucb::XCommandProcessor ),
373 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
374 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
375 CPPU_TYPE_REF( beans::XPropertyContainer ),
376 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
377 CPPU_TYPE_REF( container::XChild ) );
379 return s_aDocumentTypes.getTypes();
384 // XServiceInfo methods.
387 // virtual
388 OUString SAL_CALL Content::getImplementationName()
390 return "com.sun.star.comp.ucb.WebDAVContent";
394 // virtual
395 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
397 uno::Sequence<OUString> aSNS { WEBDAV_CONTENT_SERVICE_NAME };
398 return aSNS;
402 // XContent methods.
405 // virtual
406 OUString SAL_CALL Content::getContentType()
408 bool bFolder = false;
411 bFolder
412 = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
414 catch ( uno::RuntimeException const & )
416 throw;
418 catch ( uno::Exception const & )
422 if ( bFolder )
423 return WEBDAV_COLLECTION_TYPE;
425 return WEBDAV_CONTENT_TYPE;
429 // XCommandProcessor methods.
432 // virtual
433 uno::Any SAL_CALL Content::execute(
434 const ucb::Command& aCommand,
435 sal_Int32 /*CommandId*/,
436 const uno::Reference< ucb::XCommandEnvironment >& Environment )
438 SAL_INFO("ucb.ucp.webdav", ">>>>> Content::execute: start: command: " << aCommand.Name
439 << ", env: " << (Environment.is() ? "present" : "missing") );
441 uno::Any aRet;
443 if ( aCommand.Name == "getPropertyValues" )
446 // getPropertyValues
449 uno::Sequence< beans::Property > Properties;
450 if ( !( aCommand.Argument >>= Properties ) )
452 ucbhelper::cancelCommandExecution(
453 uno::makeAny( lang::IllegalArgumentException(
454 "Wrong argument type!",
455 static_cast< cppu::OWeakObject * >( this ),
456 -1 ) ),
457 Environment );
458 // Unreachable
461 aRet <<= getPropertyValues( Properties, Environment );
463 else if ( aCommand.Name == "setPropertyValues" )
466 // setPropertyValues
469 uno::Sequence< beans::PropertyValue > aProperties;
470 if ( !( aCommand.Argument >>= aProperties ) )
472 ucbhelper::cancelCommandExecution(
473 uno::makeAny( lang::IllegalArgumentException(
474 "Wrong argument type!",
475 static_cast< cppu::OWeakObject * >( this ),
476 -1 ) ),
477 Environment );
478 // Unreachable
481 if ( !aProperties.getLength() )
483 ucbhelper::cancelCommandExecution(
484 uno::makeAny( lang::IllegalArgumentException(
485 "No properties!",
486 static_cast< cppu::OWeakObject * >( this ),
487 -1 ) ),
488 Environment );
489 // Unreachable
492 aRet <<= setPropertyValues( aProperties, Environment );
494 else if ( aCommand.Name == "getPropertySetInfo" )
497 // getPropertySetInfo
500 // Note: Implemented by base class.
501 aRet <<= getPropertySetInfo( Environment,
502 false /* don't cache data */ );
504 else if ( aCommand.Name == "getCommandInfo" )
507 // getCommandInfo
510 // Note: Implemented by base class.
511 aRet <<= getCommandInfo( Environment, false );
513 else if ( aCommand.Name == "open" )
516 // open
519 ucb::OpenCommandArgument2 aOpenCommand;
520 if ( !( aCommand.Argument >>= aOpenCommand ) )
522 ucbhelper::cancelCommandExecution(
523 uno::makeAny( lang::IllegalArgumentException(
524 "Wrong argument type!",
525 static_cast< cppu::OWeakObject * >( this ),
526 -1 ) ),
527 Environment );
528 // Unreachable
531 aRet = open( aOpenCommand, Environment );
533 if ( (aOpenCommand.Mode == ucb::OpenMode::DOCUMENT ||
534 aOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE) &&
535 supportsExclusiveWriteLock( Environment ) )
536 lock( Environment );
538 else if ( aCommand.Name == "insert" )
541 // insert
544 ucb::InsertCommandArgument arg;
545 if ( !( aCommand.Argument >>= arg ) )
547 ucbhelper::cancelCommandExecution(
548 uno::makeAny( lang::IllegalArgumentException(
549 "Wrong argument type!",
550 static_cast< cppu::OWeakObject * >( this ),
551 -1 ) ),
552 Environment );
553 // Unreachable
556 insert( arg.Data, arg.ReplaceExisting, Environment );
558 else if ( aCommand.Name == "delete" )
561 // delete
564 bool bDeletePhysical = false;
565 aCommand.Argument >>= bDeletePhysical;
567 // KSO: Ignore parameter and destroy the content, if you don't support
568 // putting objects into trashcan. ( Since we do not have a trash can
569 // service yet (src603), you actually have no other choice. )
570 // if ( bDeletePhysical )
571 // {
574 std::unique_ptr< DAVResourceAccess > xResAccess;
576 osl::Guard< osl::Mutex > aGuard( m_aMutex );
577 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
579 xResAccess->DESTROY( Environment );
581 osl::Guard< osl::Mutex > aGuard( m_aMutex );
582 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
585 catch ( DAVException const & e )
587 cancelCommandExecution( e, Environment, true );
588 // Unreachable
590 // }
592 // Propagate destruction.
593 destroy( bDeletePhysical );
595 // Remove own and all children's Additional Core Properties.
596 removeAdditionalPropertySet();
598 else if ( aCommand.Name == "transfer" && isFolder( Environment ) )
601 // transfer
602 // ( Not available at documents )
605 ucb::TransferInfo transferArgs;
606 if ( !( aCommand.Argument >>= transferArgs ) )
608 ucbhelper::cancelCommandExecution(
609 uno::makeAny( lang::IllegalArgumentException(
610 "Wrong argument type!",
611 static_cast< cppu::OWeakObject * >( this ),
612 -1 ) ),
613 Environment );
614 // Unreachable
617 transfer( transferArgs, Environment );
619 else if ( aCommand.Name == "post" )
622 // post
625 ucb::PostCommandArgument2 aArg;
626 if ( !( aCommand.Argument >>= aArg ) )
628 ucbhelper::cancelCommandExecution(
629 uno::makeAny( lang::IllegalArgumentException(
630 "Wrong argument type!",
631 static_cast< cppu::OWeakObject * >( this ),
632 -1 ) ),
633 Environment );
634 // Unreachable
637 post( aArg, Environment );
639 else if ( aCommand.Name == "lock" &&
640 supportsExclusiveWriteLock( Environment ) )
643 // lock
646 lock( Environment );
648 else if ( aCommand.Name == "unlock" &&
649 supportsExclusiveWriteLock( Environment ) )
652 // unlock
655 unlock( Environment );
657 else if ( aCommand.Name == "createNewContent" &&
658 isFolder( Environment ) )
661 // createNewContent
664 ucb::ContentInfo aArg;
665 if ( !( aCommand.Argument >>= aArg ) )
667 ucbhelper::cancelCommandExecution(
668 uno::makeAny( lang::IllegalArgumentException(
669 "Wrong argument type!",
670 static_cast< cppu::OWeakObject * >( this ),
671 -1 ) ),
672 Environment );
673 // Unreachable
676 aRet <<= createNewContent( aArg );
678 else if ( aCommand.Name == "addProperty" )
680 ucb::PropertyCommandArgument aPropArg;
681 if ( !( aCommand.Argument >>= aPropArg ))
683 ucbhelper::cancelCommandExecution(
684 uno::makeAny( lang::IllegalArgumentException(
685 "Wrong argument type!",
686 static_cast< cppu::OWeakObject * >( this ),
687 -1 ) ),
688 Environment );
691 // TODO when/if XPropertyContainer is removed,
692 // the command execution can be canceled in addProperty
695 addProperty( aPropArg, Environment );
697 catch ( const beans::PropertyExistException &e )
699 ucbhelper::cancelCommandExecution( uno::makeAny( e ), Environment );
701 catch ( const beans::IllegalTypeException&e )
703 ucbhelper::cancelCommandExecution( uno::makeAny( e ), Environment );
705 catch ( const lang::IllegalArgumentException&e )
707 ucbhelper::cancelCommandExecution( uno::makeAny( e ), Environment );
710 else if ( aCommand.Name == "removeProperty" )
712 OUString sPropName;
713 if ( !( aCommand.Argument >>= sPropName ) )
715 ucbhelper::cancelCommandExecution(
716 uno::makeAny( lang::IllegalArgumentException(
717 "Wrong argument type!",
718 static_cast< cppu::OWeakObject * >( this ),
719 -1 ) ),
720 Environment );
723 // TODO when/if XPropertyContainer is removed,
724 // the command execution can be canceled in removeProperty
727 removeProperty( sPropName, Environment );
729 catch( const beans::UnknownPropertyException &e )
731 ucbhelper::cancelCommandExecution( uno::makeAny( e ), Environment );
733 catch( const beans::NotRemoveableException &e )
735 ucbhelper::cancelCommandExecution( uno::makeAny( e ), Environment );
738 else
741 // Unsupported command
744 ucbhelper::cancelCommandExecution(
745 uno::makeAny( ucb::UnsupportedCommandException(
746 aCommand.Name,
747 static_cast< cppu::OWeakObject * >( this ) ) ),
748 Environment );
749 // Unreachable
752 SAL_INFO("ucb.ucp.webdav", "<<<<< Content::execute: end: command: " << aCommand.Name);
753 return aRet;
757 // virtual
758 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
762 std::unique_ptr< DAVResourceAccess > xResAccess;
764 osl::MutexGuard aGuard( m_aMutex );
765 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
767 DAVResourceAccess::abort();
769 osl::Guard< osl::Mutex > aGuard( m_aMutex );
770 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
773 catch ( DAVException const & )
775 // abort failed!
780 // XPropertyContainer methods.
783 void Content::addProperty( const css::ucb::PropertyCommandArgument &aCmdArg,
784 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
786 // if ( m_bTransient )
787 // @@@ ???
788 const beans::Property aProperty = aCmdArg.Property;
789 const uno::Any aDefaultValue = aCmdArg.DefaultValue;
791 // check property Name
792 if ( !aProperty.Name.getLength() )
793 throw lang::IllegalArgumentException(
794 "\"addProperty\" with empty Property.Name",
795 static_cast< ::cppu::OWeakObject * >( this ),
796 -1 );
798 // Check property type.
799 if ( !UCBDeadPropertyValue::supportsType( aProperty.Type ) )
800 throw beans::IllegalTypeException(
801 "\"addProperty\" unsupported Property.Type",
802 static_cast< ::cppu::OWeakObject * >( this ) );
804 // check default value
805 if ( aDefaultValue.hasValue() && aDefaultValue.getValueType() != aProperty.Type )
806 throw beans::IllegalTypeException(
807 "\"addProperty\" DefaultValue does not match Property.Type",
808 static_cast< ::cppu::OWeakObject * >( this ) );
811 // Make sure a property with the requested name does not already
812 // exist in dynamic and static(!) properties.
815 // Take into account special properties with custom namespace
816 // using <prop:the_propname xmlns:prop="the_namespace">
817 OUString aSpecialName;
818 bool bIsSpecial = DAVProperties::isUCBSpecialProperty( aProperty.Name, aSpecialName );
820 // Note: This requires network access!
821 if ( getPropertySetInfo( xEnv, false /* don't cache data */ )
822 ->hasPropertyByName( bIsSpecial ? aSpecialName : aProperty.Name ) )
824 // Property does already exist.
825 throw beans::PropertyExistException();
829 // Add a new dynamic property.
832 ProppatchValue aValue( PROPSET, aProperty.Name, aDefaultValue );
834 std::vector< ProppatchValue > aProppatchValues;
835 aProppatchValues.push_back( aValue );
839 // Set property value at server.
840 std::unique_ptr< DAVResourceAccess > xResAccess;
842 osl::Guard< osl::Mutex > aGuard( m_aMutex );
843 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
845 xResAccess->PROPPATCH( aProppatchValues, xEnv );
847 osl::Guard< osl::Mutex > aGuard( m_aMutex );
848 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
851 // Notify propertyset info change listeners.
852 beans::PropertySetInfoChangeEvent evt(
853 static_cast< cppu::OWeakObject * >( this ),
854 bIsSpecial ? aSpecialName : aProperty.Name,
855 -1, // No handle available
856 beans::PropertySetInfoChange::PROPERTY_INSERTED );
857 notifyPropertySetInfoChange( evt );
859 catch ( DAVException const & e )
861 if ( e.getStatus() == SC_FORBIDDEN )
863 // Support for setting arbitrary dead properties is optional!
865 // Store property locally.
866 ContentImplHelper::addProperty( bIsSpecial ? aSpecialName : aProperty.Name,
867 aProperty.Attributes,
868 aDefaultValue );
870 else
872 if ( shouldAccessNetworkAfterException( e ) )
876 const ResourceType & rType = getResourceType( xEnv );
877 switch ( rType )
879 case UNKNOWN:
880 case DAV:
881 throw lang::IllegalArgumentException();
883 case NON_DAV:
884 // Store property locally.
885 ContentImplHelper::addProperty( bIsSpecial ? aSpecialName : aProperty.Name,
886 aProperty.Attributes,
887 aDefaultValue );
888 break;
890 default:
891 SAL_WARN( "ucb.ucp.webdav",
892 "Content::addProperty - "
893 "Unsupported resource type!" );
894 break;
897 catch ( uno::Exception const & )
899 SAL_WARN( "ucb.ucp.webdav",
900 "Content::addProperty - "
901 "Unable to determine resource type!" );
904 else
906 SAL_WARN( "ucb.ucp.webdav",
907 "Content::addProperty - "
908 "Unable to determine resource type!" );
914 void Content::removeProperty( const OUString& Name,
915 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
917 #if 0
918 // @@@ REMOVABLE at the moment not properly set in the PropSetInfo
921 beans::Property aProp
922 = getPropertySetInfo( xEnv, false /* don't cache data */ )
923 ->getPropertyByName( Name );
925 if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVABLE ) )
927 // Not removable!
928 throw beans::NotRemoveableException();
931 catch ( beans::UnknownPropertyException const & )
933 //SAL_WARN( "ucb.ucp.webdav", "removeProperty - Unknown property!" );
934 throw;
936 #endif
938 // Try to remove property from server.
941 std::vector< ProppatchValue > aProppatchValues;
942 ProppatchValue aValue( PROPREMOVE, Name, uno::Any() );
943 aProppatchValues.push_back( aValue );
945 // Remove property value from server.
946 std::unique_ptr< DAVResourceAccess > xResAccess;
948 osl::Guard< osl::Mutex > aGuard( m_aMutex );
949 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
951 xResAccess->PROPPATCH( aProppatchValues, xEnv );
953 osl::Guard< osl::Mutex > aGuard( m_aMutex );
954 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
957 // Notify propertyset info change listeners.
958 beans::PropertySetInfoChangeEvent evt(
959 static_cast< cppu::OWeakObject * >( this ),
960 Name,
961 -1, // No handle available
962 beans::PropertySetInfoChange::PROPERTY_REMOVED );
963 notifyPropertySetInfoChange( evt );
965 catch ( DAVException const & e )
967 if ( e.getStatus() == SC_FORBIDDEN )
969 // Support for setting arbitrary dead properties is optional!
971 // Try to remove property from local store.
972 ContentImplHelper::removeProperty( Name );
974 else
976 if ( shouldAccessNetworkAfterException( e ) )
980 const ResourceType & rType = getResourceType( xEnv );
981 switch ( rType )
983 case UNKNOWN:
984 case DAV:
985 throw beans::UnknownPropertyException(Name);
987 case NON_DAV:
988 // Try to remove property from local store.
989 ContentImplHelper::removeProperty( Name );
990 break;
992 default:
993 SAL_WARN( "ucb.ucp.webdav",
994 "Content::removeProperty - "
995 "Unsupported resource type!" );
996 break;
999 catch ( uno::Exception const & )
1001 SAL_WARN( "ucb.ucp.webdav",
1002 "Content::removeProperty - "
1003 "Unable to determine resource type!" );
1006 else
1008 SAL_WARN( "ucb.ucp.webdav",
1009 "Content::removeProperty - "
1010 "Unable to determine resource type!" );
1011 // throw beans::UnknownPropertyException();
1017 // virtual
1018 void SAL_CALL Content::addProperty( const OUString& Name,
1019 sal_Int16 Attributes,
1020 const uno::Any& DefaultValue )
1022 beans::Property aProperty;
1023 aProperty.Name = Name;
1024 aProperty.Type = DefaultValue.getValueType();
1025 aProperty.Attributes = Attributes;
1026 aProperty.Handle = -1;
1028 addProperty( ucb::PropertyCommandArgument( aProperty, DefaultValue ),
1029 uno::Reference< ucb::XCommandEnvironment >());
1032 // virtual
1033 void SAL_CALL Content::removeProperty( const OUString& Name )
1035 removeProperty( Name,
1036 uno::Reference< ucb::XCommandEnvironment >() );
1040 // XContentCreator methods.
1043 // virtual
1044 uno::Sequence< ucb::ContentInfo > SAL_CALL
1045 Content::queryCreatableContentsInfo()
1047 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1049 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1051 // document.
1052 aSeq.getArray()[ 0 ].Type = WEBDAV_CONTENT_TYPE;
1053 aSeq.getArray()[ 0 ].Attributes
1054 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
1055 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
1057 beans::Property aProp;
1058 m_pProvider->getProperty( "Title", aProp );
1060 uno::Sequence< beans::Property > aDocProps( 1 );
1061 aDocProps.getArray()[ 0 ] = aProp;
1062 aSeq.getArray()[ 0 ].Properties = aDocProps;
1064 // folder.
1065 aSeq.getArray()[ 1 ].Type = WEBDAV_COLLECTION_TYPE;
1066 aSeq.getArray()[ 1 ].Attributes
1067 = ucb::ContentInfoAttribute::KIND_FOLDER;
1069 uno::Sequence< beans::Property > aFolderProps( 1 );
1070 aFolderProps.getArray()[ 0 ] = aProp;
1071 aSeq.getArray()[ 1 ].Properties = aFolderProps;
1072 return aSeq;
1076 // virtual
1077 uno::Reference< ucb::XContent > SAL_CALL
1078 Content::createNewContent( const ucb::ContentInfo& Info )
1080 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1082 if ( !Info.Type.getLength() )
1083 return uno::Reference< ucb::XContent >();
1085 if ( ( Info.Type != WEBDAV_COLLECTION_TYPE )
1087 ( Info.Type != WEBDAV_CONTENT_TYPE ) )
1088 return uno::Reference< ucb::XContent >();
1090 OUString aURL = m_xIdentifier->getContentIdentifier();
1092 SAL_WARN_IF( aURL.isEmpty(), "ucb.ucp.webdav",
1093 "WebdavContent::createNewContent - empty identifier!" );
1095 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1096 aURL += "/";
1098 bool isCollection;
1099 if ( Info.Type == WEBDAV_COLLECTION_TYPE )
1101 aURL += "New_Collection";
1102 isCollection = true;
1104 else
1106 aURL += "New_Content";
1107 isCollection = false;
1110 uno::Reference< ucb::XContentIdentifier > xId(
1111 new ::ucbhelper::ContentIdentifier( aURL ) );
1113 // create the local content
1116 return new ::http_dav_ucp::Content( m_xContext,
1117 m_pProvider,
1118 xId,
1119 m_xResAccess->getSessionFactory(),
1120 isCollection );
1122 catch ( ucb::ContentCreationException & )
1124 return uno::Reference< ucb::XContent >();
1129 // virtual
1130 OUString Content::getParentURL()
1132 // <scheme>:// -> ""
1133 // <scheme>://foo -> ""
1134 // <scheme>://foo/ -> ""
1135 // <scheme>://foo/bar -> <scheme>://foo/
1136 // <scheme>://foo/bar/ -> <scheme>://foo/
1137 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
1139 OUString aURL = m_xIdentifier->getContentIdentifier();
1141 sal_Int32 nPos = aURL.lastIndexOf( '/' );
1142 if ( nPos == ( aURL.getLength() - 1 ) )
1144 // Trailing slash found. Skip.
1145 nPos = aURL.lastIndexOf( '/', nPos );
1148 sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos );
1149 if ( nPos1 != -1 )
1150 nPos1 = aURL.lastIndexOf( '/', nPos1 );
1152 if ( nPos1 == -1 )
1153 return OUString();
1155 return aURL.copy( 0, nPos + 1 );
1159 // Non-interface methods.
1162 // static
1163 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1164 const uno::Reference< uno::XComponentContext >& rxContext,
1165 const uno::Sequence< beans::Property >& rProperties,
1166 const ContentProperties& rData,
1167 const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider,
1168 const OUString& rContentId )
1170 // Note: Empty sequence means "get values of all supported properties".
1172 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
1173 = new ::ucbhelper::PropertyValueSet( rxContext );
1175 sal_Int32 nCount = rProperties.getLength();
1176 if ( nCount )
1178 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
1179 bool bTriedToGetAdditionalPropSet = false;
1181 const beans::Property* pProps = rProperties.getConstArray();
1182 for ( sal_Int32 n = 0; n < nCount; ++n )
1184 const beans::Property& rProp = pProps[ n ];
1186 // Process standard UCB, DAV and HTTP properties.
1187 const uno::Any & rValue = rData.getValue( rProp.Name );
1188 if ( rValue.hasValue() )
1190 xRow->appendObject( rProp, rValue );
1192 else
1194 // Process local Additional Properties.
1195 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1197 xAdditionalPropSet =
1198 rProvider->getAdditionalPropertySet( rContentId,
1199 false );
1200 bTriedToGetAdditionalPropSet = true;
1203 if ( !xAdditionalPropSet.is() ||
1204 !xRow->appendPropertySetValue(
1205 xAdditionalPropSet, rProp ) )
1207 // Append empty entry.
1208 xRow->appendVoid( rProp );
1213 else
1215 // Append all standard UCB, DAV and HTTP properties.
1217 const std::unique_ptr< PropertyValueMap > & xProps = rData.getProperties();
1219 ContentProvider * pProvider
1220 = static_cast< ContentProvider * >( rProvider.get() );
1221 beans::Property aProp;
1223 for ( const auto& rProp : *xProps )
1225 if ( pProvider->getProperty( rProp.first, aProp ) )
1226 xRow->appendObject( aProp, rProp.second.value() );
1229 // Append all local Additional Properties.
1230 uno::Reference< beans::XPropertySet > xSet =
1231 rProvider->getAdditionalPropertySet( rContentId, false );
1232 xRow->appendPropertySet( xSet );
1235 return uno::Reference< sdbc::XRow >( xRow.get() );
1239 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1240 const uno::Sequence< beans::Property >& rProperties,
1241 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1243 std::unique_ptr< ContentProperties > xProps;
1244 std::unique_ptr< ContentProperties > xCachedProps;
1245 std::unique_ptr< DAVResourceAccess > xResAccess;
1246 OUString aUnescapedTitle;
1247 bool bHasAll = false;
1248 uno::Reference< uno::XComponentContext > xContext;
1249 uno::Reference< ucb::XContentIdentifier > xIdentifier;
1250 rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider;
1253 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1255 aUnescapedTitle = SerfUri::unescape( m_aEscapedTitle );
1256 xContext.set( m_xContext );
1257 xIdentifier.set( m_xIdentifier );
1258 xProvider.set( m_xProvider.get() );
1259 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
1261 // First, ask cache...
1262 if ( m_xCachedProps.get() )
1264 xCachedProps.reset( new ContentProperties( *m_xCachedProps ) );
1266 std::vector< OUString > aMissingProps;
1267 if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) )
1269 // All properties are already in cache! No server access needed.
1270 bHasAll = true;
1273 // use the cached ContentProperties instance
1274 xProps.reset( new ContentProperties( *xCachedProps ) );
1278 if ( !m_bTransient && !bHasAll )
1280 // Obtain values from server...
1283 // First, identify whether resource is DAV or not
1284 bool bNetworkAccessAllowed = true;
1285 const ResourceType & rType = getResourceType( xEnv, xResAccess, &bNetworkAccessAllowed );
1287 if ( DAV == rType )
1289 // cache lookup... getResourceType may fill the props cache via
1290 // PROPFIND!
1291 if ( m_xCachedProps.get() )
1293 xCachedProps.reset(
1294 new ContentProperties( *m_xCachedProps ) );
1296 std::vector< OUString > aMissingProps;
1297 if ( xCachedProps->containsAllNames(
1298 rProperties, aMissingProps ) )
1300 // All properties are already in cache! No server access
1301 // needed.
1302 bHasAll = true;
1305 // use the cached ContentProperties instance
1306 xProps.reset( new ContentProperties( *xCachedProps ) );
1309 if ( !bHasAll )
1311 // Only DAV resources support PROPFIND
1312 std::vector< OUString > aPropNames;
1314 uno::Sequence< beans::Property > aProperties(
1315 rProperties.getLength() );
1317 if ( !m_aFailedPropNames.empty() )
1319 sal_Int32 nProps = 0;
1320 sal_Int32 nCount = rProperties.getLength();
1321 for ( sal_Int32 n = 0; n < nCount; ++n )
1323 const OUString & rName = rProperties[ n ].Name;
1325 if ( std::none_of(m_aFailedPropNames.begin(), m_aFailedPropNames.end(),
1326 [&rName](const OUString& rPropName) { return rPropName == rName; }) )
1328 aProperties[ nProps ] = rProperties[ n ];
1329 nProps++;
1333 aProperties.realloc( nProps );
1335 else
1337 aProperties = rProperties;
1340 if ( aProperties.getLength() > 0 )
1341 ContentProperties::UCBNamesToDAVNames(
1342 aProperties, aPropNames );
1344 if ( !aPropNames.empty() )
1346 std::vector< DAVResource > resources;
1349 xResAccess->PROPFIND(
1350 DAVZERO, aPropNames, resources, xEnv );
1352 if ( 1 == resources.size() )
1354 if ( xProps.get())
1355 xProps->addProperties(
1356 aPropNames,
1357 ContentProperties( resources[ 0 ] ));
1358 else
1359 xProps.reset(
1360 new ContentProperties( resources[ 0 ] ) );
1363 catch ( DAVException const & e )
1365 bNetworkAccessAllowed = bNetworkAccessAllowed &&
1366 shouldAccessNetworkAfterException( e );
1368 if ( !bNetworkAccessAllowed )
1370 cancelCommandExecution( e, xEnv );
1371 // unreachable
1378 if ( bNetworkAccessAllowed )
1380 // All properties obtained already?
1381 std::vector< OUString > aMissingProps;
1382 if ( !( xProps.get()
1383 && xProps->containsAllNames(
1384 rProperties, aMissingProps ) )
1385 || !m_bDidGetOrHead )
1387 // Possibly the missing props can be obtained using a HEAD
1388 // request.
1390 std::vector< OUString > aHeaderNames;
1391 ContentProperties::UCBNamesToHTTPNames(
1392 rProperties,
1393 aHeaderNames,
1394 true /* bIncludeUnmatched */ );
1396 if ( !aHeaderNames.empty() )
1400 DAVResource resource;
1401 xResAccess->HEAD( aHeaderNames, resource, xEnv );
1402 m_bDidGetOrHead = true;
1404 if ( xProps.get() )
1405 xProps->addProperties(
1406 aMissingProps,
1407 ContentProperties( resource ) );
1408 else
1409 xProps.reset ( new ContentProperties( resource ) );
1411 if ( m_eResourceType == NON_DAV )
1412 xProps->addProperties( aMissingProps,
1413 ContentProperties(
1414 aUnescapedTitle,
1415 false ) );
1417 catch ( DAVException const & e )
1419 // non "general-purpose servers" may not support HEAD requests
1420 // see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
1421 // In this case, perform a partial GET only to get the header info
1422 // vid. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
1423 // WARNING if the server does not support partial GETs,
1424 // the GET will transfer the whole content
1425 bool bError = true;
1426 DAVException aLastException = e;
1428 // According to the spec. the origin server SHOULD return
1429 // * 405 (Method Not Allowed):
1430 // the method is known but not allowed for the requested resource
1431 // * 501 (Not Implemented):
1432 // the method is unrecognized or not implemented
1433 // TODO SC_NOT_FOUND is only for google-code server
1434 if ( aLastException.getStatus() == SC_NOT_IMPLEMENTED ||
1435 aLastException.getStatus() == SC_METHOD_NOT_ALLOWED ||
1436 aLastException.getStatus() == SC_NOT_FOUND )
1438 lcl_sendPartialGETRequest( bError,
1439 aLastException,
1440 aMissingProps,
1441 aHeaderNames,
1442 xResAccess,
1443 xProps,
1444 xEnv );
1445 m_bDidGetOrHead = !bError;
1448 if ( bError )
1450 if ( !shouldAccessNetworkAfterException( aLastException ) )
1452 cancelCommandExecution( aLastException, xEnv );
1453 // unreachable
1461 // might trigger HTTP redirect.
1462 // Therefore, title must be updated here.
1463 SerfUri aUri( xResAccess->getURL() );
1464 aUnescapedTitle = aUri.GetPathBaseNameUnescaped();
1466 if ( rType == UNKNOWN )
1468 xProps.reset( new ContentProperties( aUnescapedTitle ) );
1471 // For DAV resources we only know the Title, for non-DAV
1472 // resources we additionally know that it is a document.
1474 if ( rType == DAV )
1476 //xProps.reset(
1477 // new ContentProperties( aUnescapedTitle ) );
1478 xProps->addProperty(
1479 "Title",
1480 uno::makeAny( aUnescapedTitle ),
1481 true );
1483 else
1485 if ( !xProps.get() )
1486 xProps.reset( new ContentProperties( aUnescapedTitle, false ) );
1487 else
1488 xProps->addProperty(
1489 "Title",
1490 uno::makeAny( aUnescapedTitle ),
1491 true );
1493 xProps->addProperty(
1494 "IsFolder",
1495 uno::makeAny( false ),
1496 true );
1497 xProps->addProperty(
1498 "IsDocument",
1499 uno::makeAny( true ),
1500 true );
1501 xProps->addProperty(
1502 "ContentType",
1503 uno::makeAny( OUString(WEBDAV_CONTENT_TYPE) ),
1504 true );
1507 else
1509 // No server access for just created (not yet committed) objects.
1510 // Only a minimal set of properties supported at this stage.
1511 if (m_bTransient)
1512 xProps.reset( new ContentProperties( aUnescapedTitle,
1513 m_bCollection ) );
1516 sal_Int32 nCount = rProperties.getLength();
1517 for ( sal_Int32 n = 0; n < nCount; ++n )
1519 const OUString rName = rProperties[ n ].Name;
1520 if ( rName == "BaseURI" )
1522 // Add BaseURI property, if requested.
1523 xProps->addProperty(
1524 "BaseURI",
1525 uno::makeAny( getBaseURI( xResAccess ) ),
1526 true );
1528 else if ( rName == "CreatableContentsInfo" )
1530 // Add CreatableContentsInfo property, if requested.
1531 bool bFolder = false;
1532 xProps->getValue( "IsFolder" )
1533 >>= bFolder;
1534 xProps->addProperty(
1535 "CreatableContentsInfo",
1536 uno::makeAny( bFolder
1537 ? queryCreatableContentsInfo()
1538 : uno::Sequence< ucb::ContentInfo >() ),
1539 true );
1543 uno::Reference< sdbc::XRow > xResultRow
1544 = getPropertyValues( xContext,
1545 rProperties,
1546 *xProps,
1547 xProvider,
1548 xIdentifier->getContentIdentifier() );
1551 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1553 if ( !m_xCachedProps.get() )
1554 m_xCachedProps.reset( new CachableContentProperties( *xProps ) );
1555 else
1556 m_xCachedProps->addProperties( *xProps );
1558 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
1559 m_aEscapedTitle = SerfUri::escapeSegment( aUnescapedTitle );
1562 return xResultRow;
1566 uno::Sequence< uno::Any > Content::setPropertyValues(
1567 const uno::Sequence< beans::PropertyValue >& rValues,
1568 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1570 uno::Reference< ucb::XContentIdentifier > xIdentifier;
1571 rtl::Reference< ContentProvider > xProvider;
1572 bool bTransient;
1573 std::unique_ptr< DAVResourceAccess > xResAccess;
1576 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1578 xProvider.set( m_pProvider );
1579 xIdentifier.set( m_xIdentifier );
1580 bTransient = m_bTransient;
1581 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
1584 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1585 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1586 sal_Int32 nChanged = 0;
1588 beans::PropertyChangeEvent aEvent;
1589 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1590 aEvent.Further = false;
1591 // aEvent.PropertyName =
1592 aEvent.PropertyHandle = -1;
1593 // aEvent.OldValue =
1594 // aEvent.NewValue =
1596 std::vector< ProppatchValue > aProppatchValues;
1597 std::vector< sal_Int32 > aProppatchPropsPositions;
1599 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1600 bool bTriedToGetAdditionalPropSet = false;
1602 bool bExchange = false;
1603 OUString aNewTitle;
1604 OUString aOldTitle;
1605 sal_Int32 nTitlePos = -1;
1607 uno::Reference< beans::XPropertySetInfo > xInfo;
1609 const beans::PropertyValue* pValues = rValues.getConstArray();
1610 sal_Int32 nCount = rValues.getLength();
1611 for ( sal_Int32 n = 0; n < nCount; ++n )
1613 const beans::PropertyValue& rValue = pValues[ n ];
1614 const OUString & rName = rValue.Name;
1616 beans::Property aTmpProp;
1617 xProvider->getProperty( rName, aTmpProp );
1619 if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY )
1621 // Read-only property!
1622 aRet[ n ] <<= lang::IllegalAccessException(
1623 "Property is read-only!",
1624 static_cast< cppu::OWeakObject * >( this ) );
1625 continue;
1629 // Mandatory props.
1632 if ( rName == "ContentType" )
1634 // Read-only property!
1635 aRet[ n ] <<= lang::IllegalAccessException(
1636 "Property is read-only!",
1637 static_cast< cppu::OWeakObject * >( this ) );
1639 else if ( rName == "IsDocument" )
1641 // Read-only property!
1642 aRet[ n ] <<= lang::IllegalAccessException(
1643 "Property is read-only!",
1644 static_cast< cppu::OWeakObject * >( this ) );
1646 else if ( rName == "IsFolder" )
1648 // Read-only property!
1649 aRet[ n ] <<= lang::IllegalAccessException(
1650 "Property is read-only!",
1651 static_cast< cppu::OWeakObject * >( this ) );
1653 else if ( rName == "Title" )
1655 OUString aNewValue;
1656 if ( rValue.Value >>= aNewValue )
1658 // No empty titles!
1659 if ( aNewValue.getLength() > 0 )
1663 SerfUri aURI( xIdentifier->getContentIdentifier() );
1664 aOldTitle = aURI.GetPathBaseNameUnescaped();
1666 if ( aNewValue != aOldTitle )
1668 // modified title -> modified URL -> exchange !
1669 if ( !bTransient )
1670 bExchange = true;
1672 // new value will be set later...
1673 aNewTitle = aNewValue;
1675 // remember position within sequence of values (for
1676 // error handling).
1677 nTitlePos = n;
1680 catch ( DAVException const & )
1682 aRet[ n ] <<= lang::IllegalArgumentException(
1683 "Invalid content identifier!",
1684 static_cast< cppu::OWeakObject * >( this ),
1685 -1 );
1688 else
1690 aRet[ n ] <<= lang::IllegalArgumentException(
1691 "Empty title not allowed!",
1692 static_cast< cppu::OWeakObject * >( this ),
1693 -1 );
1696 else
1698 aRet[ n ] <<= beans::IllegalTypeException(
1699 "Property value has wrong type!",
1700 static_cast< cppu::OWeakObject * >( this ) );
1703 else
1706 // Optional props.
1709 OUString aSpecialName;
1710 bool bIsSpecial = DAVProperties::isUCBSpecialProperty( rName, aSpecialName );
1712 if ( !xInfo.is() )
1713 xInfo = getPropertySetInfo( xEnv,
1714 false /* don't cache data */ );
1716 if ( !xInfo->hasPropertyByName( bIsSpecial ? aSpecialName : rName ) )
1718 // Check, whether property exists. Skip otherwise.
1719 // PROPPATCH::set would add the property automatically, which
1720 // is not allowed for "setPropertyValues" command!
1721 aRet[ n ] <<= beans::UnknownPropertyException(
1722 "Property is unknown!",
1723 static_cast< cppu::OWeakObject * >( this ) );
1724 continue;
1727 if ( rName == "Size" )
1729 // Read-only property!
1730 aRet[ n ] <<= lang::IllegalAccessException(
1731 "Property is read-only!",
1732 static_cast< cppu::OWeakObject * >( this ) );
1734 else if ( rName == "DateCreated" )
1736 // Read-only property!
1737 aRet[ n ] <<= lang::IllegalAccessException(
1738 "Property is read-only!",
1739 static_cast< cppu::OWeakObject * >( this ) );
1741 else if ( rName == "DateModified" )
1743 // Read-only property!
1744 aRet[ n ] <<= lang::IllegalAccessException(
1745 "Property is read-only!",
1746 static_cast< cppu::OWeakObject * >( this ) );
1748 else if ( rName == "MediaType" )
1750 // Read-only property!
1751 // (but could be writable, if 'getcontenttype' would be)
1752 aRet[ n ] <<= lang::IllegalAccessException(
1753 "Property is read-only!",
1754 static_cast< cppu::OWeakObject * >( this ) );
1756 if ( rName == "CreatableContentsInfo" )
1758 // Read-only property!
1759 aRet[ n ] <<= lang::IllegalAccessException(
1760 "Property is read-only!",
1761 static_cast< cppu::OWeakObject * >( this ) );
1763 else
1765 if ( getResourceType( xEnv, xResAccess ) == DAV )
1767 // Property value will be set on server.
1768 ProppatchValue aValue( PROPSET, rName, rValue.Value );
1769 aProppatchValues.push_back( aValue );
1771 // remember position within sequence of values (for
1772 // error handling).
1773 aProppatchPropsPositions.push_back( n );
1775 else
1777 // Property value will be stored in local property store.
1778 if ( !bTriedToGetAdditionalPropSet &&
1779 !xAdditionalPropSet.is() )
1781 xAdditionalPropSet
1782 = getAdditionalPropertySet( false );
1783 bTriedToGetAdditionalPropSet = true;
1786 if ( xAdditionalPropSet.is() )
1790 uno::Any aOldValue
1791 = xAdditionalPropSet->getPropertyValue( rName );
1792 if ( aOldValue != rValue.Value )
1794 xAdditionalPropSet->setPropertyValue(
1795 rName, rValue.Value );
1797 aEvent.PropertyName = rName;
1798 aEvent.OldValue = aOldValue;
1799 aEvent.NewValue = rValue.Value;
1801 aChanges.getArray()[ nChanged ] = aEvent;
1802 nChanged++;
1805 catch ( beans::UnknownPropertyException const & e )
1807 aRet[ n ] <<= e;
1809 catch ( lang::WrappedTargetException const & e )
1811 aRet[ n ] <<= e;
1813 catch ( beans::PropertyVetoException const & e )
1815 aRet[ n ] <<= e;
1817 catch ( lang::IllegalArgumentException const & e )
1819 aRet[ n ] <<= e;
1822 else
1824 aRet[ n ] <<= uno::Exception(
1825 "No property set for storing the value!",
1826 static_cast< cppu::OWeakObject * >( this ) );
1831 } // for
1833 if ( !bTransient && (!aProppatchValues.empty()) )
1837 // Set property values at server.
1838 xResAccess->PROPPATCH( aProppatchValues, xEnv );
1840 for ( const auto& rProppatchValue : aProppatchValues )
1842 aEvent.PropertyName = rProppatchValue.name;
1843 aEvent.OldValue = uno::Any(); // @@@ too expensive to obtain!
1844 aEvent.NewValue = rProppatchValue.value;
1846 aChanges.getArray()[ nChanged ] = aEvent;
1847 nChanged++;
1850 catch ( DAVException const & e )
1852 // SAL_WARN( "ucb.ucp.webdav",
1853 // "Content::setPropertyValues - PROPPATCH failed!" );
1855 #if 1
1856 cancelCommandExecution( e, xEnv );
1857 // unreachable
1858 #else
1859 // Note: PROPPATCH either sets ALL property values OR NOTHING.
1861 std::vector< sal_Int32 >::const_iterator it
1862 = aProppatchPropsPositions.begin();
1863 std::vector< sal_Int32 >::const_iterator end
1864 = aProppatchPropsPositions.end();
1866 while ( it != end )
1868 // Set error.
1869 aRet[ (*it) ] <<= MapDAVException( e, true );
1870 ++it;
1872 #endif
1876 if ( bExchange )
1878 // Assemble new content identifier...
1880 OUString aNewURL = getParentURL();
1881 if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
1882 aNewURL += "/";
1884 aNewURL += SerfUri::escapeSegment( aNewTitle );
1886 uno::Reference< ucb::XContentIdentifier > xNewId
1887 = new ::ucbhelper::ContentIdentifier( aNewURL );
1888 uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier;
1892 SerfUri sourceURI( xOldId->getContentIdentifier() );
1893 SerfUri targetURI( xNewId->getContentIdentifier() );
1894 targetURI.SetScheme( sourceURI.GetScheme() );
1896 xResAccess->MOVE(
1897 sourceURI.GetPath(), targetURI.GetURI(), false, xEnv );
1898 // @@@ Should check for resources that could not be moved
1899 // (due to source access or target overwrite) and send
1900 // this information through the interaction handler.
1902 // @@@ Existing content should be checked to see if it needs
1903 // to be deleted at the source
1905 // @@@ Existing content should be checked to see if it has
1906 // been overwritten at the target
1908 if ( exchangeIdentity( xNewId ) )
1910 xResAccess->setURL( aNewURL );
1912 // DAV resources store all additional props on server!
1913 // // Adapt Additional Core Properties.
1914 // renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1915 // xNewId->getContentIdentifier(),
1916 // true );
1918 else
1920 // Do not set new title!
1921 aNewTitle.clear();
1923 // Set error .
1924 aRet[ nTitlePos ] <<= uno::Exception(
1925 "Exchange failed!",
1926 static_cast< cppu::OWeakObject * >( this ) );
1929 catch ( DAVException const & e )
1931 // Do not set new title!
1932 aNewTitle.clear();
1934 // Set error .
1935 aRet[ nTitlePos ] = MapDAVException( e, true );
1939 if ( aNewTitle.getLength() )
1941 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1943 aEvent.PropertyName = "Title";
1944 aEvent.OldValue <<= aOldTitle;
1945 aEvent.NewValue <<= aNewTitle;
1947 m_aEscapedTitle = SerfUri::escapeSegment( aNewTitle );
1949 aChanges.getArray()[ nChanged ] = aEvent;
1950 nChanged++;
1953 if ( nChanged > 0 )
1955 aChanges.realloc( nChanged );
1956 notifyPropertiesChange( aChanges );
1960 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1961 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
1964 return aRet;
1968 uno::Any Content::open(
1969 const ucb::OpenCommandArgument2 & rArg,
1970 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1972 uno::Any aRet;
1974 bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) ||
1975 ( rArg.Mode == ucb::OpenMode::FOLDERS ) ||
1976 ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) );
1977 if ( bOpenFolder )
1979 if ( isFolder( xEnv ) )
1981 // Open collection.
1983 uno::Reference< ucb::XDynamicResultSet > xSet
1984 = new DynamicResultSet( m_xContext, this, rArg, xEnv );
1985 aRet <<= xSet;
1987 else
1989 // Error: Not a folder!
1991 OUString aMsg( "Non-folder resource cannot be opened as folder! Wrong Open Mode!" );
1993 ucbhelper::cancelCommandExecution(
1994 uno::makeAny(
1995 lang::IllegalArgumentException(
1996 aMsg,
1997 static_cast< cppu::OWeakObject * >( this ),
1998 -1 ) ),
1999 xEnv );
2000 // Unreachable
2004 if ( rArg.Sink.is() )
2006 // Open document.
2008 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
2009 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
2011 // Currently(?) unsupported.
2012 ucbhelper::cancelCommandExecution(
2013 uno::makeAny(
2014 ucb::UnsupportedOpenModeException(
2015 OUString(),
2016 static_cast< cppu::OWeakObject * >( this ),
2017 sal_Int16( rArg.Mode ) ) ),
2018 xEnv );
2019 // Unreachable
2022 uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
2023 if ( xOut.is() )
2025 // PUSH: write data
2028 std::unique_ptr< DAVResourceAccess > xResAccess;
2031 osl::MutexGuard aGuard( m_aMutex );
2033 xResAccess.reset(
2034 new DAVResourceAccess( *m_xResAccess ) );
2037 DAVResource aResource;
2038 std::vector< OUString > aHeaders;
2040 xResAccess->GET( xOut, aHeaders, aResource, xEnv );
2041 m_bDidGetOrHead = true;
2044 osl::MutexGuard aGuard( m_aMutex );
2046 // cache headers.
2047 if ( !m_xCachedProps.get())
2048 m_xCachedProps.reset(
2049 new CachableContentProperties( ContentProperties( aResource ) ) );
2050 else
2051 m_xCachedProps->addProperties( ContentProperties( aResource ) );
2053 m_xResAccess.reset(
2054 new DAVResourceAccess( *xResAccess ) );
2057 catch ( DAVException const & e )
2059 cancelCommandExecution( e, xEnv );
2060 // Unreachable
2063 else
2065 uno::Reference< io::XActiveDataSink > xDataSink( rArg.Sink, uno::UNO_QUERY );
2066 if ( xDataSink.is() )
2068 // PULL: wait for client read
2071 std::unique_ptr< DAVResourceAccess > xResAccess;
2073 osl::MutexGuard aGuard( m_aMutex );
2075 xResAccess.reset(
2076 new DAVResourceAccess( *m_xResAccess ) );
2079 // fill inputstream sync; return if all data present
2080 DAVResource aResource;
2081 std::vector< OUString > aHeaders;
2083 uno::Reference< io::XInputStream > xIn
2084 = xResAccess->GET( aHeaders, aResource, xEnv );
2085 m_bDidGetOrHead = true;
2088 osl::MutexGuard aGuard( m_aMutex );
2090 // cache headers.
2091 if ( !m_xCachedProps.get())
2092 m_xCachedProps.reset(
2093 new CachableContentProperties( ContentProperties( aResource ) ) );
2094 else
2095 m_xCachedProps->addProperties(
2096 aResource.properties );
2098 m_xResAccess.reset(
2099 new DAVResourceAccess( *xResAccess ) );
2102 xDataSink->setInputStream( xIn );
2104 catch ( DAVException const & e )
2106 cancelCommandExecution( e, xEnv );
2107 // Unreachable
2110 else
2112 // Note: aOpenCommand.Sink may contain an XStream
2113 // implementation. Support for this type of
2114 // sink is optional...
2115 ucbhelper::cancelCommandExecution(
2116 uno::makeAny(
2117 ucb::UnsupportedDataSinkException(
2118 OUString(),
2119 static_cast< cppu::OWeakObject * >( this ),
2120 rArg.Sink ) ),
2121 xEnv );
2122 // Unreachable
2127 return aRet;
2131 void Content::post(
2132 const ucb::PostCommandArgument2 & rArg,
2133 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2135 uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY );
2136 if ( xSink.is() )
2140 std::unique_ptr< DAVResourceAccess > xResAccess;
2142 osl::MutexGuard aGuard( m_aMutex );
2143 xResAccess.reset(
2144 new DAVResourceAccess( *m_xResAccess ) );
2147 uno::Reference< io::XInputStream > xResult
2148 = xResAccess->POST( rArg.MediaType,
2149 rArg.Referer,
2150 rArg.Source,
2151 xEnv );
2154 osl::MutexGuard aGuard( m_aMutex );
2155 m_xResAccess.reset(
2156 new DAVResourceAccess( *xResAccess ) );
2159 xSink->setInputStream( xResult );
2161 catch ( DAVException const & e )
2163 cancelCommandExecution( e, xEnv, true );
2164 // Unreachable
2167 else
2169 uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
2170 if ( xResult.is() )
2174 std::unique_ptr< DAVResourceAccess > xResAccess;
2176 osl::MutexGuard aGuard( m_aMutex );
2177 xResAccess.reset(
2178 new DAVResourceAccess( *m_xResAccess ) );
2181 xResAccess->POST( rArg.MediaType,
2182 rArg.Referer,
2183 rArg.Source,
2184 xResult,
2185 xEnv );
2188 osl::MutexGuard aGuard( m_aMutex );
2189 m_xResAccess.reset(
2190 new DAVResourceAccess( *xResAccess ) );
2193 catch ( DAVException const & e )
2195 cancelCommandExecution( e, xEnv, true );
2196 // Unreachable
2199 else
2201 ucbhelper::cancelCommandExecution(
2202 uno::makeAny(
2203 ucb::UnsupportedDataSinkException(
2204 OUString(),
2205 static_cast< cppu::OWeakObject * >( this ),
2206 rArg.Sink ) ),
2207 xEnv );
2208 // Unreachable
2214 void Content::queryChildren( ContentRefList& rChildren )
2216 // Obtain a list with a snapshot of all currently instantiated contents
2217 // from provider and extract the contents which are direct children
2218 // of this content.
2220 ::ucbhelper::ContentRefList aAllContents;
2221 m_xProvider->queryExistingContents( aAllContents );
2223 OUString aURL = m_xIdentifier->getContentIdentifier();
2224 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
2226 if ( nURLPos != ( aURL.getLength() - 1 ) )
2228 // No trailing slash found. Append.
2229 aURL += "/";
2232 sal_Int32 nLen = aURL.getLength();
2234 for ( const auto& rChild : aAllContents )
2236 ::ucbhelper::ContentImplHelperRef xChild = rChild;
2237 OUString aChildURL
2238 = xChild->getIdentifier()->getContentIdentifier();
2240 // Is aURL a prefix of aChildURL?
2241 if ( ( aChildURL.getLength() > nLen ) &&
2242 ( aChildURL.startsWith( aURL ) ) )
2244 sal_Int32 nPos = nLen;
2245 nPos = aChildURL.indexOf( '/', nPos );
2247 if ( ( nPos == -1 ) ||
2248 ( nPos == ( aChildURL.getLength() - 1 ) ) )
2250 // No further slashes / only a final slash. It's a child!
2251 rChildren.push_back(
2252 ::http_dav_ucp::Content::ContentRef(
2253 static_cast< ::http_dav_ucp::Content * >(
2254 xChild.get() ) ) );
2261 void Content::insert(
2262 const uno::Reference< io::XInputStream > & xInputStream,
2263 bool bReplaceExisting,
2264 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2266 bool bTransient, bCollection;
2267 OUString aEscapedTitle;
2268 std::unique_ptr< DAVResourceAccess > xResAccess;
2271 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2273 bTransient = m_bTransient;
2274 bCollection = m_bCollection;
2275 aEscapedTitle = m_aEscapedTitle;
2276 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
2279 // Check, if all required properties are present.
2281 if ( aEscapedTitle.isEmpty() )
2283 SAL_WARN( "ucb.ucp.webdav", "Content::insert - Title missing!" );
2285 uno::Sequence<OUString> aProps { "Title" };
2286 ucbhelper::cancelCommandExecution(
2287 uno::makeAny( ucb::MissingPropertiesException(
2288 OUString(),
2289 static_cast< cppu::OWeakObject * >( this ),
2290 aProps ) ),
2291 Environment );
2292 // Unreachable
2295 if ( !bReplaceExisting )
2297 /* [RFC 2616] - HTTP
2299 The PUT method requests that the enclosed entity be stored under the
2300 supplied Request-URI. If the Request-URI refers to an already
2301 existing resource, the enclosed entity SHOULD be considered as a
2302 modified version of the one residing on the origin server.
2305 /* [RFC 2518] - WebDAV
2307 MKCOL creates a new collection resource at the location specified by
2308 the Request-URI. If the resource identified by the Request-URI is
2309 non-null then the MKCOL MUST fail.
2312 // ==> Complain on PUT, continue on MKCOL.
2313 if ( !bTransient || !bCollection )
2315 #undef ERROR
2316 ucb::UnsupportedNameClashException aEx(
2317 "Unable to write without overwrite!",
2318 static_cast< cppu::OWeakObject * >( this ),
2319 ucb::NameClash::ERROR );
2321 uno::Reference< task::XInteractionHandler > xIH;
2323 if ( Environment.is() )
2324 xIH = Environment->getInteractionHandler();
2326 if ( xIH.is() )
2328 uno::Any aExAsAny( uno::makeAny( aEx ) );
2330 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
2331 = new ucbhelper::SimpleInteractionRequest(
2332 aExAsAny,
2333 ContinuationFlags::Approve
2334 | ContinuationFlags::Disapprove );
2335 xIH->handle( xRequest.get() );
2337 const ContinuationFlags nResp = xRequest->getResponse();
2339 switch ( nResp )
2341 case ContinuationFlags::NONE:
2342 // Not handled; throw.
2343 throw aEx;
2344 // break;
2346 case ContinuationFlags::Approve:
2347 // Continue -> Overwrite.
2348 bReplaceExisting = true;
2349 break;
2351 case ContinuationFlags::Disapprove:
2352 // Abort.
2353 throw ucb::CommandFailedException(
2354 OUString(),
2355 uno::Reference< uno::XInterface >(),
2356 aExAsAny );
2357 // break;
2359 default:
2360 SAL_WARN( "ucb.ucp.webdav",
2361 "Content::insert - "
2362 "Unknown interaction selection!" );
2363 throw ucb::CommandFailedException(
2364 "Unknown interaction selection!",
2365 uno::Reference< uno::XInterface >(),
2366 aExAsAny );
2367 // break;
2370 else
2372 // No IH; throw.
2373 throw aEx;
2378 if ( bTransient )
2380 // Assemble new content identifier...
2381 OUString aURL = getParentURL();
2382 if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2383 aURL += "/";
2385 aURL += aEscapedTitle;
2389 xResAccess->setURL( aURL );
2391 if ( bCollection )
2392 xResAccess->MKCOL( Environment );
2393 else
2394 xResAccess->PUT( xInputStream, Environment );
2396 catch ( DAVException const & except )
2398 if ( bCollection )
2400 if ( except.getStatus() == SC_METHOD_NOT_ALLOWED )
2402 // [RFC 2518] - WebDAV
2403 // 405 (Method Not Allowed) - MKCOL can only be
2404 // executed on a deleted/non-existent resource.
2406 if ( bReplaceExisting )
2408 // Destroy old resource.
2411 xResAccess->DESTROY( Environment );
2413 catch ( DAVException const & e )
2415 cancelCommandExecution( e, Environment, true );
2416 // Unreachable
2419 // Insert (recursion!).
2420 insert( xInputStream, bReplaceExisting, Environment );
2423 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2424 m_xResAccess.reset(
2425 new DAVResourceAccess( *xResAccess ) );
2428 // Success!
2429 return;
2431 else
2433 OUString aTitle;
2436 SerfUri aURI( aURL );
2437 aTitle = aURI.GetPathBaseNameUnescaped();
2439 catch ( DAVException const & )
2443 ucbhelper::cancelCommandExecution(
2444 uno::makeAny(
2445 ucb::NameClashException(
2446 OUString(),
2447 static_cast< cppu::OWeakObject * >( this ),
2448 task::InteractionClassification_ERROR,
2449 aTitle ) ),
2450 Environment );
2451 // Unreachable
2456 cancelCommandExecution( except, Environment, true );
2457 // Unreachable
2461 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2462 m_xIdentifier
2463 = new ::ucbhelper::ContentIdentifier( aURL );
2466 inserted();
2469 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2470 m_bTransient = false;
2473 else
2475 if ( !xInputStream.is() )
2477 ucbhelper::cancelCommandExecution(
2478 uno::makeAny(
2479 ucb::MissingInputStreamException(
2480 OUString(),
2481 static_cast< cppu::OWeakObject * >( this ) ) ),
2482 Environment );
2483 // Unreachable
2488 xResAccess->PUT( xInputStream, Environment );
2490 catch ( DAVException const & e )
2492 cancelCommandExecution( e, Environment, true );
2493 // Unreachable
2498 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2499 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
2504 void Content::transfer(
2505 const ucb::TransferInfo & rArgs,
2506 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2508 uno::Reference< uno::XComponentContext > xContext;
2509 uno::Reference< ucb::XContentIdentifier > xIdentifier;
2510 uno::Reference< ucb::XContentProvider > xProvider;
2511 std::unique_ptr< DAVResourceAccess > xResAccess;
2514 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2516 xContext.set( m_xContext );
2517 xIdentifier.set( m_xIdentifier );
2518 xProvider.set( m_xProvider.get() );
2519 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
2522 OUString aTargetURI;
2525 SerfUri sourceURI( rArgs.SourceURL );
2526 SerfUri targetURI( xIdentifier->getContentIdentifier() );
2527 aTargetURI = targetURI.GetPathBaseNameUnescaped();
2529 // Check source's and target's URL scheme
2531 OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase();
2532 if ( aScheme == VNDSUNSTARWEBDAV_URL_SCHEME)
2534 sourceURI.SetScheme( HTTP_URL_SCHEME );
2536 else if ( aScheme == VNDSUNSTARWEBDAVS_URL_SCHEME)
2538 sourceURI.SetScheme( HTTPS_URL_SCHEME );
2540 else if ( aScheme == DAV_URL_SCHEME )
2542 sourceURI.SetScheme( HTTP_URL_SCHEME );
2544 else if ( aScheme == DAVS_URL_SCHEME )
2546 sourceURI.SetScheme( HTTPS_URL_SCHEME );
2548 else if (aScheme == WEBDAV_URL_SCHEME)
2550 sourceURI.SetScheme(HTTP_URL_SCHEME);
2552 else if (aScheme == WEBDAVS_URL_SCHEME)
2554 sourceURI.SetScheme(HTTPS_URL_SCHEME);
2556 else
2558 if ( aScheme != HTTP_URL_SCHEME && aScheme != HTTPS_URL_SCHEME )
2560 ucbhelper::cancelCommandExecution(
2561 uno::makeAny(
2562 ucb::InteractiveBadTransferURLException(
2563 "Unsupported URL scheme!",
2564 static_cast< cppu::OWeakObject * >( this ) ) ),
2565 Environment );
2566 // Unreachable
2570 aScheme = targetURI.GetScheme().toAsciiLowerCase();
2571 if ( aScheme == VNDSUNSTARWEBDAV_URL_SCHEME)
2572 targetURI.SetScheme( HTTP_URL_SCHEME );
2573 else if ( aScheme == VNDSUNSTARWEBDAVS_URL_SCHEME)
2574 targetURI.SetScheme( HTTPS_URL_SCHEME );
2575 else if ( aScheme == DAV_URL_SCHEME )
2576 targetURI.SetScheme( HTTP_URL_SCHEME );
2577 else if ( aScheme == DAVS_URL_SCHEME )
2578 targetURI.SetScheme( HTTPS_URL_SCHEME );
2579 else if (aScheme == WEBDAV_URL_SCHEME)
2580 targetURI.SetScheme(HTTP_URL_SCHEME);
2581 else if (aScheme == WEBDAVS_URL_SCHEME)
2582 targetURI.SetScheme(HTTPS_URL_SCHEME);
2584 // @@@ This implementation of 'transfer' only works
2585 // if the source and target are located at same host.
2586 // (Neon does not support cross-server copy/move)
2588 // Check for same host
2590 if ( sourceURI.GetHost().getLength() &&
2591 ( sourceURI.GetHost() != targetURI.GetHost() ) )
2593 ucbhelper::cancelCommandExecution(
2594 uno::makeAny( ucb::InteractiveBadTransferURLException(
2595 "Different hosts!",
2596 static_cast< cppu::OWeakObject * >( this ) ) ),
2597 Environment );
2598 // Unreachable
2601 OUString aTitle = rArgs.NewTitle;
2603 if ( aTitle.isEmpty() )
2604 aTitle = sourceURI.GetPathBaseNameUnescaped();
2606 if ( aTitle == "/" )
2608 // kso: ???
2609 aTitle.clear();
2612 targetURI.AppendPath( aTitle );
2614 OUString aTargetURL = xIdentifier->getContentIdentifier();
2615 if ( ( aTargetURL.lastIndexOf( '/' ) + 1 )
2616 != aTargetURL.getLength() )
2617 aTargetURL += "/";
2619 aTargetURL += aTitle;
2621 uno::Reference< ucb::XContentIdentifier > xTargetId
2622 = new ::ucbhelper::ContentIdentifier( aTargetURL );
2624 DAVResourceAccess aSourceAccess( xContext,
2625 xResAccess->getSessionFactory(),
2626 sourceURI.GetURI() );
2628 if ( rArgs.MoveData )
2630 uno::Reference< ucb::XContentIdentifier > xId
2631 = new ::ucbhelper::ContentIdentifier( rArgs.SourceURL );
2633 // Note: The static cast is okay here, because its sure that
2634 // xProvider is always the WebDAVContentProvider.
2635 rtl::Reference< Content > xSource
2636 = static_cast< Content * >(
2637 xProvider->queryContent( xId ).get() );
2639 // [RFC 2518] - WebDAV
2640 // If a resource exists at the destination and the Overwrite
2641 // header is "T" then prior to performing the move the server
2642 // MUST perform a DELETE with "Depth: infinity" on the
2643 // destination resource. If the Overwrite header is set to
2644 // "F" then the operation will fail.
2646 aSourceAccess.MOVE( sourceURI.GetPath(),
2647 targetURI.GetURI(),
2648 rArgs.NameClash
2649 == ucb::NameClash::OVERWRITE,
2650 Environment );
2652 if ( xSource.is() )
2654 // Propagate destruction to listeners.
2655 xSource->destroy( true );
2658 // DAV resources store all additional props on server!
2659 // // Rename own and all children's Additional Core Properties.
2660 // renameAdditionalPropertySet( xId->getContentIdentifier(),
2661 // xTargetId->getContentIdentifier(),
2662 // true );
2664 else
2666 // [RFC 2518] - WebDAV
2667 // If a resource exists at the destination and the Overwrite
2668 // header is "T" then prior to performing the copy the server
2669 // MUST perform a DELETE with "Depth: infinity" on the
2670 // destination resource. If the Overwrite header is set to
2671 // "F" then the operation will fail.
2673 aSourceAccess.COPY( sourceURI.GetPath(),
2674 targetURI.GetURI(),
2675 rArgs.NameClash
2676 == ucb::NameClash::OVERWRITE,
2677 Environment );
2679 // DAV resources store all additional props on server!
2680 // // Copy own and all children's Additional Core Properties.
2681 // copyAdditionalPropertySet( xId->getContentIdentifier(),
2682 // xTargetId->getContentIdentifier(),
2683 // true );
2686 // Note: The static cast is okay here, because its sure that
2687 // xProvider is always the WebDAVContentProvider.
2688 rtl::Reference< Content > xTarget
2689 = static_cast< Content * >(
2690 xProvider->queryContent( xTargetId ).get() );
2692 // Announce transferred content in its new folder.
2693 xTarget->inserted();
2695 catch ( ucb::IllegalIdentifierException const & )
2697 // queryContent
2699 catch ( DAVException const & e )
2701 // [RFC 2518] - WebDAV
2702 // 412 (Precondition Failed) - The server was unable to maintain
2703 // the liveness of the properties listed in the propertybehavior
2704 // XML element or the Overwrite header is "F" and the state of
2705 // the destination resource is non-null.
2707 if ( e.getStatus() == SC_PRECONDITION_FAILED )
2709 switch ( rArgs.NameClash )
2711 case 0/*ucb::NameClash::ERROR*/:
2713 ucbhelper::cancelCommandExecution(
2714 uno::makeAny(
2715 ucb::NameClashException(
2716 OUString(),
2717 static_cast< cppu::OWeakObject * >( this ),
2718 task::InteractionClassification_ERROR,
2719 aTargetURI ) ),
2720 Environment );
2721 // Unreachable
2723 [[fallthrough]];
2725 case ucb::NameClash::OVERWRITE:
2726 break;
2728 case ucb::NameClash::KEEP: // deprecated
2729 case ucb::NameClash::RENAME:
2730 case ucb::NameClash::ASK:
2731 default:
2733 ucbhelper::cancelCommandExecution(
2734 uno::makeAny(
2735 ucb::UnsupportedNameClashException(
2736 OUString(),
2737 static_cast< cppu::OWeakObject * >( this ),
2738 rArgs.NameClash ) ),
2739 Environment );
2740 // Unreachable
2745 cancelCommandExecution( e, Environment, true );
2746 // Unreachable
2750 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2751 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
2756 void Content::destroy( bool bDeletePhysical )
2758 // @@@ take care about bDeletePhysical -> trashcan support
2760 uno::Reference< ucb::XContent > xThis = this;
2762 deleted();
2764 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2766 // Process instantiated children...
2768 ::http_dav_ucp::Content::ContentRefList aChildren;
2769 queryChildren( aChildren );
2771 for ( auto& rChild : aChildren )
2773 rChild->destroy( bDeletePhysical );
2778 bool Content::supportsExclusiveWriteLock(
2779 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2781 if ( getResourceType( Environment ) == DAV )
2783 if ( m_xCachedProps.get() )
2785 uno::Sequence< ucb::LockEntry > aSupportedLocks;
2786 if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK )
2787 >>= aSupportedLocks )
2789 for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n )
2791 if ( aSupportedLocks[ n ].Scope
2792 == ucb::LockScope_EXCLUSIVE &&
2793 aSupportedLocks[ n ].Type
2794 == ucb::LockType_WRITE )
2795 return true;
2800 return false;
2804 void Content::lock(
2805 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2809 std::unique_ptr< DAVResourceAccess > xResAccess;
2811 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2812 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
2815 uno::Any aOwnerAny;
2816 aOwnerAny <<= OUString( "http://ucb.openoffice.org" );
2818 ucb::Lock aLock(
2819 ucb::LockScope_EXCLUSIVE,
2820 ucb::LockType_WRITE,
2821 ucb::LockDepth_ZERO,
2822 aOwnerAny,
2823 180, // lock timeout in secs
2824 //-1, // infinite lock
2825 uno::Sequence< OUString >() );
2827 xResAccess->LOCK( aLock, Environment );
2828 m_bLocked = true;
2831 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2832 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
2835 catch ( DAVException const & e )
2837 cancelCommandExecution( e, Environment, false );
2838 // Unreachable
2843 void Content::unlock(
2844 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2848 std::unique_ptr< DAVResourceAccess > xResAccess;
2850 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2851 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
2854 xResAccess->UNLOCK( Environment );
2855 m_bLocked = false;
2858 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2859 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
2862 catch ( DAVException const & e )
2864 cancelCommandExecution( e, Environment, false );
2865 // Unreachable
2870 bool Content::exchangeIdentity(
2871 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2873 if ( !xNewId.is() )
2874 return false;
2876 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
2878 uno::Reference< ucb::XContent > xThis = this;
2880 // Already persistent?
2881 if ( m_bTransient )
2883 SAL_WARN( "ucb.ucp.webdav", "Content::exchangeIdentity - Not persistent!" );
2884 return false;
2887 // Exchange own identity.
2889 // Fail, if a content with given id already exists.
2890 // if ( !hasData( xNewId ) )
2892 OUString aOldURL = m_xIdentifier->getContentIdentifier();
2894 aGuard.clear();
2895 if ( exchange( xNewId ) )
2897 // Process instantiated children...
2899 ContentRefList aChildren;
2900 queryChildren( aChildren );
2902 for ( const auto& rChild : aChildren )
2904 ContentRef xChild = rChild;
2906 // Create new content identifier for the child...
2907 uno::Reference< ucb::XContentIdentifier >
2908 xOldChildId = xChild->getIdentifier();
2909 OUString aOldChildURL
2910 = xOldChildId->getContentIdentifier();
2911 OUString aNewChildURL
2912 = aOldChildURL.replaceAt(
2914 aOldURL.getLength(),
2915 xNewId->getContentIdentifier() );
2916 uno::Reference< ucb::XContentIdentifier > xNewChildId
2917 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
2919 if ( !xChild->exchangeIdentity( xNewChildId ) )
2920 return false;
2922 return true;
2926 SAL_WARN( "ucb.ucp.webdav",
2927 "Content::exchangeIdentity - "
2928 "Panic! Cannot exchange identity!" );
2929 return false;
2933 bool Content::isFolder(
2934 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
2937 osl::MutexGuard aGuard( m_aMutex );
2939 if ( m_bTransient )
2940 return m_bCollection;
2943 uno::Sequence< beans::Property > aProperties( 1 );
2944 aProperties[ 0 ].Name = "IsFolder";
2945 aProperties[ 0 ].Handle = -1;
2946 uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) );
2947 if ( xRow.is() )
2951 return xRow->getBoolean( 1 );
2953 catch ( sdbc::SQLException const & )
2958 return false;
2962 uno::Any Content::MapDAVException( const DAVException & e, bool bWrite )
2964 // Map DAVException...
2965 uno::Any aException;
2967 OUString aURL;
2968 if ( m_bTransient )
2970 aURL = getParentURL();
2971 if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2972 aURL += "/";
2974 aURL += m_aEscapedTitle;
2976 else
2978 aURL = m_xIdentifier->getContentIdentifier();
2981 switch ( e.getStatus() )
2983 case SC_NOT_FOUND:
2985 uno::Sequence< uno::Any > aArgs( 1 );
2986 aArgs[ 0 ] <<= beans::PropertyValue(
2987 "Uri", -1,
2988 uno::makeAny(aURL),
2989 beans::PropertyState_DIRECT_VALUE);
2991 aException <<=
2992 ucb::InteractiveAugmentedIOException(
2993 "Not found!",
2994 static_cast< cppu::OWeakObject * >( this ),
2995 task::InteractionClassification_ERROR,
2996 ucb::IOErrorCode_NOT_EXISTING,
2997 aArgs );
2998 return aException;
3000 default:
3001 break;
3004 switch ( e.getError() )
3006 case DAVException::DAV_HTTP_ERROR:
3008 if ( bWrite )
3009 aException <<=
3010 ucb::InteractiveNetworkWriteException(
3011 e.getData(),
3012 static_cast< cppu::OWeakObject * >( this ),
3013 task::InteractionClassification_ERROR,
3014 e.getData() );
3015 else
3016 aException <<=
3017 ucb::InteractiveNetworkReadException(
3018 e.getData(),
3019 static_cast< cppu::OWeakObject * >( this ),
3020 task::InteractionClassification_ERROR,
3021 e.getData() );
3022 break;
3025 case DAVException::DAV_HTTP_LOOKUP:
3026 aException <<=
3027 ucb::InteractiveNetworkResolveNameException(
3028 OUString(),
3029 static_cast< cppu::OWeakObject * >( this ),
3030 task::InteractionClassification_ERROR,
3031 e.getData() );
3032 break;
3034 // @@@ No matching InteractiveNetwork*Exception
3035 // case DAVException::DAV_HTTP_AUTH:
3036 // break;
3038 // @@@ No matching InteractiveNetwork*Exception
3039 // case DAVException::DAV_HTTP_AUTHPROXY:
3040 // break;
3042 case DAVException::DAV_HTTP_CONNECT:
3043 aException <<=
3044 ucb::InteractiveNetworkConnectException(
3045 OUString(),
3046 static_cast< cppu::OWeakObject * >( this ),
3047 task::InteractionClassification_ERROR,
3048 e.getData() );
3049 break;
3051 // @@@ No matching InteractiveNetwork*Exception
3052 // case DAVException::DAV_HTTP_TIMEOUT:
3053 // break;
3055 // @@@ No matching InteractiveNetwork*Exception
3056 // case DAVException::DAV_HTTP_REDIRECT:
3057 // break;
3059 // @@@ No matching InteractiveNetwork*Exception
3060 // case DAVException::DAV_SESSION_CREATE:
3061 // break;
3063 case DAVException::DAV_INVALID_ARG:
3064 aException <<=
3065 lang::IllegalArgumentException(
3066 OUString(),
3067 static_cast< cppu::OWeakObject * >( this ),
3068 -1 );
3069 break;
3071 case DAVException::DAV_LOCKED:
3072 #if 1
3073 aException <<=
3074 ucb::InteractiveLockingLockedException(
3075 "Locked!",
3076 static_cast< cppu::OWeakObject * >( this ),
3077 task::InteractionClassification_ERROR,
3078 aURL,
3079 false ); // not SelfOwned
3080 #else
3082 uno::Sequence< uno::Any > aArgs( 1 );
3083 aArgs[ 0 ] <<= beans::PropertyValue(
3084 OUString("Uri"), -1,
3085 uno::makeAny(aURL),
3086 beans::PropertyState_DIRECT_VALUE);
3088 aException <<=
3089 ucb::InteractiveAugmentedIOException(
3090 OUString( "Locked!" ),
3091 static_cast< cppu::OWeakObject * >( this ),
3092 task::InteractionClassification_ERROR,
3093 ucb::IOErrorCode_LOCKING_VIOLATION,
3094 aArgs );
3096 #endif
3097 break;
3099 case DAVException::DAV_LOCKED_SELF:
3100 aException <<=
3101 ucb::InteractiveLockingLockedException(
3102 "Locked (self)!",
3103 static_cast< cppu::OWeakObject * >( this ),
3104 task::InteractionClassification_ERROR,
3105 aURL,
3106 true ); // SelfOwned
3107 break;
3109 case DAVException::DAV_NOT_LOCKED:
3110 aException <<=
3111 ucb::InteractiveLockingNotLockedException(
3112 "Not locked!",
3113 static_cast< cppu::OWeakObject * >( this ),
3114 task::InteractionClassification_ERROR,
3115 aURL );
3116 break;
3118 case DAVException::DAV_LOCK_EXPIRED:
3119 aException <<=
3120 ucb::InteractiveLockingLockExpiredException(
3121 "Lock expired!",
3122 static_cast< cppu::OWeakObject * >( this ),
3123 task::InteractionClassification_ERROR,
3124 aURL );
3125 break;
3127 default:
3128 aException <<=
3129 ucb::InteractiveNetworkGeneralException(
3130 OUString(),
3131 static_cast< cppu::OWeakObject * >( this ),
3132 task::InteractionClassification_ERROR );
3133 break;
3136 return aException;
3140 // static
3141 bool Content::shouldAccessNetworkAfterException( const DAVException & e )
3143 if ( ( e.getStatus() == SC_NOT_FOUND ) ||
3144 ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) ||
3145 ( e.getError() == DAVException::DAV_HTTP_CONNECT ) ||
3146 ( e.getError() == DAVException::DAV_HTTP_AUTH ) ||
3147 ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) )
3148 return false;
3150 return true;
3154 void Content::cancelCommandExecution(
3155 const DAVException & e,
3156 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
3157 bool bWrite /* = false */ )
3159 ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv );
3160 // Unreachable
3164 OUString
3165 Content::getBaseURI( const std::unique_ptr< DAVResourceAccess > & rResAccess )
3167 osl::Guard< osl::Mutex > aGuard( m_aMutex );
3169 // First, try to obtain value of response header "Content-Location".
3170 if ( m_xCachedProps.get() )
3172 OUString aLocation;
3173 m_xCachedProps->getValue( "Content-Location" ) >>= aLocation;
3174 if ( aLocation.getLength() )
3178 // Do not use m_xIdentifier->getContentIdentifier() because it
3179 // for example does not reflect redirects applied to requests
3180 // done using the original URI but m_xResAccess' URI does.
3181 return rtl::Uri::convertRelToAbs( rResAccess->getURL(),
3182 aLocation );
3184 catch ( rtl::MalformedUriException const & )
3190 return rResAccess->getURL();
3194 Content::ResourceType Content::getResourceType(
3195 const uno::Reference< ucb::XCommandEnvironment >& xEnv,
3196 const std::unique_ptr< DAVResourceAccess > & rResAccess,
3197 bool * networkAccessAllowed )
3200 osl::MutexGuard g(m_aMutex);
3201 if (m_eResourceType != UNKNOWN) {
3202 return m_eResourceType;
3206 ResourceType eResourceType = UNKNOWN;
3210 // Try to fetch some frequently used property value, e.g. those
3211 // used when loading documents... along with identifying whether
3212 // this is a DAV resource.
3213 std::vector< DAVResource > resources;
3214 std::vector< OUString > aPropNames;
3215 uno::Sequence< beans::Property > aProperties( 5 );
3216 aProperties[ 0 ].Name = "IsFolder";
3217 aProperties[ 1 ].Name = "IsDocument";
3218 aProperties[ 2 ].Name = "IsReadOnly";
3219 aProperties[ 3 ].Name = "MediaType";
3220 aProperties[ 4 ].Name = DAVProperties::SUPPORTEDLOCK;
3222 ContentProperties::UCBNamesToDAVNames(
3223 aProperties, aPropNames );
3225 rResAccess->PROPFIND(
3226 DAVZERO, aPropNames, resources, xEnv );
3228 // TODO - is this really only one?
3229 if ( resources.size() == 1 )
3231 osl::MutexGuard g(m_aMutex);
3232 m_xCachedProps.reset(
3233 new CachableContentProperties( ContentProperties( resources[ 0 ] ) ) );
3234 m_xCachedProps->containsAllNames(
3235 aProperties, m_aFailedPropNames );
3238 eResourceType = DAV;
3240 catch ( DAVException const & e )
3242 rResAccess->resetUri();
3244 if ( e.getStatus() == SC_METHOD_NOT_ALLOWED )
3246 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3247 // resource is NON_DAV
3248 eResourceType = NON_DAV;
3250 else if (networkAccessAllowed != nullptr)
3252 *networkAccessAllowed = *networkAccessAllowed
3253 && shouldAccessNetworkAfterException(e);
3256 // cancel command execution is case that no user authentication data has been provided.
3257 if ( e.getError() == DAVException::DAV_HTTP_NOAUTH )
3259 cancelCommandExecution( e, uno::Reference< ucb::XCommandEnvironment >() );
3263 osl::MutexGuard g(m_aMutex);
3264 if (m_eResourceType == UNKNOWN) {
3265 m_eResourceType = eResourceType;
3266 } else {
3267 SAL_WARN_IF(
3268 eResourceType != m_eResourceType, "ucb.ucp.webdav",
3269 "different resource types for <" << rResAccess->getURL() << ">: "
3270 << +eResourceType << " vs. " << +m_eResourceType);
3272 return m_eResourceType;
3276 Content::ResourceType Content::getResourceType(
3277 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3279 std::unique_ptr< DAVResourceAccess > xResAccess;
3281 osl::MutexGuard aGuard( m_aMutex );
3282 xResAccess.reset( new DAVResourceAccess( *m_xResAccess ) );
3284 const Content::ResourceType & ret = getResourceType( xEnv, xResAccess );
3286 osl::Guard< osl::Mutex > aGuard( m_aMutex );
3287 m_xResAccess.reset( new DAVResourceAccess( *xResAccess ) );
3289 return ret;
3292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */