1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <com/sun/star/task/XInteractionAbort.hpp>
22 #include <com/sun/star/ucb/XWebDAVCommandEnvironment.hpp>
24 #include <ucbhelper/simpleauthenticationrequest.hxx>
25 #include <comphelper/seekableinput.hxx>
26 #include <sal/log.hxx>
28 #include "DAVAuthListenerImpl.hxx"
29 #include "DAVResourceAccess.hxx"
31 #include <com/sun/star/lang/IllegalArgumentException.hpp>
32 #include <com/sun/star/io/IOException.hpp>
34 using namespace http_dav_ucp
;
35 using namespace com::sun::star
;
38 // DAVAuthListener_Impl Implementation.
42 int DAVAuthListener_Impl::authenticate(
43 const OUString
& inRealm
,
44 const OUString
& inHostName
,
45 OUString
& inoutUserName
,
46 OUString
& outPassWord
,
47 bool bCanUseSystemCredentials
,
48 bool bUsePreviousCredentials
)
52 uno::Reference
< task::XInteractionHandler
> xIH
53 = m_xEnv
->getInteractionHandler();
57 // Providing previously retrieved credentials will cause the password
58 // container to reject these. Thus, the credential input dialog will be shown again.
59 // #102871# - Supply username and password from previous try.
60 // Password container service depends on this!
61 if ( inoutUserName
.isEmpty() && bUsePreviousCredentials
)
62 inoutUserName
= m_aPrevUsername
;
64 if ( outPassWord
.isEmpty() && bUsePreviousCredentials
)
65 outPassWord
= m_aPrevPassword
;
67 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
68 = new ucbhelper::SimpleAuthenticationRequest(
69 m_aURL
, inHostName
, inRealm
, inoutUserName
,
71 true /*bAllowPersistentStoring*/,
72 bCanUseSystemCredentials
);
73 xIH
->handle( xRequest
.get() );
75 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
76 = xRequest
->getSelection();
78 if ( xSelection
.is() )
80 // Handler handled the request.
81 uno::Reference
< task::XInteractionAbort
> xAbort(
82 xSelection
.get(), uno::UNO_QUERY
);
86 ucbhelper::InteractionSupplyAuthentication
> & xSupp
87 = xRequest
->getAuthenticationSupplier();
89 bool bUseSystemCredentials
= false;
91 if ( bCanUseSystemCredentials
)
93 = xSupp
->getUseSystemCredentials();
95 if ( bUseSystemCredentials
)
97 // This is the (strange) way to tell neon to use
98 // system credentials.
99 inoutUserName
.clear();
104 inoutUserName
= xSupp
->getUserName();
105 outPassWord
= xSupp
->getPassword();
108 // #102871# - Remember username and password.
109 m_aPrevUsername
= inoutUserName
;
110 m_aPrevPassword
= outPassWord
;
123 // DAVResourceAccess Implementation.
126 DAVResourceAccess::DAVResourceAccess(
127 const uno::Reference
< uno::XComponentContext
> & rContext
,
128 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
,
129 const OUString
& rURL
)
131 m_xSessionFactory( rSessionFactory
),
132 m_xContext( rContext
)
137 DAVResourceAccess::DAVResourceAccess( const DAVResourceAccess
& rOther
)
138 : m_aURL( rOther
.m_aURL
),
139 m_aPath( rOther
.m_aPath
),
140 m_xSession( rOther
.m_xSession
),
141 m_xSessionFactory( rOther
.m_xSessionFactory
),
142 m_xContext( rOther
.m_xContext
),
143 m_aRedirectURIs( rOther
.m_aRedirectURIs
)
148 DAVResourceAccess
& DAVResourceAccess::operator=(
149 const DAVResourceAccess
& rOther
)
151 m_aURL
= rOther
.m_aURL
;
152 m_aPath
= rOther
.m_aPath
;
153 m_xSession
= rOther
.m_xSession
;
154 m_xSessionFactory
= rOther
.m_xSessionFactory
;
155 m_xContext
= rOther
.m_xContext
;
156 m_aRedirectURIs
= rOther
.m_aRedirectURIs
;
162 void DAVResourceAccess::PROPFIND(
164 const std::vector
< OUString
> & rPropertyNames
,
165 std::vector
< DAVResource
> & rResources
,
166 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
177 DAVRequestHeaders aHeaders
;
179 getUserRequestHeaders( xEnv
,
181 ucb::WebDAVHTTPMethod_PROPFIND
,
184 m_xSession
->PROPFIND( getRequestURI(),
188 DAVRequestEnvironment(
190 new DAVAuthListener_Impl( xEnv
, m_aURL
),
193 catch ( DAVException
& e
)
196 bRetry
= handleException( e
, errorCount
);
205 void DAVResourceAccess::PROPFIND(
207 std::vector
< DAVResourceInfo
> & rResInfo
,
208 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
219 DAVRequestHeaders aHeaders
;
220 getUserRequestHeaders( xEnv
,
222 ucb::WebDAVHTTPMethod_PROPFIND
,
225 m_xSession
->PROPFIND( getRequestURI(),
228 DAVRequestEnvironment(
230 new DAVAuthListener_Impl( xEnv
, m_aURL
),
233 catch ( DAVException
& e
)
236 bRetry
= handleException( e
, errorCount
);
245 void DAVResourceAccess::PROPPATCH(
246 const std::vector
< ProppatchValue
>& rValues
,
247 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
258 DAVRequestHeaders aHeaders
;
259 getUserRequestHeaders( xEnv
,
261 ucb::WebDAVHTTPMethod_PROPPATCH
,
264 m_xSession
->PROPPATCH( getRequestURI(),
266 DAVRequestEnvironment(
268 new DAVAuthListener_Impl( xEnv
, m_aURL
),
271 catch ( DAVException
& e
)
274 bRetry
= handleException( e
, errorCount
);
283 void DAVResourceAccess::HEAD(
284 const std::vector
< OUString
> & rHeaderNames
,
285 DAVResource
& rResource
,
286 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
297 DAVRequestHeaders aHeaders
;
298 getUserRequestHeaders( xEnv
,
300 ucb::WebDAVHTTPMethod_HEAD
,
303 m_xSession
->HEAD( getRequestURI(),
306 DAVRequestEnvironment(
308 new DAVAuthListener_Impl( xEnv
, m_aURL
),
311 catch ( DAVException
& e
)
314 bRetry
= handleException( e
, errorCount
);
323 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
324 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
328 uno::Reference
< io::XInputStream
> xStream
;
336 DAVRequestHeaders aHeaders
;
337 getUserRequestHeaders( xEnv
,
339 ucb::WebDAVHTTPMethod_GET
,
342 xStream
= m_xSession
->GET( getRequestURI(),
343 DAVRequestEnvironment(
345 new DAVAuthListener_Impl(
349 catch ( DAVException
& e
)
352 bRetry
= handleException( e
, errorCount
);
363 void DAVResourceAccess::GET(
364 uno::Reference
< io::XOutputStream
> & rStream
,
365 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
376 DAVRequestHeaders aHeaders
;
377 getUserRequestHeaders( xEnv
,
379 ucb::WebDAVHTTPMethod_GET
,
382 m_xSession
->GET( getRequestURI(),
384 DAVRequestEnvironment(
386 new DAVAuthListener_Impl( xEnv
, m_aURL
),
389 catch ( DAVException
& e
)
392 bRetry
= handleException( e
, errorCount
);
401 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
402 const std::vector
< OUString
> & rHeaderNames
,
403 DAVResource
& rResource
,
404 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
408 uno::Reference
< io::XInputStream
> xStream
;
416 DAVRequestHeaders aHeaders
;
417 getUserRequestHeaders( xEnv
,
419 ucb::WebDAVHTTPMethod_GET
,
422 xStream
= m_xSession
->GET( getRequestURI(),
425 DAVRequestEnvironment(
427 new DAVAuthListener_Impl(
431 catch ( DAVException
& e
)
434 bRetry
= handleException( e
, errorCount
);
445 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
446 DAVRequestHeaders
&rRequestHeaders
,
447 const std::vector
< OUString
> & rHeaderNames
,
448 DAVResource
& rResource
,
449 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
453 uno::Reference
< io::XInputStream
> xStream
;
461 getUserRequestHeaders( xEnv
,
463 ucb::WebDAVHTTPMethod_GET
,
466 xStream
= m_xSession
->GET( getRequestURI(),
469 DAVRequestEnvironment(
471 new DAVAuthListener_Impl(
473 rRequestHeaders
, xEnv
) );
475 catch ( DAVException
& e
)
478 bRetry
= handleException( e
, errorCount
);
489 void DAVResourceAccess::GET(
490 uno::Reference
< io::XOutputStream
> & rStream
,
491 const std::vector
< OUString
> & rHeaderNames
,
492 DAVResource
& rResource
,
493 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
504 DAVRequestHeaders aHeaders
;
505 getUserRequestHeaders( xEnv
,
507 ucb::WebDAVHTTPMethod_GET
,
510 m_xSession
->GET( getRequestURI(),
514 DAVRequestEnvironment(
516 new DAVAuthListener_Impl( xEnv
, m_aURL
),
519 catch ( DAVException
& e
)
522 bRetry
= handleException( e
, errorCount
);
531 void DAVResourceAccess::abort()
533 // 17.11.09 (tkr): abort currently disabled caused by issue i106766
535 // m_xSession->abort();
536 SAL_INFO("ucb.ucp.webdav", "Not implemented. -> #i106766#" );
542 /// @throws DAVException
543 void resetInputStream( const uno::Reference
< io::XInputStream
> & rStream
)
547 uno::Reference
< io::XSeekable
> xSeekable(
548 rStream
, uno::UNO_QUERY
);
549 if ( xSeekable
.is() )
551 xSeekable
->seek( 0 );
555 catch ( lang::IllegalArgumentException
const & )
558 catch ( io::IOException
const & )
562 throw DAVException( DAVException::DAV_INVALID_ARG
);
568 void DAVResourceAccess::PUT(
569 const uno::Reference
< io::XInputStream
> & rStream
,
570 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
574 // Make stream seekable, if it not. Needed, if request must be retried.
575 uno::Reference
< io::XInputStream
> xSeekableStream
576 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
577 rStream
, m_xContext
);
584 resetInputStream( xSeekableStream
);
589 DAVRequestHeaders aHeaders
;
590 getUserRequestHeaders( xEnv
,
592 ucb::WebDAVHTTPMethod_PUT
,
595 m_xSession
->PUT( getRequestURI(),
597 DAVRequestEnvironment(
599 new DAVAuthListener_Impl( xEnv
, m_aURL
),
602 catch ( DAVException
& e
)
605 bRetry
= handleException( e
, errorCount
);
614 uno::Reference
< io::XInputStream
> DAVResourceAccess::POST(
615 const OUString
& rContentType
,
616 const OUString
& rReferer
,
617 const uno::Reference
< io::XInputStream
> & rInputStream
,
618 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
622 // Make stream seekable, if it not. Needed, if request must be retried.
623 uno::Reference
< io::XInputStream
> xSeekableStream
624 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
625 rInputStream
, m_xContext
);
627 uno::Reference
< io::XInputStream
> xStream
;
634 resetInputStream( xSeekableStream
);
640 DAVRequestHeaders aHeaders
;
641 getUserRequestHeaders( xEnv
,
643 ucb::WebDAVHTTPMethod_POST
,
646 xStream
= m_xSession
->POST( getRequestURI(),
650 DAVRequestEnvironment(
652 new DAVAuthListener_Impl(
656 catch ( DAVException
& e
)
659 bRetry
= handleException( e
, errorCount
);
663 if ( e
.getError() == DAVException::DAV_HTTP_REDIRECT
)
665 // #i74980# - Upon POST redirect, do a GET.
676 void DAVResourceAccess::POST(
677 const OUString
& rContentType
,
678 const OUString
& rReferer
,
679 const uno::Reference
< io::XInputStream
> & rInputStream
,
680 uno::Reference
< io::XOutputStream
> & rOutputStream
,
681 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
685 // Make stream seekable, if it not. Needed, if request must be retried.
686 uno::Reference
< io::XInputStream
> xSeekableStream
687 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
688 rInputStream
, m_xContext
);
696 resetInputStream( xSeekableStream
);
702 DAVRequestHeaders aHeaders
;
703 getUserRequestHeaders( xEnv
,
705 ucb::WebDAVHTTPMethod_POST
,
708 m_xSession
->POST( getRequestURI(),
713 DAVRequestEnvironment(
715 new DAVAuthListener_Impl( xEnv
, m_aURL
),
718 catch ( DAVException
& e
)
721 bRetry
= handleException( e
, errorCount
);
725 if ( e
.getError() == DAVException::DAV_HTTP_REDIRECT
)
727 // #i74980# - Upon POST redirect, do a GET.
728 GET( rOutputStream
, xEnv
);
737 void DAVResourceAccess::MKCOL(
738 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
749 DAVRequestHeaders aHeaders
;
750 getUserRequestHeaders( xEnv
,
752 ucb::WebDAVHTTPMethod_MKCOL
,
755 m_xSession
->MKCOL( getRequestURI(),
756 DAVRequestEnvironment(
758 new DAVAuthListener_Impl( xEnv
, m_aURL
),
761 catch ( DAVException
& e
)
764 bRetry
= handleException( e
, errorCount
);
773 void DAVResourceAccess::COPY(
774 const OUString
& rSourcePath
,
775 const OUString
& rDestinationURI
,
777 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
788 DAVRequestHeaders aHeaders
;
789 getUserRequestHeaders( xEnv
,
791 ucb::WebDAVHTTPMethod_COPY
,
794 m_xSession
->COPY( rSourcePath
,
796 DAVRequestEnvironment(
798 new DAVAuthListener_Impl( xEnv
, m_aURL
),
802 catch ( DAVException
& e
)
805 bRetry
= handleException( e
, errorCount
);
814 void DAVResourceAccess::MOVE(
815 const OUString
& rSourcePath
,
816 const OUString
& rDestinationURI
,
818 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
829 DAVRequestHeaders aHeaders
;
830 getUserRequestHeaders( xEnv
,
832 ucb::WebDAVHTTPMethod_MOVE
,
835 m_xSession
->MOVE( rSourcePath
,
837 DAVRequestEnvironment(
839 new DAVAuthListener_Impl( xEnv
, m_aURL
),
843 catch ( DAVException
& e
)
846 bRetry
= handleException( e
, errorCount
);
855 void DAVResourceAccess::DESTROY(
856 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
867 DAVRequestHeaders aHeaders
;
868 getUserRequestHeaders( xEnv
,
870 ucb::WebDAVHTTPMethod_DELETE
,
873 m_xSession
->DESTROY( getRequestURI(),
874 DAVRequestEnvironment(
876 new DAVAuthListener_Impl( xEnv
, m_aURL
),
879 catch ( DAVException
& e
)
882 bRetry
= handleException( e
, errorCount
);
892 void DAVResourceAccess::LOCK(
894 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
905 DAVRequestHeaders aHeaders
;
906 getUserRequestHeaders( xEnv
,
908 ucb::WebDAVHTTPMethod_LOCK
,
911 m_xSession
->LOCK( getRequestURI(),
913 DAVRequestEnvironment(
915 new DAVAuthListener_Impl( xEnv
, m_aURL
),
918 catch ( DAVException
& e
)
921 bRetry
= handleException( e
, errorCount
);
929 void DAVResourceAccess::UNLOCK(
930 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
941 DAVRequestHeaders aHeaders
;
942 getUserRequestHeaders( xEnv
,
944 ucb::WebDAVHTTPMethod_UNLOCK
,
947 m_xSession
->UNLOCK( getRequestURI(),
948 DAVRequestEnvironment(
950 new DAVAuthListener_Impl( xEnv
, m_aURL
),
953 catch ( DAVException
& e
)
956 bRetry
= handleException( e
, errorCount
);
965 void DAVResourceAccess::setURL( const OUString
& rNewURL
)
967 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
969 m_aPath
.clear(); // Next initialize() will create new session.
973 // init dav session and path
974 void DAVResourceAccess::initialize()
976 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
977 if ( m_aPath
.isEmpty() )
979 SerfUri
aURI( m_aURL
);
980 OUString
aPath( aURI
.GetPath() );
982 /* #134089# - Check URI */
983 if ( aPath
.isEmpty() )
984 throw DAVException( DAVException::DAV_INVALID_ARG
);
986 /* #134089# - Check URI */
987 if ( aURI
.GetHost().isEmpty() )
988 throw DAVException( DAVException::DAV_INVALID_ARG
);
990 if ( !m_xSession
.is() || !m_xSession
->CanUse( m_aURL
) )
994 // create new webdav session
996 = m_xSessionFactory
->createDAVSession( m_aURL
, m_xContext
);
998 if ( !m_xSession
.is() )
1002 // Own URI is needed for redirect cycle detection.
1003 m_aRedirectURIs
.push_back( aURI
);
1008 // Not only the path has to be encoded
1009 m_aURL
= aURI
.GetURI();
1014 const OUString
& DAVResourceAccess::getRequestURI() const
1016 SAL_WARN_IF( !m_xSession
.is(), "ucb.ucp.webdav",
1017 "DAVResourceAccess::getRequestURI - Not initialized!" );
1019 // In case a proxy is used we have to use the absolute URI for a request.
1020 if ( m_xSession
->UsesProxy() )
1028 void DAVResourceAccess::getUserRequestHeaders(
1029 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1030 const OUString
& rURI
,
1031 ucb::WebDAVHTTPMethod eMethod
,
1032 DAVRequestHeaders
& rRequestHeaders
)
1037 uno::Reference
< ucb::XWebDAVCommandEnvironment
> xDAVEnv(
1038 xEnv
, uno::UNO_QUERY
);
1040 if ( !xDAVEnv
.is() )
1043 uno::Sequence
< beans::StringPair
> aRequestHeaders
1044 = xDAVEnv
->getUserRequestHeaders( rURI
, eMethod
);
1046 for ( sal_Int32 n
= 0; n
< aRequestHeaders
.getLength(); ++n
)
1048 rRequestHeaders
.push_back(
1049 DAVRequestHeader( aRequestHeaders
[ n
].First
,
1050 aRequestHeaders
[ n
].Second
) );
1055 bool DAVResourceAccess::detectRedirectCycle(
1056 const OUString
& rRedirectURL
)
1058 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1060 SerfUri
aUri( rRedirectURL
);
1062 return std::any_of(m_aRedirectURIs
.begin(), m_aRedirectURIs
.end(),
1063 [&aUri
](const SerfUri
& rUri
) { return aUri
== rUri
; });
1067 void DAVResourceAccess::resetUri()
1069 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1070 if ( ! m_aRedirectURIs
.empty() )
1072 std::vector
< SerfUri
>::const_iterator it
= m_aRedirectURIs
.begin();
1074 SerfUri
aUri( *it
);
1075 m_aRedirectURIs
.clear();
1076 setURL ( aUri
.GetURI() );
1082 bool DAVResourceAccess::handleException( DAVException
& e
, int errorCount
)
1084 switch ( e
.getError() )
1086 case DAVException::DAV_HTTP_REDIRECT
:
1087 if ( !detectRedirectCycle( e
.getData() ) )
1089 // set new URL and path.
1090 setURL( e
.getData() );
1095 // --> tkr #67048# copy & paste images doesn't display.
1096 // if we have a bad connection try again. Up to three times.
1097 case DAVException::DAV_HTTP_ERROR
:
1098 // retry up to three times, if not a client-side error.
1099 if ( ( e
.getStatus() < 400 || e
.getStatus() >= 500 ||
1100 e
.getStatus() == 413 ) &&
1107 // --> tkr: if connection has said retry then retry!
1108 case DAVException::DAV_HTTP_RETRY
:
1112 return false; // Abort
1116 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */