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 .
20 #include <osl/diagnose.h>
22 #include <com/sun/star/task/XInteractionAbort.hpp>
23 #include <com/sun/star/ucb/XWebDAVCommandEnvironment.hpp>
25 #include <ucbhelper/simpleauthenticationrequest.hxx>
26 #include <comphelper/seekableinput.hxx>
28 #include "DAVAuthListenerImpl.hxx"
29 #include "DAVResourceAccess.hxx"
31 using namespace http_dav_ucp
;
32 using namespace com::sun::star
;
37 // DAVAuthListener_Impl Implementation.
44 int DAVAuthListener_Impl::authenticate(
45 const OUString
& inRealm
,
46 const OUString
& inHostName
,
47 OUString
& inoutUserName
,
48 OUString
& outPassWord
,
49 bool bCanUseSystemCredentials
,
50 bool bUsePreviousCredentials
)
54 uno::Reference
< task::XInteractionHandler
> xIH
55 = m_xEnv
->getInteractionHandler();
59 // Providing previously retrieved credentials will cause the password
60 // container to reject these. Thus, the credential input dialog will be shown again.
61 // #102871# - Supply username and password from previous try.
62 // Password container service depends on this!
63 if ( inoutUserName
.isEmpty() && bUsePreviousCredentials
)
64 inoutUserName
= m_aPrevUsername
;
66 if ( outPassWord
.isEmpty() && bUsePreviousCredentials
)
67 outPassWord
= m_aPrevPassword
;
69 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
70 = new ucbhelper::SimpleAuthenticationRequest(
71 m_aURL
, inHostName
, inRealm
, inoutUserName
,
72 outPassWord
, OUString(),
73 true /*bAllowPersistentStoring*/,
74 bCanUseSystemCredentials
);
75 xIH
->handle( xRequest
.get() );
77 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
78 = xRequest
->getSelection();
80 if ( xSelection
.is() )
82 // Handler handled the request.
83 uno::Reference
< task::XInteractionAbort
> xAbort(
84 xSelection
.get(), uno::UNO_QUERY
);
88 ucbhelper::InteractionSupplyAuthentication
> & xSupp
89 = xRequest
->getAuthenticationSupplier();
91 bool bUseSystemCredentials
= false;
93 if ( bCanUseSystemCredentials
)
95 = xSupp
->getUseSystemCredentials();
97 if ( bUseSystemCredentials
)
99 // This is the (strange) way to tell neon to use
100 // system credentials.
101 inoutUserName
.clear();
106 inoutUserName
= xSupp
->getUserName();
107 outPassWord
= xSupp
->getPassword();
110 // #102871# - Remember username and password.
111 m_aPrevUsername
= inoutUserName
;
112 m_aPrevPassword
= outPassWord
;
127 // DAVResourceAccess Implementation.
133 DAVResourceAccess::DAVResourceAccess(
134 const uno::Reference
< uno::XComponentContext
> & rContext
,
135 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
,
136 const OUString
& rURL
)
138 m_xSessionFactory( rSessionFactory
),
139 m_xContext( rContext
)
144 DAVResourceAccess::DAVResourceAccess( const DAVResourceAccess
& rOther
)
145 : m_aURL( rOther
.m_aURL
),
146 m_aPath( rOther
.m_aPath
),
147 m_xSession( rOther
.m_xSession
),
148 m_xSessionFactory( rOther
.m_xSessionFactory
),
149 m_xContext( rOther
.m_xContext
),
150 m_aRedirectURIs( rOther
.m_aRedirectURIs
)
155 DAVResourceAccess
& DAVResourceAccess::operator=(
156 const DAVResourceAccess
& rOther
)
158 m_aURL
= rOther
.m_aURL
;
159 m_aPath
= rOther
.m_aPath
;
160 m_xSession
= rOther
.m_xSession
;
161 m_xSessionFactory
= rOther
.m_xSessionFactory
;
162 m_xContext
= rOther
.m_xContext
;
163 m_aRedirectURIs
= rOther
.m_aRedirectURIs
;
169 void DAVResourceAccess::PROPFIND(
171 const std::vector
< OUString
> & rPropertyNames
,
172 std::vector
< DAVResource
> & rResources
,
173 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
174 throw( DAVException
)
185 DAVRequestHeaders aHeaders
;
187 getUserRequestHeaders( xEnv
,
189 ucb::WebDAVHTTPMethod_PROPFIND
,
192 m_xSession
->PROPFIND( getRequestURI(),
196 DAVRequestEnvironment(
198 new DAVAuthListener_Impl( xEnv
, m_aURL
),
201 catch ( DAVException
& e
)
204 bRetry
= handleException( e
, errorCount
);
213 void DAVResourceAccess::PROPFIND(
215 std::vector
< DAVResourceInfo
> & rResInfo
,
216 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
217 throw( DAVException
)
228 DAVRequestHeaders aHeaders
;
229 getUserRequestHeaders( xEnv
,
231 ucb::WebDAVHTTPMethod_PROPFIND
,
234 m_xSession
->PROPFIND( getRequestURI(),
237 DAVRequestEnvironment(
239 new DAVAuthListener_Impl( xEnv
, m_aURL
),
242 catch ( DAVException
& e
)
245 bRetry
= handleException( e
, errorCount
);
254 void DAVResourceAccess::PROPPATCH(
255 const std::vector
< ProppatchValue
>& rValues
,
256 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
257 throw( DAVException
)
268 DAVRequestHeaders aHeaders
;
269 getUserRequestHeaders( xEnv
,
271 ucb::WebDAVHTTPMethod_PROPPATCH
,
274 m_xSession
->PROPPATCH( getRequestURI(),
276 DAVRequestEnvironment(
278 new DAVAuthListener_Impl( xEnv
, m_aURL
),
281 catch ( DAVException
& e
)
284 bRetry
= handleException( e
, errorCount
);
293 void DAVResourceAccess::HEAD(
294 const std::vector
< OUString
> & rHeaderNames
,
295 DAVResource
& rResource
,
296 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
297 throw( DAVException
)
308 DAVRequestHeaders aHeaders
;
309 getUserRequestHeaders( xEnv
,
311 ucb::WebDAVHTTPMethod_HEAD
,
314 m_xSession
->HEAD( getRequestURI(),
317 DAVRequestEnvironment(
319 new DAVAuthListener_Impl( xEnv
, m_aURL
),
322 catch ( DAVException
& e
)
325 bRetry
= handleException( e
, errorCount
);
334 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
335 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
336 throw( DAVException
)
340 uno::Reference
< io::XInputStream
> xStream
;
348 DAVRequestHeaders aHeaders
;
349 getUserRequestHeaders( xEnv
,
351 ucb::WebDAVHTTPMethod_GET
,
354 xStream
= m_xSession
->GET( getRequestURI(),
355 DAVRequestEnvironment(
357 new DAVAuthListener_Impl(
361 catch ( DAVException
& e
)
364 bRetry
= handleException( e
, errorCount
);
375 void DAVResourceAccess::GET(
376 uno::Reference
< io::XOutputStream
> & rStream
,
377 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
378 throw( DAVException
)
389 DAVRequestHeaders aHeaders
;
390 getUserRequestHeaders( xEnv
,
392 ucb::WebDAVHTTPMethod_GET
,
395 m_xSession
->GET( getRequestURI(),
397 DAVRequestEnvironment(
399 new DAVAuthListener_Impl( xEnv
, m_aURL
),
402 catch ( DAVException
& e
)
405 bRetry
= handleException( e
, errorCount
);
414 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
415 const std::vector
< OUString
> & rHeaderNames
,
416 DAVResource
& rResource
,
417 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
418 throw( DAVException
)
422 uno::Reference
< io::XInputStream
> xStream
;
430 DAVRequestHeaders aHeaders
;
431 getUserRequestHeaders( xEnv
,
433 ucb::WebDAVHTTPMethod_GET
,
436 xStream
= m_xSession
->GET( getRequestURI(),
439 DAVRequestEnvironment(
441 new DAVAuthListener_Impl(
445 catch ( DAVException
& e
)
448 bRetry
= handleException( e
, errorCount
);
459 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
460 DAVRequestHeaders
&rRequestHeaders
,
461 const std::vector
< OUString
> & rHeaderNames
,
462 DAVResource
& rResource
,
463 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
464 throw( DAVException
)
468 uno::Reference
< io::XInputStream
> xStream
;
476 getUserRequestHeaders( xEnv
,
478 ucb::WebDAVHTTPMethod_GET
,
481 xStream
= m_xSession
->GET( getRequestURI(),
484 DAVRequestEnvironment(
486 new DAVAuthListener_Impl(
488 rRequestHeaders
, xEnv
) );
490 catch ( DAVException
& e
)
493 bRetry
= handleException( e
, errorCount
);
504 void DAVResourceAccess::GET(
505 uno::Reference
< io::XOutputStream
> & rStream
,
506 const std::vector
< OUString
> & rHeaderNames
,
507 DAVResource
& rResource
,
508 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
509 throw( DAVException
)
520 DAVRequestHeaders aHeaders
;
521 getUserRequestHeaders( xEnv
,
523 ucb::WebDAVHTTPMethod_GET
,
526 m_xSession
->GET( getRequestURI(),
530 DAVRequestEnvironment(
532 new DAVAuthListener_Impl( xEnv
, m_aURL
),
535 catch ( DAVException
& e
)
538 bRetry
= handleException( e
, errorCount
);
547 void DAVResourceAccess::abort()
548 throw( DAVException
)
550 // 17.11.09 (tkr): abort currently disabled caused by issue i106766
552 // m_xSession->abort();
553 SAL_INFO("ucb.ucp.webdav", "Not implemented. -> #i106766#" );
559 void resetInputStream( const uno::Reference
< io::XInputStream
> & rStream
)
560 throw( DAVException
)
564 uno::Reference
< io::XSeekable
> xSeekable(
565 rStream
, uno::UNO_QUERY
);
566 if ( xSeekable
.is() )
568 xSeekable
->seek( 0 );
572 catch ( lang::IllegalArgumentException
const & )
575 catch ( io::IOException
const & )
579 throw DAVException( DAVException::DAV_INVALID_ARG
);
585 void DAVResourceAccess::PUT(
586 const uno::Reference
< io::XInputStream
> & rStream
,
587 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
588 throw( DAVException
)
592 // Make stream seekable, if it not. Needed, if request must be retried.
593 uno::Reference
< io::XInputStream
> xSeekableStream
594 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
595 rStream
, m_xContext
);
602 resetInputStream( xSeekableStream
);
607 DAVRequestHeaders aHeaders
;
608 getUserRequestHeaders( xEnv
,
610 ucb::WebDAVHTTPMethod_PUT
,
613 m_xSession
->PUT( getRequestURI(),
615 DAVRequestEnvironment(
617 new DAVAuthListener_Impl( xEnv
, m_aURL
),
620 catch ( DAVException
& e
)
623 bRetry
= handleException( e
, errorCount
);
632 uno::Reference
< io::XInputStream
> DAVResourceAccess::POST(
633 const OUString
& rContentType
,
634 const OUString
& rReferer
,
635 const uno::Reference
< io::XInputStream
> & rInputStream
,
636 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
637 throw ( DAVException
)
641 // Make stream seekable, if it not. Needed, if request must be retried.
642 uno::Reference
< io::XInputStream
> xSeekableStream
643 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
644 rInputStream
, m_xContext
);
646 uno::Reference
< io::XInputStream
> xStream
;
653 resetInputStream( xSeekableStream
);
659 DAVRequestHeaders aHeaders
;
660 getUserRequestHeaders( xEnv
,
662 ucb::WebDAVHTTPMethod_POST
,
665 xStream
= m_xSession
->POST( getRequestURI(),
669 DAVRequestEnvironment(
671 new DAVAuthListener_Impl(
675 catch ( DAVException
& e
)
678 bRetry
= handleException( e
, errorCount
);
682 if ( e
.getError() == DAVException::DAV_HTTP_REDIRECT
)
684 // #i74980# - Upon POST redirect, do a GET.
695 void DAVResourceAccess::POST(
696 const OUString
& rContentType
,
697 const OUString
& rReferer
,
698 const uno::Reference
< io::XInputStream
> & rInputStream
,
699 uno::Reference
< io::XOutputStream
> & rOutputStream
,
700 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
701 throw ( DAVException
)
705 // Make stream seekable, if it not. Needed, if request must be retried.
706 uno::Reference
< io::XInputStream
> xSeekableStream
707 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
708 rInputStream
, m_xContext
);
716 resetInputStream( xSeekableStream
);
722 DAVRequestHeaders aHeaders
;
723 getUserRequestHeaders( xEnv
,
725 ucb::WebDAVHTTPMethod_POST
,
728 m_xSession
->POST( getRequestURI(),
733 DAVRequestEnvironment(
735 new DAVAuthListener_Impl( xEnv
, m_aURL
),
738 catch ( DAVException
& e
)
741 bRetry
= handleException( e
, errorCount
);
745 if ( e
.getError() == DAVException::DAV_HTTP_REDIRECT
)
747 // #i74980# - Upon POST redirect, do a GET.
748 GET( rOutputStream
, xEnv
);
757 void DAVResourceAccess::MKCOL(
758 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
759 throw( DAVException
)
770 DAVRequestHeaders aHeaders
;
771 getUserRequestHeaders( xEnv
,
773 ucb::WebDAVHTTPMethod_MKCOL
,
776 m_xSession
->MKCOL( getRequestURI(),
777 DAVRequestEnvironment(
779 new DAVAuthListener_Impl( xEnv
, m_aURL
),
782 catch ( DAVException
& e
)
785 bRetry
= handleException( e
, errorCount
);
794 void DAVResourceAccess::COPY(
795 const OUString
& rSourcePath
,
796 const OUString
& rDestinationURI
,
798 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
799 throw( DAVException
)
810 DAVRequestHeaders aHeaders
;
811 getUserRequestHeaders( xEnv
,
813 ucb::WebDAVHTTPMethod_COPY
,
816 m_xSession
->COPY( rSourcePath
,
818 DAVRequestEnvironment(
820 new DAVAuthListener_Impl( xEnv
, m_aURL
),
824 catch ( DAVException
& e
)
827 bRetry
= handleException( e
, errorCount
);
836 void DAVResourceAccess::MOVE(
837 const OUString
& rSourcePath
,
838 const OUString
& rDestinationURI
,
840 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
841 throw( DAVException
)
852 DAVRequestHeaders aHeaders
;
853 getUserRequestHeaders( xEnv
,
855 ucb::WebDAVHTTPMethod_MOVE
,
858 m_xSession
->MOVE( rSourcePath
,
860 DAVRequestEnvironment(
862 new DAVAuthListener_Impl( xEnv
, m_aURL
),
866 catch ( DAVException
& e
)
869 bRetry
= handleException( e
, errorCount
);
878 void DAVResourceAccess::DESTROY(
879 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
880 throw( DAVException
)
891 DAVRequestHeaders aHeaders
;
892 getUserRequestHeaders( xEnv
,
894 ucb::WebDAVHTTPMethod_DELETE
,
897 m_xSession
->DESTROY( getRequestURI(),
898 DAVRequestEnvironment(
900 new DAVAuthListener_Impl( xEnv
, m_aURL
),
903 catch ( DAVException
& e
)
906 bRetry
= handleException( e
, errorCount
);
916 void DAVResourceAccess::LOCK(
918 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
919 throw ( DAVException
)
930 DAVRequestHeaders aHeaders
;
931 getUserRequestHeaders( xEnv
,
933 ucb::WebDAVHTTPMethod_LOCK
,
936 m_xSession
->LOCK( getRequestURI(),
938 DAVRequestEnvironment(
940 new DAVAuthListener_Impl( xEnv
, m_aURL
),
943 catch ( DAVException
& e
)
946 bRetry
= handleException( e
, errorCount
);
954 #if 0 // currently not used, but please don't remove code
956 // refresh existing lock.
957 sal_Int64
DAVResourceAccess::LOCK(
959 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
960 throw ( DAVException
)
964 sal_Int64 nNewTimeout
= 0;
972 DAVRequestHeaders aHeaders
;
973 getUserRequestHeaders( xEnv
,
975 ucb::WebDAVHTTPMethod_LOCK
,
978 nNewTimeout
= m_xSession
->LOCK( getRequestURI(),
980 DAVRequestEnvironment(
982 new DAVAuthListener_Impl(
986 catch ( DAVException
& e
)
989 bRetry
= handleException( e
, errorCount
);
1001 void DAVResourceAccess::UNLOCK(
1002 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1003 throw ( DAVException
)
1014 DAVRequestHeaders aHeaders
;
1015 getUserRequestHeaders( xEnv
,
1017 ucb::WebDAVHTTPMethod_UNLOCK
,
1020 m_xSession
->UNLOCK( getRequestURI(),
1021 DAVRequestEnvironment(
1023 new DAVAuthListener_Impl( xEnv
, m_aURL
),
1026 catch ( DAVException
& e
)
1029 bRetry
= handleException( e
, errorCount
);
1038 void DAVResourceAccess::setURL( const OUString
& rNewURL
)
1039 throw( DAVException
)
1041 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1043 m_aPath
.clear(); // Next initialize() will create new session.
1047 // init dav session and path
1048 void DAVResourceAccess::initialize()
1049 throw ( DAVException
)
1051 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1052 if ( m_aPath
.isEmpty() )
1054 SerfUri
aURI( m_aURL
);
1055 OUString
aPath( aURI
.GetPath() );
1057 /* #134089# - Check URI */
1058 if ( aPath
.isEmpty() )
1059 throw DAVException( DAVException::DAV_INVALID_ARG
);
1061 /* #134089# - Check URI */
1062 if ( aURI
.GetHost().isEmpty() )
1063 throw DAVException( DAVException::DAV_INVALID_ARG
);
1065 if ( !m_xSession
.is() || !m_xSession
->CanUse( m_aURL
) )
1069 // create new webdav session
1071 = m_xSessionFactory
->createDAVSession( m_aURL
, m_xContext
);
1073 if ( !m_xSession
.is() )
1077 // Own URI is needed for redirect cycle detection.
1078 m_aRedirectURIs
.push_back( aURI
);
1083 // Not only the path has to be encoded
1084 m_aURL
= aURI
.GetURI();
1089 const OUString
& DAVResourceAccess::getRequestURI() const
1091 SAL_WARN_IF( !m_xSession
.is(), "ucb.ucp.webdav",
1092 "DAVResourceAccess::getRequestURI - Not initialized!" );
1094 // In case a proxy is used we have to use the absolute URI for a request.
1095 if ( m_xSession
->UsesProxy() )
1103 void DAVResourceAccess::getUserRequestHeaders(
1104 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1105 const rtl::OUString
& rURI
,
1106 ucb::WebDAVHTTPMethod eMethod
,
1107 DAVRequestHeaders
& rRequestHeaders
)
1112 uno::Reference
< ucb::XWebDAVCommandEnvironment
> xDAVEnv(
1113 xEnv
, uno::UNO_QUERY
);
1115 if ( !xDAVEnv
.is() )
1118 uno::Sequence
< beans::StringPair
> aRequestHeaders
1119 = xDAVEnv
->getUserRequestHeaders( rURI
, eMethod
);
1121 for ( sal_Int32 n
= 0; n
< aRequestHeaders
.getLength(); ++n
)
1123 rRequestHeaders
.push_back(
1124 DAVRequestHeader( aRequestHeaders
[ n
].First
,
1125 aRequestHeaders
[ n
].Second
) );
1130 bool DAVResourceAccess::detectRedirectCycle(
1131 const OUString
& rRedirectURL
)
1132 throw ( DAVException
)
1134 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1136 SerfUri
aUri( rRedirectURL
);
1138 std::vector
< SerfUri
>::const_iterator it
= m_aRedirectURIs
.begin();
1139 std::vector
< SerfUri
>::const_iterator end
= m_aRedirectURIs
.end();
1143 if ( aUri
== (*it
) )
1153 void DAVResourceAccess::resetUri()
1155 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1156 if ( ! m_aRedirectURIs
.empty() )
1158 std::vector
< SerfUri
>::const_iterator it
= m_aRedirectURIs
.begin();
1160 SerfUri
aUri( (*it
) );
1161 m_aRedirectURIs
.clear();
1162 setURL ( aUri
.GetURI() );
1168 bool DAVResourceAccess::handleException( DAVException
& e
, int errorCount
)
1169 throw ( DAVException
)
1171 switch ( e
.getError() )
1173 case DAVException::DAV_HTTP_REDIRECT
:
1174 if ( !detectRedirectCycle( e
.getData() ) )
1176 // set new URL and path.
1177 setURL( e
.getData() );
1182 // --> tkr #67048# copy & paste images doesn't display.
1183 // if we have a bad connection try again. Up to three times.
1184 case DAVException::DAV_HTTP_ERROR
:
1185 // retry up to three times, if not a client-side error.
1186 if ( ( e
.getStatus() < 400 || e
.getStatus() >= 500 ||
1187 e
.getStatus() == 413 ) &&
1194 // --> tkr: if connection has said retry then retry!
1195 case DAVException::DAV_HTTP_RETRY
:
1199 return false; // Abort
1203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */