Bump version to 24.04.3.4
[LibreOffice.git] / ucb / source / ucp / webdav-curl / DAVResourceAccess.cxx
blobc1b775c08f7068d9279a526dc5edc9c066bf5e85
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 .
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>
27 #include "DAVAuthListenerImpl.hxx"
28 #include "DAVResourceAccess.hxx"
29 #include "webdavprovider.hxx"
31 #include <officecfg/Office/Security.hxx>
33 #include <com/sun/star/lang/IllegalArgumentException.hpp>
34 #include <com/sun/star/io/IOException.hpp>
35 #include <utility>
37 using namespace http_dav_ucp;
38 using namespace com::sun::star;
41 // DAVAuthListener_Impl Implementation.
44 // virtual
45 int DAVAuthListener_Impl::authenticate(
46 const OUString & inRealm,
47 const OUString & inHostName,
48 OUString & inoutUserName,
49 OUString & outPassWord,
50 bool bCanUseSystemCredentials,
51 bool bUsePreviousCredentials )
53 if ( m_xEnv.is() )
55 uno::Reference< task::XInteractionHandler > xIH
56 = m_xEnv->getInteractionHandler();
58 if ( xIH.is() )
60 // Providing previously retrieved credentials will cause the password
61 // container to reject these. Thus, the credential input dialog will be shown again.
62 // #102871# - Supply username and password from previous try.
63 // Password container service depends on this!
64 if ( inoutUserName.isEmpty() && bUsePreviousCredentials )
65 inoutUserName = m_aPrevUsername;
67 if ( outPassWord.isEmpty() && bUsePreviousCredentials )
68 outPassWord = m_aPrevPassword;
70 rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
71 = new ucbhelper::SimpleAuthenticationRequest(
72 m_aURL, inHostName, inRealm, inoutUserName,
73 outPassWord,
74 bCanUseSystemCredentials );
75 xIH->handle( xRequest );
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 );
85 if ( !xAbort.is() )
87 const rtl::Reference<
88 ucbhelper::InteractionSupplyAuthentication > & xSupp
89 = xRequest->getAuthenticationSupplier();
91 bool bUseSystemCredentials = false;
93 if ( bCanUseSystemCredentials )
94 bUseSystemCredentials
95 = xSupp->getUseSystemCredentials();
97 if ( bUseSystemCredentials )
99 // This is the (strange) way to tell neon to use
100 // system credentials.
101 inoutUserName.clear();
102 outPassWord.clear();
104 else
106 inoutUserName = xSupp->getUserName();
107 outPassWord = xSupp->getPassword();
110 // #102871# - Remember username and password.
111 m_aPrevUsername = inoutUserName;
112 m_aPrevPassword = outPassWord;
114 // go on.
115 return 0;
120 // Abort.
121 return -1;
125 // DAVResourceAccess Implementation.
127 constexpr size_t g_nRedirectLimit = 5;
129 DAVResourceAccess::DAVResourceAccess(
130 uno::Reference< uno::XComponentContext > xContext,
131 rtl::Reference< DAVSessionFactory > xSessionFactory,
132 OUString aURL )
133 : m_aURL(std::move( aURL )),
134 m_xSessionFactory(std::move( xSessionFactory )),
135 m_xContext(std::move( xContext ))
140 DAVResourceAccess::DAVResourceAccess( const DAVResourceAccess & rOther )
141 : m_aURL( rOther.m_aURL ),
142 m_aPath( rOther.m_aPath ),
143 m_aFlags( rOther.m_aFlags ),
144 m_xSession( rOther.m_xSession ),
145 m_xSessionFactory( rOther.m_xSessionFactory ),
146 m_xContext( rOther.m_xContext ),
147 m_aRedirectURIs( rOther.m_aRedirectURIs )
152 DAVResourceAccess & DAVResourceAccess::operator=(
153 const DAVResourceAccess & rOther )
155 m_aURL = rOther.m_aURL;
156 m_aPath = rOther.m_aPath;
157 m_aFlags = rOther.m_aFlags;
158 m_xSession = rOther.m_xSession;
159 m_xSessionFactory = rOther.m_xSessionFactory;
160 m_xContext = rOther.m_xContext;
161 m_aRedirectURIs = rOther.m_aRedirectURIs;
163 return *this;
166 void DAVResourceAccess::OPTIONS(
167 DAVOptions & rOptions,
168 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
170 initialize();
172 int errorCount = 0;
173 bool bRetry;
176 bRetry = false;
179 DAVRequestHeaders aHeaders;
181 getUserRequestHeaders( xEnv,
182 getRequestURI(),
183 ucb::WebDAVHTTPMethod_OPTIONS,
184 aHeaders );
186 m_xSession->OPTIONS( getRequestURI(),
187 rOptions,
188 DAVRequestEnvironment(
189 new DAVAuthListener_Impl( xEnv, m_aURL ),
190 aHeaders ) );
192 catch (DAVException const& e)
194 errorCount++;
195 bRetry = handleException( e, errorCount );
196 if ( !bRetry )
197 throw;
200 while ( bRetry );
203 void DAVResourceAccess::PROPFIND(
204 const Depth nDepth,
205 const std::vector< OUString > & rPropertyNames,
206 std::vector< DAVResource > & rResources,
207 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
209 initialize();
211 int errorCount = 0;
212 bool bRetry;
215 bRetry = false;
218 DAVRequestHeaders aHeaders;
220 getUserRequestHeaders( xEnv,
221 getRequestURI(),
222 ucb::WebDAVHTTPMethod_PROPFIND,
223 aHeaders );
225 m_xSession->PROPFIND( getRequestURI(),
226 nDepth,
227 rPropertyNames,
228 rResources,
229 DAVRequestEnvironment(
230 new DAVAuthListener_Impl( xEnv, m_aURL ),
231 aHeaders ) );
233 catch (DAVException const& e)
235 errorCount++;
236 bRetry = handleException( e, errorCount );
237 if ( !bRetry )
238 throw;
241 while ( bRetry );
245 void DAVResourceAccess::PROPFIND(
246 const Depth nDepth,
247 std::vector< DAVResourceInfo > & rResInfo,
248 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
250 initialize();
252 int errorCount = 0;
253 bool bRetry;
256 bRetry = false;
259 DAVRequestHeaders aHeaders;
260 getUserRequestHeaders( xEnv,
261 getRequestURI(),
262 ucb::WebDAVHTTPMethod_PROPFIND,
263 aHeaders );
265 m_xSession->PROPFIND( getRequestURI(),
266 nDepth,
267 rResInfo,
268 DAVRequestEnvironment(
269 new DAVAuthListener_Impl( xEnv, m_aURL ),
270 aHeaders ) ) ;
272 catch (DAVException const& e)
274 errorCount++;
275 bRetry = handleException( e, errorCount );
276 if ( !bRetry )
277 throw;
280 while ( bRetry );
284 void DAVResourceAccess::PROPPATCH(
285 const std::vector< ProppatchValue >& rValues,
286 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
288 initialize();
290 int errorCount = 0;
291 bool bRetry;
294 bRetry = false;
297 DAVRequestHeaders aHeaders;
298 getUserRequestHeaders( xEnv,
299 getRequestURI(),
300 ucb::WebDAVHTTPMethod_PROPPATCH,
301 aHeaders );
303 m_xSession->PROPPATCH( getRequestURI(),
304 rValues,
305 DAVRequestEnvironment(
306 new DAVAuthListener_Impl( xEnv, m_aURL ),
307 aHeaders ) );
309 catch (DAVException const& e)
311 errorCount++;
312 bRetry = handleException( e, errorCount );
313 if ( !bRetry )
314 throw;
317 while ( bRetry );
321 void DAVResourceAccess::HEAD(
322 const std::vector< OUString > & rHeaderNames,
323 DAVResource & rResource,
324 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
326 initialize();
328 int errorCount = 0;
329 bool bRetry;
332 bRetry = false;
335 DAVRequestHeaders aHeaders;
336 getUserRequestHeaders( xEnv,
337 getRequestURI(),
338 ucb::WebDAVHTTPMethod_HEAD,
339 aHeaders );
341 m_xSession->HEAD( getRequestURI(),
342 rHeaderNames,
343 rResource,
344 DAVRequestEnvironment(
345 new DAVAuthListener_Impl( xEnv, m_aURL ),
346 aHeaders ) );
348 catch (DAVException const& e)
350 errorCount++;
351 bRetry = handleException( e, errorCount );
352 if ( !bRetry )
353 throw;
356 while ( bRetry );
360 uno::Reference< io::XInputStream > DAVResourceAccess::GET(
361 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
363 initialize();
365 uno::Reference< io::XInputStream > xStream;
366 int errorCount = 0;
367 bool bRetry;
370 bRetry = false;
373 DAVRequestHeaders aHeaders;
374 getUserRequestHeaders( xEnv,
375 getRequestURI(),
376 ucb::WebDAVHTTPMethod_GET,
377 aHeaders );
379 xStream = m_xSession->GET( getRequestURI(),
380 DAVRequestEnvironment(
381 new DAVAuthListener_Impl(
382 xEnv, m_aURL ),
383 aHeaders ) );
385 catch (DAVException const& e)
387 errorCount++;
388 bRetry = handleException( e, errorCount );
389 if ( !bRetry )
390 throw;
393 while ( bRetry );
395 return xStream;
399 void DAVResourceAccess::GET(
400 uno::Reference< io::XOutputStream > & rStream,
401 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
403 initialize();
405 int errorCount = 0;
406 bool bRetry;
409 bRetry = false;
412 DAVRequestHeaders aHeaders;
413 getUserRequestHeaders( xEnv,
414 getRequestURI(),
415 ucb::WebDAVHTTPMethod_GET,
416 aHeaders );
418 m_xSession->GET( getRequestURI(),
419 rStream,
420 DAVRequestEnvironment(
421 new DAVAuthListener_Impl( xEnv, m_aURL ),
422 aHeaders ) );
424 catch (DAVException const& e)
426 errorCount++;
427 bRetry = handleException( e, errorCount );
428 if ( !bRetry )
429 throw;
432 while ( bRetry );
436 uno::Reference< io::XInputStream > DAVResourceAccess::GET(
437 const std::vector< OUString > & rHeaderNames,
438 DAVResource & rResource,
439 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
441 initialize();
443 uno::Reference< io::XInputStream > xStream;
444 int errorCount = 0;
445 bool bRetry;
448 bRetry = false;
451 DAVRequestHeaders aHeaders;
452 getUserRequestHeaders( xEnv,
453 getRequestURI(),
454 ucb::WebDAVHTTPMethod_GET,
455 aHeaders );
457 xStream = m_xSession->GET( getRequestURI(),
458 rHeaderNames,
459 rResource,
460 DAVRequestEnvironment(
461 new DAVAuthListener_Impl(
462 xEnv, m_aURL ),
463 aHeaders ) );
465 catch (DAVException const& e)
467 errorCount++;
468 bRetry = handleException( e, errorCount );
469 if ( !bRetry )
470 throw;
473 while ( bRetry );
475 return xStream;
479 // used as HEAD substitute when HEAD is not implemented on server
480 void DAVResourceAccess::GET0(
481 DAVRequestHeaders &rRequestHeaders,
482 const std::vector< OUString > & rHeaderNames,
483 DAVResource & rResource,
484 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
486 initialize();
488 int errorCount = 0;
489 bool bRetry;
492 bRetry = false;
495 getUserRequestHeaders( xEnv,
496 getRequestURI(),
497 ucb::WebDAVHTTPMethod_GET,
498 rRequestHeaders );
500 m_xSession->GET( getRequestURI(),
501 rHeaderNames,
502 rResource,
503 DAVRequestEnvironment(
504 new DAVAuthListener_Impl(
505 xEnv, m_aURL ),
506 rRequestHeaders ) );
508 catch (DAVException const& e)
510 errorCount++;
511 bRetry = handleException( e, errorCount );
512 if ( !bRetry )
513 throw;
516 while ( bRetry );
520 void DAVResourceAccess::GET(
521 uno::Reference< io::XOutputStream > & rStream,
522 const std::vector< OUString > & rHeaderNames,
523 DAVResource & rResource,
524 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
526 initialize();
528 bool bRetry;
529 int errorCount = 0;
532 bRetry = false;
535 DAVRequestHeaders aHeaders;
536 getUserRequestHeaders( xEnv,
537 getRequestURI(),
538 ucb::WebDAVHTTPMethod_GET,
539 aHeaders );
541 m_xSession->GET( getRequestURI(),
542 rStream,
543 rHeaderNames,
544 rResource,
545 DAVRequestEnvironment(
546 new DAVAuthListener_Impl( xEnv, m_aURL ),
547 aHeaders ) );
549 catch (DAVException const& e)
551 errorCount++;
552 bRetry = handleException( e, errorCount );
553 if ( !bRetry )
554 throw;
557 while ( bRetry );
561 void DAVResourceAccess::abort()
563 // seems pointless to call initialize() here, but prepare for nullptr
564 decltype(m_xSession) xSession;
566 osl::Guard<osl::Mutex> const g(m_aMutex);
567 xSession = m_xSession;
569 if (xSession.is())
571 xSession->abort();
576 namespace {
578 /// @throws DAVException
579 void resetInputStream( const uno::Reference< io::XInputStream > & rStream )
583 uno::Reference< io::XSeekable > xSeekable(
584 rStream, uno::UNO_QUERY );
585 if ( xSeekable.is() )
587 xSeekable->seek( 0 );
588 return;
591 catch ( lang::IllegalArgumentException const & )
594 catch ( io::IOException const & )
598 throw DAVException( DAVException::DAV_INVALID_ARG );
601 } // namespace
604 void DAVResourceAccess::PUT(
605 const uno::Reference< io::XInputStream > & rStream,
606 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
608 initialize();
610 // Make stream seekable, if it not. Needed, if request must be retried.
611 uno::Reference< io::XInputStream > xSeekableStream
612 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
613 rStream, m_xContext );
615 int errorCount = 0;
616 bool bRetry = false;
619 if ( bRetry )
620 resetInputStream( xSeekableStream );
622 bRetry = false;
625 DAVRequestHeaders aHeaders;
626 getUserRequestHeaders( xEnv,
627 getRequestURI(),
628 ucb::WebDAVHTTPMethod_PUT,
629 aHeaders );
631 m_xSession->PUT( getRequestURI(),
632 xSeekableStream,
633 DAVRequestEnvironment(
634 new DAVAuthListener_Impl( xEnv, m_aURL ),
635 aHeaders ) );
637 catch (DAVException const& e)
639 errorCount++;
640 bRetry = handleException( e, errorCount );
641 if ( !bRetry )
642 throw;
645 while ( bRetry );
649 uno::Reference< io::XInputStream > DAVResourceAccess::POST(
650 const OUString & rContentType,
651 const OUString & rReferer,
652 const uno::Reference< io::XInputStream > & rInputStream,
653 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
655 initialize();
657 // Make stream seekable, if it not. Needed, if request must be retried.
658 uno::Reference< io::XInputStream > xSeekableStream
659 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
660 rInputStream, m_xContext );
662 uno::Reference< io::XInputStream > xStream;
663 int errorCount = 0;
664 bool bRetry = false;
667 if ( bRetry )
669 resetInputStream( xSeekableStream );
670 bRetry = false;
675 DAVRequestHeaders aHeaders;
676 getUserRequestHeaders( xEnv,
677 getRequestURI(),
678 ucb::WebDAVHTTPMethod_POST,
679 aHeaders );
681 xStream = m_xSession->POST( getRequestURI(),
682 rContentType,
683 rReferer,
684 xSeekableStream,
685 DAVRequestEnvironment(
686 new DAVAuthListener_Impl(
687 xEnv, m_aURL ),
688 aHeaders ) );
690 catch (DAVException const& e)
692 errorCount++;
693 bRetry = handleException( e, errorCount );
694 if ( !bRetry )
695 throw;
697 if ( e.getError() == DAVException::DAV_HTTP_REDIRECT )
699 // #i74980# - Upon POST redirect, do a GET.
700 return GET( xEnv );
704 while ( bRetry );
706 return xStream;
710 void DAVResourceAccess::POST(
711 const OUString & rContentType,
712 const OUString & rReferer,
713 const uno::Reference< io::XInputStream > & rInputStream,
714 uno::Reference< io::XOutputStream > & rOutputStream,
715 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
717 initialize();
719 // Make stream seekable, if it not. Needed, if request must be retried.
720 uno::Reference< io::XInputStream > xSeekableStream
721 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
722 rInputStream, m_xContext );
724 int errorCount = 0;
725 bool bRetry = false;
728 if ( bRetry )
730 resetInputStream( xSeekableStream );
731 bRetry = false;
736 DAVRequestHeaders aHeaders;
737 getUserRequestHeaders( xEnv,
738 getRequestURI(),
739 ucb::WebDAVHTTPMethod_POST,
740 aHeaders );
742 m_xSession->POST( getRequestURI(),
743 rContentType,
744 rReferer,
745 xSeekableStream,
746 rOutputStream,
747 DAVRequestEnvironment(
748 new DAVAuthListener_Impl( xEnv, m_aURL ),
749 aHeaders ) );
751 catch (DAVException const& e)
753 errorCount++;
754 bRetry = handleException( e, errorCount );
755 if ( !bRetry )
756 throw;
758 if ( e.getError() == DAVException::DAV_HTTP_REDIRECT )
760 // #i74980# - Upon POST redirect, do a GET.
761 GET( rOutputStream, xEnv );
762 return;
766 while ( bRetry );
770 void DAVResourceAccess::MKCOL(
771 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
773 initialize();
775 int errorCount = 0;
776 bool bRetry;
779 bRetry = false;
782 DAVRequestHeaders aHeaders;
783 getUserRequestHeaders( xEnv,
784 getRequestURI(),
785 ucb::WebDAVHTTPMethod_MKCOL,
786 aHeaders );
788 m_xSession->MKCOL( getRequestURI(),
789 DAVRequestEnvironment(
790 new DAVAuthListener_Impl( xEnv, m_aURL ),
791 aHeaders ) );
793 catch (DAVException const& e)
795 errorCount++;
796 bRetry = handleException( e, errorCount );
797 if ( !bRetry )
798 throw;
801 while ( bRetry );
805 void DAVResourceAccess::COPY(
806 const OUString & rSourcePath,
807 const OUString & rDestinationURI,
808 bool bOverwrite,
809 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
811 initialize();
813 int errorCount = 0;
814 bool bRetry;
817 bRetry = false;
820 DAVRequestHeaders aHeaders;
821 getUserRequestHeaders( xEnv,
822 getRequestURI(),
823 ucb::WebDAVHTTPMethod_COPY,
824 aHeaders );
826 m_xSession->COPY( rSourcePath,
827 rDestinationURI,
828 DAVRequestEnvironment(
829 new DAVAuthListener_Impl( xEnv, m_aURL ),
830 aHeaders ),
831 bOverwrite );
833 catch (DAVException const& e)
835 errorCount++;
836 bRetry = handleException( e, errorCount );
837 if ( !bRetry )
838 throw;
841 while ( bRetry );
845 void DAVResourceAccess::MOVE(
846 const OUString & rSourcePath,
847 const OUString & rDestinationURI,
848 bool bOverwrite,
849 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
851 initialize();
853 int errorCount = 0;
854 bool bRetry;
857 bRetry = false;
860 DAVRequestHeaders aHeaders;
861 getUserRequestHeaders( xEnv,
862 getRequestURI(),
863 ucb::WebDAVHTTPMethod_MOVE,
864 aHeaders );
866 m_xSession->MOVE( rSourcePath,
867 rDestinationURI,
868 DAVRequestEnvironment(
869 new DAVAuthListener_Impl( xEnv, m_aURL ),
870 aHeaders ),
871 bOverwrite );
873 catch (DAVException const& e)
875 errorCount++;
876 bRetry = handleException( e, errorCount );
877 if ( !bRetry )
878 throw;
881 while ( bRetry );
885 void DAVResourceAccess::DESTROY(
886 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
888 initialize();
890 int errorCount = 0;
891 bool bRetry;
894 bRetry = false;
897 DAVRequestHeaders aHeaders;
898 getUserRequestHeaders( xEnv,
899 getRequestURI(),
900 ucb::WebDAVHTTPMethod_DELETE,
901 aHeaders );
903 m_xSession->DESTROY( getRequestURI(),
904 DAVRequestEnvironment(
905 new DAVAuthListener_Impl( xEnv, m_aURL ),
906 aHeaders ) );
908 catch (DAVException const& e)
910 errorCount++;
911 bRetry = handleException( e, errorCount );
912 if ( !bRetry )
913 throw;
916 while ( bRetry );
920 // set new lock.
921 void DAVResourceAccess::LOCK(
922 ucb::Lock & inLock,
923 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
925 initialize();
927 int errorCount = 0;
928 bool bRetry;
931 bRetry = false;
934 DAVRequestHeaders aHeaders;
935 getUserRequestHeaders( xEnv,
936 getRequestURI(),
937 ucb::WebDAVHTTPMethod_LOCK,
938 aHeaders );
940 m_xSession->LOCK( getRequestURI(),
941 inLock,
942 DAVRequestEnvironment(
943 new DAVAuthListener_Impl( xEnv, m_aURL ),
944 aHeaders ) );
946 catch (DAVException const& e)
948 errorCount++;
949 bRetry = handleException( e, errorCount );
950 if ( !bRetry )
951 throw;
954 while ( bRetry );
957 void DAVResourceAccess::UNLOCK(
958 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
960 initialize();
962 int errorCount = 0;
963 bool bRetry;
966 bRetry = false;
969 DAVRequestHeaders aHeaders;
970 getUserRequestHeaders( xEnv,
971 getRequestURI(),
972 ucb::WebDAVHTTPMethod_UNLOCK,
973 aHeaders );
975 m_xSession->UNLOCK( getRequestURI(),
976 DAVRequestEnvironment(
977 new DAVAuthListener_Impl( xEnv, m_aURL ),
978 aHeaders ) );
980 catch (DAVException const& e)
982 errorCount++;
983 bRetry = handleException( e, errorCount );
984 if ( !bRetry )
985 throw;
988 while ( bRetry );
991 void DAVResourceAccess::setFlags( const uno::Sequence< beans::NamedValue >& rFlags )
993 osl::Guard< osl::Mutex > aGuard( m_aMutex );
994 m_aFlags = rFlags;
997 void DAVResourceAccess::setURL( const OUString & rNewURL )
999 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1000 m_aURL = rNewURL;
1001 m_aPath.clear(); // Next initialize() will create new session.
1005 // init dav session and path
1006 void DAVResourceAccess::initialize()
1008 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1009 if ( m_aPath.isEmpty() )
1011 CurlUri aURI(m_aURL);
1012 assert(aURI.GetScheme() == HTTP_URL_SCHEME || aURI.GetScheme() == HTTPS_URL_SCHEME);
1013 if (aURI.GetScheme() == HTTP_URL_SCHEME)
1015 if (!officecfg::Office::Security::Net::AllowInsecureProtocols::get())
1017 // "http" not allowed -> immediately redirect to "https",
1018 // better than showing confusing error to user
1019 aURI.SetScheme(HTTPS_URL_SCHEME);
1022 OUString aPath( aURI.GetRelativeReference() );
1024 /* #134089# - Check URI */
1025 if ( aPath.isEmpty() )
1026 throw DAVException( DAVException::DAV_INVALID_ARG );
1028 /* #134089# - Check URI */
1029 if ( aURI.GetHost().isEmpty() )
1030 throw DAVException( DAVException::DAV_INVALID_ARG );
1032 if ( !m_xSession.is() || !m_xSession->CanUse( m_aURL, m_aFlags ) )
1034 m_xSession.clear();
1036 // create new webdav session
1037 m_xSession = m_xSessionFactory->createDAVSession(aURI.GetURI(), m_aFlags, m_xContext);
1039 if ( !m_xSession.is() )
1040 return;
1043 // Own URI is needed to redirect cycle detection.
1044 m_aRedirectURIs.push_back( aURI );
1046 // Success.
1047 m_aPath = aPath;
1049 // Not only the path has to be encoded
1050 m_aURL = aURI.GetURI();
1055 const OUString & DAVResourceAccess::getRequestURI() const
1057 assert(m_xSession.is() &&
1058 "DAVResourceAccess::getRequestURI - Not initialized!");
1060 // In case a proxy is used we have to use the absolute URI for a request.
1061 if ( m_xSession->UsesProxy() )
1062 return m_aURL;
1064 return m_aPath;
1068 // static
1069 void DAVResourceAccess::getUserRequestHeaders(
1070 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
1071 const OUString & rURI,
1072 ucb::WebDAVHTTPMethod eMethod,
1073 DAVRequestHeaders & rRequestHeaders )
1075 if ( !xEnv.is() )
1076 return;
1078 uno::Reference< ucb::XWebDAVCommandEnvironment > xDAVEnv(
1079 xEnv, uno::UNO_QUERY );
1081 if ( !xDAVEnv.is() )
1082 return;
1084 uno::Sequence< beans::StringPair > aRequestHeaders
1085 = xDAVEnv->getUserRequestHeaders( rURI, eMethod );
1087 for ( sal_Int32 n = 0; n < aRequestHeaders.getLength(); ++n )
1089 rRequestHeaders.push_back(
1090 DAVRequestHeader( aRequestHeaders[ n ].First,
1091 aRequestHeaders[ n ].Second ) );
1095 // This function member implements the control on cyclical redirections
1096 bool DAVResourceAccess::detectRedirectCycle(
1097 ::std::u16string_view const rRedirectURL)
1099 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1101 CurlUri const aUri( rRedirectURL );
1103 // Check for maximum number of redirections
1104 // according to <https://tools.ietf.org/html/rfc7231#section-6.4>.
1105 // A practical limit may be 5, due to earlier specifications:
1106 // <https://tools.ietf.org/html/rfc2068#section-10.3>
1107 // it can be raised keeping in mind the added net activity.
1108 if( g_nRedirectLimit <= m_aRedirectURIs.size() )
1109 return true;
1111 // try to detect a cyclical redirection
1112 return std::any_of(m_aRedirectURIs.begin(), m_aRedirectURIs.end(),
1113 [&aUri](const CurlUri& rUri) { return aUri == rUri; });
1117 void DAVResourceAccess::resetUri()
1119 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1120 if ( ! m_aRedirectURIs.empty() )
1122 auto const it = m_aRedirectURIs.begin();
1124 CurlUri const aUri( *it );
1125 m_aRedirectURIs.clear();
1126 setURL ( aUri.GetURI() );
1127 initialize();
1132 bool DAVResourceAccess::handleException(DAVException const& e, int const errorCount)
1134 switch ( e.getError() )
1136 case DAVException::DAV_HTTP_REDIRECT:
1137 if ( !detectRedirectCycle( e.getData() ) )
1139 // set new URL and path.
1140 setURL( e.getData() );
1141 initialize();
1142 return true;
1144 return false;
1145 // i#67048 copy & paste images doesn't display. This bug refers
1146 // to an old OOo problem about getting resources from sites with a bad connection.
1147 // If we have a bad connection try again. Up to three times.
1148 case DAVException::DAV_HTTP_ERROR:
1149 // retry up to three times, if not a client-side error (4xx error codes)
1150 if ( e.getStatus() < SC_BAD_REQUEST && errorCount < 3 )
1151 return true;
1152 // check the server side errors
1153 switch( e.getStatus() )
1155 // the HTTP server side response status codes that can be retried
1156 // [Serf TODO? i#119036] case SC_REQUEST_ENTITY_TOO_LARGE:
1157 case SC_BAD_GATEWAY: // retry, can be an excessive load
1158 case SC_GATEWAY_TIMEOUT: // retry, may be we get lucky
1159 case SC_SERVICE_UNAVAILABLE: // retry, the service may become available
1160 case SC_INSUFFICIENT_STORAGE: // space may be freed, retry
1162 if ( errorCount < 3 )
1163 return true;
1164 else
1165 return false;
1167 break;
1168 // all the other HTTP server response status codes are NOT retry
1169 default:
1170 return false;
1172 break;
1173 // if connection has said retry then retry!
1174 case DAVException::DAV_HTTP_RETRY:
1175 return true;
1176 // <--
1177 default:
1178 return false; // Abort
1182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */