1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <com/sun/star/io/IOException.hpp>
31 #include <com/sun/star/lang/IllegalArgumentException.hpp>
32 #include <com/sun/star/task/XInteractionAbort.hpp>
33 #include <com/sun/star/ucb/XWebDAVCommandEnvironment.hpp>
35 #include <ucbhelper/simpleauthenticationrequest.hxx>
36 #include <comphelper/seekableinput.hxx>
38 #include "DAVAuthListenerImpl.hxx"
39 #include "DAVResourceAccess.hxx"
41 using namespace webdav_ucp
;
42 using namespace com::sun::star
;
45 // DAVAuthListener_Impl Implementation.
47 static constexpr sal_uInt32 g_nRedirectLimit
= 5;
50 int DAVAuthListener_Impl::authenticate(
51 const OUString
& inRealm
,
52 const OUString
& inHostName
,
53 OUString
& inoutUserName
,
54 OUString
& outPassWord
,
55 bool bCanUseSystemCredentials
)
59 uno::Reference
< task::XInteractionHandler
> xIH
60 = m_xEnv
->getInteractionHandler();
64 // #102871# - Supply username and password from previous try.
65 // Password container service depends on this!
66 if ( inoutUserName
.isEmpty() )
67 inoutUserName
= m_aPrevUsername
;
69 if ( outPassWord
.isEmpty() )
70 outPassWord
= m_aPrevPassword
;
72 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
73 = new ucbhelper::SimpleAuthenticationRequest(
74 m_aURL
, inHostName
, inRealm
, inoutUserName
,
75 outPassWord
, bCanUseSystemCredentials
);
76 xIH
->handle( xRequest
.get() );
78 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
79 = xRequest
->getSelection();
81 if ( xSelection
.is() )
83 // Handler handled the request.
84 uno::Reference
< task::XInteractionAbort
> xAbort(
85 xSelection
.get(), uno::UNO_QUERY
);
89 ucbhelper::InteractionSupplyAuthentication
> & xSupp
90 = xRequest
->getAuthenticationSupplier();
92 bool bUseSystemCredentials
= false;
94 if ( bCanUseSystemCredentials
)
96 = xSupp
->getUseSystemCredentials();
98 if ( bUseSystemCredentials
)
100 // This is the (strange) way to tell neon to use
101 // system credentials.
102 inoutUserName
.clear();
107 inoutUserName
= xSupp
->getUserName();
108 outPassWord
= xSupp
->getPassword();
111 // #102871# - Remember username and password.
112 m_aPrevUsername
= inoutUserName
;
113 m_aPrevPassword
= outPassWord
;
126 // DAVResourceAccess Implementation.
129 DAVResourceAccess::DAVResourceAccess(
130 const uno::Reference
< uno::XComponentContext
> & rxContext
,
131 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
,
132 const OUString
& rURL
)
134 m_xSessionFactory( rSessionFactory
),
135 m_xContext( rxContext
)
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
;
166 void DAVResourceAccess::OPTIONS(
167 DAVOptions
& rOptions
,
168 const css::uno::Reference
<
169 css::ucb::XCommandEnvironment
> & xEnv
)
180 DAVRequestHeaders aHeaders
;
182 getUserRequestHeaders( xEnv
,
184 css::ucb::WebDAVHTTPMethod_OPTIONS
,
187 m_xSession
->OPTIONS( getRequestURI(),
189 DAVRequestEnvironment(
191 new DAVAuthListener_Impl( xEnv
, m_aURL
),
194 catch ( const DAVException
& e
)
197 bRetry
= handleException( e
, errorCount
);
205 void DAVResourceAccess::PROPFIND(
207 const std::vector
< OUString
> & rPropertyNames
,
208 std::vector
< DAVResource
> & rResources
,
209 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
220 DAVRequestHeaders aHeaders
;
222 getUserRequestHeaders( xEnv
,
224 ucb::WebDAVHTTPMethod_PROPFIND
,
227 m_xSession
->PROPFIND( getRequestURI(),
231 DAVRequestEnvironment(
233 new DAVAuthListener_Impl( xEnv
, m_aURL
),
236 catch ( const DAVException
& e
)
239 bRetry
= handleException( e
, errorCount
);
248 void DAVResourceAccess::PROPFIND(
250 std::vector
< DAVResourceInfo
> & rResInfo
,
251 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
262 DAVRequestHeaders aHeaders
;
263 getUserRequestHeaders( xEnv
,
265 ucb::WebDAVHTTPMethod_PROPFIND
,
268 m_xSession
->PROPFIND( getRequestURI(),
271 DAVRequestEnvironment(
273 new DAVAuthListener_Impl( xEnv
, m_aURL
),
276 catch ( const DAVException
& e
)
279 bRetry
= handleException( e
, errorCount
);
288 void DAVResourceAccess::PROPPATCH(
289 const std::vector
< ProppatchValue
>& rValues
,
290 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
301 DAVRequestHeaders aHeaders
;
302 getUserRequestHeaders( xEnv
,
304 ucb::WebDAVHTTPMethod_PROPPATCH
,
307 m_xSession
->PROPPATCH( getRequestURI(),
309 DAVRequestEnvironment(
311 new DAVAuthListener_Impl( xEnv
, m_aURL
),
314 catch ( const DAVException
& e
)
317 bRetry
= handleException( e
, errorCount
);
326 void DAVResourceAccess::HEAD(
327 const std::vector
< OUString
> & rHeaderNames
,
328 DAVResource
& rResource
,
329 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
340 DAVRequestHeaders aHeaders
;
341 getUserRequestHeaders( xEnv
,
343 ucb::WebDAVHTTPMethod_HEAD
,
346 m_xSession
->HEAD( getRequestURI(),
349 DAVRequestEnvironment(
351 new DAVAuthListener_Impl( xEnv
, m_aURL
),
354 catch ( const DAVException
& e
)
357 bRetry
= handleException( e
, errorCount
);
366 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
367 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
371 uno::Reference
< io::XInputStream
> xStream
;
379 DAVRequestHeaders aHeaders
;
380 getUserRequestHeaders( xEnv
,
382 ucb::WebDAVHTTPMethod_GET
,
385 xStream
= m_xSession
->GET( getRequestURI(),
386 DAVRequestEnvironment(
388 new DAVAuthListener_Impl(
392 catch ( const DAVException
& e
)
395 bRetry
= handleException( e
, errorCount
);
406 void DAVResourceAccess::GET(
407 uno::Reference
< io::XOutputStream
> & rStream
,
408 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
419 DAVRequestHeaders aHeaders
;
420 getUserRequestHeaders( xEnv
,
422 ucb::WebDAVHTTPMethod_GET
,
425 m_xSession
->GET( getRequestURI(),
427 DAVRequestEnvironment(
429 new DAVAuthListener_Impl( xEnv
, m_aURL
),
432 catch ( const DAVException
& e
)
435 bRetry
= handleException( e
, errorCount
);
443 uno::Reference
< io::XInputStream
> DAVResourceAccess::GET(
444 const std::vector
< OUString
> & rHeaderNames
,
445 DAVResource
& rResource
,
446 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
450 uno::Reference
< io::XInputStream
> xStream
;
458 DAVRequestHeaders aHeaders
;
459 getUserRequestHeaders( xEnv
,
461 ucb::WebDAVHTTPMethod_GET
,
464 xStream
= m_xSession
->GET( getRequestURI(),
467 DAVRequestEnvironment(
469 new DAVAuthListener_Impl(
473 catch ( const DAVException
& e
)
476 bRetry
= handleException( e
, errorCount
);
486 // used as HEAD substitute when HEAD is not implemented on server
487 void DAVResourceAccess::GET0(
488 DAVRequestHeaders
&rRequestHeaders
,
489 const std::vector
< OUString
> & rHeaderNames
,
490 DAVResource
& rResource
,
491 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
502 getUserRequestHeaders( xEnv
,
504 ucb::WebDAVHTTPMethod_GET
,
507 m_xSession
->GET0( getRequestURI(),
510 DAVRequestEnvironment(
512 new DAVAuthListener_Impl(
514 rRequestHeaders
, xEnv
) );
516 catch ( const DAVException
& e
)
519 bRetry
= handleException( e
, errorCount
);
528 void DAVResourceAccess::GET(
529 uno::Reference
< io::XOutputStream
> & rStream
,
530 const std::vector
< OUString
> & rHeaderNames
,
531 DAVResource
& rResource
,
532 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
543 DAVRequestHeaders aHeaders
;
544 getUserRequestHeaders( xEnv
,
546 ucb::WebDAVHTTPMethod_GET
,
549 m_xSession
->GET( getRequestURI(),
553 DAVRequestEnvironment(
555 new DAVAuthListener_Impl( xEnv
, m_aURL
),
558 catch ( const DAVException
& e
)
561 bRetry
= handleException( e
, errorCount
);
570 void DAVResourceAccess::abort()
579 /// @throws DAVException
580 void resetInputStream( const uno::Reference
< io::XInputStream
> & rStream
)
584 uno::Reference
< io::XSeekable
> xSeekable(
585 rStream
, uno::UNO_QUERY
);
586 if ( xSeekable
.is() )
588 xSeekable
->seek( 0 );
592 catch ( lang::IllegalArgumentException
const & )
595 catch ( io::IOException
const & )
599 throw DAVException( DAVException::DAV_INVALID_ARG
);
605 void DAVResourceAccess::PUT(
606 const uno::Reference
< io::XInputStream
> & rStream
,
607 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
611 // Make stream seekable, if it not. Needed, if request must be retried.
612 uno::Reference
< io::XInputStream
> xSeekableStream
613 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
614 rStream
, m_xContext
);
621 resetInputStream( xSeekableStream
);
626 DAVRequestHeaders aHeaders
;
627 getUserRequestHeaders( xEnv
,
629 ucb::WebDAVHTTPMethod_PUT
,
632 m_xSession
->PUT( getRequestURI(),
634 DAVRequestEnvironment(
636 new DAVAuthListener_Impl( xEnv
, m_aURL
),
639 catch ( const DAVException
& e
)
642 bRetry
= handleException( e
, errorCount
);
651 uno::Reference
< io::XInputStream
> DAVResourceAccess::POST(
652 const OUString
& rContentType
,
653 const OUString
& rReferer
,
654 const uno::Reference
< io::XInputStream
> & rInputStream
,
655 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
659 // Make stream seekable, if it not. Needed, if request must be retried.
660 uno::Reference
< io::XInputStream
> xSeekableStream
661 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
662 rInputStream
, m_xContext
);
664 uno::Reference
< io::XInputStream
> xStream
;
671 resetInputStream( xSeekableStream
);
677 DAVRequestHeaders aHeaders
;
678 getUserRequestHeaders( xEnv
,
680 ucb::WebDAVHTTPMethod_POST
,
683 xStream
= m_xSession
->POST( getRequestURI(),
687 DAVRequestEnvironment(
689 new DAVAuthListener_Impl(
693 catch ( const DAVException
& e
)
696 bRetry
= handleException( e
, errorCount
);
700 if ( e
.getError() == DAVException::DAV_HTTP_REDIRECT
)
702 // #i74980# - Upon POST redirect, do a GET.
713 void DAVResourceAccess::POST(
714 const OUString
& rContentType
,
715 const OUString
& rReferer
,
716 const uno::Reference
< io::XInputStream
> & rInputStream
,
717 uno::Reference
< io::XOutputStream
> & rOutputStream
,
718 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
722 // Make stream seekable, if it not. Needed, if request must be retried.
723 uno::Reference
< io::XInputStream
> xSeekableStream
724 = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
725 rInputStream
, m_xContext
);
733 resetInputStream( xSeekableStream
);
739 DAVRequestHeaders aHeaders
;
740 getUserRequestHeaders( xEnv
,
742 ucb::WebDAVHTTPMethod_POST
,
745 m_xSession
->POST( getRequestURI(),
750 DAVRequestEnvironment(
752 new DAVAuthListener_Impl( xEnv
, m_aURL
),
755 catch ( const DAVException
& e
)
758 bRetry
= handleException( e
, errorCount
);
762 if ( e
.getError() == DAVException::DAV_HTTP_REDIRECT
)
764 // #i74980# - Upon POST redirect, do a GET.
765 GET( rOutputStream
, xEnv
);
774 void DAVResourceAccess::MKCOL(
775 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
786 DAVRequestHeaders aHeaders
;
787 getUserRequestHeaders( xEnv
,
789 ucb::WebDAVHTTPMethod_MKCOL
,
792 m_xSession
->MKCOL( getRequestURI(),
793 DAVRequestEnvironment(
795 new DAVAuthListener_Impl( xEnv
, m_aURL
),
798 catch ( const DAVException
& e
)
801 bRetry
= handleException( e
, errorCount
);
810 void DAVResourceAccess::COPY(
811 const OUString
& rSourcePath
,
812 const OUString
& rDestinationURI
,
814 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
825 DAVRequestHeaders aHeaders
;
826 getUserRequestHeaders( xEnv
,
828 ucb::WebDAVHTTPMethod_COPY
,
831 m_xSession
->COPY( rSourcePath
,
833 DAVRequestEnvironment(
835 new DAVAuthListener_Impl( xEnv
, m_aURL
),
839 catch ( const DAVException
& e
)
842 bRetry
= handleException( e
, errorCount
);
851 void DAVResourceAccess::MOVE(
852 const OUString
& rSourcePath
,
853 const OUString
& rDestinationURI
,
855 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
866 DAVRequestHeaders aHeaders
;
867 getUserRequestHeaders( xEnv
,
869 ucb::WebDAVHTTPMethod_MOVE
,
872 m_xSession
->MOVE( rSourcePath
,
874 DAVRequestEnvironment(
876 new DAVAuthListener_Impl( xEnv
, m_aURL
),
880 catch ( const DAVException
& e
)
883 bRetry
= handleException( e
, errorCount
);
892 void DAVResourceAccess::DESTROY(
893 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
904 DAVRequestHeaders aHeaders
;
905 getUserRequestHeaders( xEnv
,
907 ucb::WebDAVHTTPMethod_DELETE
,
910 m_xSession
->DESTROY( getRequestURI(),
911 DAVRequestEnvironment(
913 new DAVAuthListener_Impl( xEnv
, m_aURL
),
916 catch ( const DAVException
& e
)
919 bRetry
= handleException( e
, errorCount
);
929 void DAVResourceAccess::LOCK(
931 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
942 DAVRequestHeaders aHeaders
;
943 getUserRequestHeaders( xEnv
,
945 ucb::WebDAVHTTPMethod_LOCK
,
948 m_xSession
->LOCK( getRequestURI(),
950 DAVRequestEnvironment(
952 new DAVAuthListener_Impl( xEnv
, m_aURL
),
955 catch ( const DAVException
& e
)
958 bRetry
= handleException( e
, errorCount
);
966 void DAVResourceAccess::UNLOCK(
967 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
978 DAVRequestHeaders aHeaders
;
979 getUserRequestHeaders( xEnv
,
981 ucb::WebDAVHTTPMethod_UNLOCK
,
984 m_xSession
->UNLOCK( getRequestURI(),
985 DAVRequestEnvironment(
987 new DAVAuthListener_Impl( xEnv
, m_aURL
),
990 catch ( const DAVException
& e
)
993 bRetry
= handleException( e
, errorCount
);
1002 void DAVResourceAccess::setFlags( const uno::Sequence
< beans::NamedValue
>& rFlags
)
1004 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1009 void DAVResourceAccess::setURL( const OUString
& rNewURL
)
1011 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1013 m_aPath
.clear(); // Next initialize() will create new session.
1017 // init dav session and path
1018 void DAVResourceAccess::initialize()
1020 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1021 if ( m_aPath
.isEmpty() )
1023 NeonUri
aURI( m_aURL
);
1024 const OUString
& aPath( aURI
.GetPath() );
1026 /* #134089# - Check URI */
1027 if ( aPath
.isEmpty() )
1028 throw DAVException( DAVException::DAV_INVALID_ARG
);
1030 /* #134089# - Check URI */
1031 if ( aURI
.GetHost().isEmpty() )
1032 throw DAVException( DAVException::DAV_INVALID_ARG
);
1034 if ( !m_xSession
.is() || !m_xSession
->CanUse( m_aURL
, m_aFlags
) )
1038 // create new webdav session
1040 = m_xSessionFactory
->createDAVSession( m_aURL
, m_aFlags
, m_xContext
);
1042 if ( !m_xSession
.is() )
1046 // Own URI is needed to redirect cycle detection.
1047 m_aRedirectURIs
.push_back( aURI
);
1052 // Not only the path has to be encoded
1053 m_aURL
= aURI
.GetURI();
1058 const OUString
& DAVResourceAccess::getRequestURI() const
1060 assert( m_xSession
.is() && "DAVResourceAccess::getRequestURI - Not initialized!" );
1062 // In case a proxy is used we have to use the absolute URI for a request.
1063 if ( m_xSession
->UsesProxy() )
1071 void DAVResourceAccess::getUserRequestHeaders(
1072 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1073 const OUString
& rURI
,
1074 ucb::WebDAVHTTPMethod eMethod
,
1075 DAVRequestHeaders
& rRequestHeaders
)
1079 uno::Reference
< ucb::XWebDAVCommandEnvironment
> xDAVEnv(
1080 xEnv
, uno::UNO_QUERY
);
1084 const uno::Sequence
< beans::StringPair
> aRequestHeaders
1085 = xDAVEnv
->getUserRequestHeaders( rURI
, eMethod
);
1087 for ( const auto& rRequestHeader
: aRequestHeaders
)
1089 rRequestHeaders
.emplace_back(
1090 rRequestHeader
.First
,
1091 rRequestHeader
.Second
);
1096 // Make sure a User-Agent header is always included, as at least
1097 // en.wikipedia.org:80 forces back 403 "Scripts should use an informative
1098 // User-Agent string with contact information, or they may be IP-blocked
1099 // without notice" otherwise:
1100 if ( std::any_of(rRequestHeaders
.begin(), rRequestHeaders
.end(),
1101 [](const DAVRequestHeader
& rHeader
) { return rHeader
.first
.equalsIgnoreAsciiCase( "User-Agent" ); }) )
1105 rRequestHeaders
.emplace_back( "User-Agent", "LibreOffice" );
1108 // This function member implements the control on cyclical redirections
1109 bool DAVResourceAccess::detectRedirectCycle(
1110 const OUString
& rRedirectURL
)
1112 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1114 NeonUri
aUri( rRedirectURL
);
1116 // Check for maximum number of redirections
1117 // according to <https://tools.ietf.org/html/rfc7231#section-6.4>.
1118 // A practical limit may be 5, due to earlier specifications:
1119 // <https://tools.ietf.org/html/rfc2068#section-10.3>
1120 // it can be raised keeping in mind the added net activity.
1121 if( static_cast< size_t >( g_nRedirectLimit
) <= m_aRedirectURIs
.size() )
1124 // try to detect a cyclical redirection
1125 return std::any_of(m_aRedirectURIs
.begin(), m_aRedirectURIs
.end(),
1126 [&aUri
](const NeonUri
& rUri
) {
1127 // if equal, cyclical redirection detected
1128 return aUri
== rUri
; });
1132 void DAVResourceAccess::resetUri()
1134 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1135 if ( !m_aRedirectURIs
.empty() )
1137 std::vector
< NeonUri
>::const_iterator it
= m_aRedirectURIs
.begin();
1139 NeonUri
aUri( *it
);
1140 m_aRedirectURIs
.clear();
1141 setURL ( aUri
.GetURI() );
1147 bool DAVResourceAccess::handleException( const DAVException
& e
, int errorCount
)
1149 switch ( e
.getError() )
1151 case DAVException::DAV_HTTP_REDIRECT
:
1152 if ( !detectRedirectCycle( e
.getData() ) )
1154 // set new URL and path.
1155 setURL( e
.getData() );
1160 // #67048# copy & paste images doesn't display. This bug refers
1161 // to an old OOo problem about getting resources from sites with a bad connection.
1162 // If we have a bad connection try again. Up to three times.
1163 case DAVException::DAV_HTTP_ERROR
:
1164 // retry up to three times, if not a client-side error (4xx error codes)
1165 if ( e
.getStatus() < SC_BAD_REQUEST
&& errorCount
< 3 )
1167 // check the server side errors
1168 switch( e
.getStatus() )
1170 // the HTTP server side response status codes that can be retried
1171 case SC_BAD_GATEWAY
: // retry, can be an excessive load
1172 case SC_GATEWAY_TIMEOUT
: // retry, may be we get lucky
1173 case SC_SERVICE_UNAVAILABLE
: // retry, the service may become available
1174 case SC_INSUFFICIENT_STORAGE
: // space may be freed, retry
1176 return errorCount
< 3;
1179 // all the other HTTP server response status codes are NOT retry
1184 // if connection has said retry then retry!
1185 case DAVException::DAV_HTTP_RETRY
:
1188 return false; // Abort
1192 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */