1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_ucb.hxx"
26 
27 #include "osl/diagnose.h"
28 
29 #include "com/sun/star/task/XInteractionAbort.hpp"
30 #include "com/sun/star/ucb/XWebDAVCommandEnvironment.hpp"
31 
32 #include "ucbhelper/simpleauthenticationrequest.hxx"
33 #include "comphelper/seekableinput.hxx"
34 
35 #include "DAVAuthListenerImpl.hxx"
36 #include "DAVResourceAccess.hxx"
37 
38 using namespace http_dav_ucp;
39 using namespace com::sun::star;
40 
41 //=========================================================================
42 //=========================================================================
43 //
44 // DAVAuthListener_Impl Implementation.
45 //
46 //=========================================================================
47 //=========================================================================
48 
49 //=========================================================================
50 // virtual
51 int DAVAuthListener_Impl::authenticate(
52     const ::rtl::OUString & inRealm,
53     const ::rtl::OUString & inHostName,
54     ::rtl::OUString & inoutUserName,
55     ::rtl::OUString & outPassWord,
56     sal_Bool bCanUseSystemCredentials,
57     sal_Bool bUsePreviousCredentials )
58 {
59     if ( m_xEnv.is() )
60     {
61         uno::Reference< task::XInteractionHandler > xIH
62             = m_xEnv->getInteractionHandler();
63 
64         if ( xIH.is() )
65         {
66             // Providing previously retrieved credentials will cause the password
67             // container to reject these. Thus, the credential input dialog will be shown again.
68             // #102871# - Supply username and password from previous try.
69             // Password container service depends on this!
70             if ( inoutUserName.getLength() == 0 && bUsePreviousCredentials )
71                 inoutUserName = m_aPrevUsername;
72 
73             if ( outPassWord.getLength() == 0 && bUsePreviousCredentials )
74                 outPassWord = m_aPrevPassword;
75 
76             rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
77                 = new ucbhelper::SimpleAuthenticationRequest(
78                     m_aURL, inHostName, inRealm, inoutUserName,
79                     outPassWord, ::rtl::OUString(),
80                     true /*bAllowPersistentStoring*/,
81                     bCanUseSystemCredentials );
82             xIH->handle( xRequest.get() );
83 
84             rtl::Reference< ucbhelper::InteractionContinuation > xSelection
85                 = xRequest->getSelection();
86 
87             if ( xSelection.is() )
88             {
89                 // Handler handled the request.
90                 uno::Reference< task::XInteractionAbort > xAbort(
91                     xSelection.get(), uno::UNO_QUERY );
92                 if ( !xAbort.is() )
93                 {
94                     const rtl::Reference<
95                         ucbhelper::InteractionSupplyAuthentication > & xSupp
96                         = xRequest->getAuthenticationSupplier();
97 
98                     sal_Bool bUseSystemCredentials = sal_False;
99 
100                     if ( bCanUseSystemCredentials )
101                         bUseSystemCredentials
102                             = xSupp->getUseSystemCredentials();
103 
104                     if ( bUseSystemCredentials )
105                     {
106                         // This is the (strange) way to tell neon to use
107                         // system credentials.
108                         inoutUserName = rtl::OUString();
109                         outPassWord   = rtl::OUString();
110                     }
111                     else
112                     {
113                         inoutUserName = xSupp->getUserName();
114                         outPassWord   = xSupp->getPassword();
115                     }
116 
117                     // #102871# - Remember username and password.
118                     m_aPrevUsername = inoutUserName;
119                     m_aPrevPassword = outPassWord;
120 
121                     // go on.
122                     return 0;
123                 }
124             }
125         }
126     }
127     // Abort.
128     return -1;
129 }
130 
131 //=========================================================================
132 //=========================================================================
133 //
134 // DAVResourceAccess Implementation.
135 //
136 //=========================================================================
137 //=========================================================================
138 
139 //=========================================================================
140 DAVResourceAccess::DAVResourceAccess(
141     const uno::Reference< lang::XMultiServiceFactory > & rSMgr,
142     rtl::Reference< DAVSessionFactory > const & rSessionFactory,
143     const rtl::OUString & rURL )
144 : m_aURL( rURL ),
145   m_xSessionFactory( rSessionFactory ),
146   m_xSMgr( rSMgr )
147 {
148 }
149 
150 //=========================================================================
151 DAVResourceAccess::DAVResourceAccess( const DAVResourceAccess & rOther )
152 : m_aURL( rOther.m_aURL ),
153   m_aPath( rOther.m_aPath ),
154   m_xSession( rOther.m_xSession ),
155   m_xSessionFactory( rOther.m_xSessionFactory ),
156   m_xSMgr( rOther.m_xSMgr ),
157   m_aRedirectURIs( rOther.m_aRedirectURIs )
158 {
159 }
160 
161 //=========================================================================
162 DAVResourceAccess & DAVResourceAccess::operator=(
163     const DAVResourceAccess & rOther )
164 {
165     m_aURL            = rOther.m_aURL;
166     m_aPath           = rOther.m_aPath;
167     m_xSession        = rOther.m_xSession;
168     m_xSessionFactory = rOther.m_xSessionFactory;
169     m_xSMgr           = rOther.m_xSMgr;
170     m_aRedirectURIs   = rOther.m_aRedirectURIs;
171 
172     return *this;
173 }
174 
175 //=========================================================================
176 void DAVResourceAccess::PROPFIND(
177     const Depth nDepth,
178     const std::vector< rtl::OUString > & rPropertyNames,
179     std::vector< DAVResource > & rResources,
180     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
181   throw( DAVException )
182 {
183     initialize();
184 
185     int errorCount = 0;
186     bool bRetry;
187     do
188     {
189         bRetry = false;
190         try
191         {
192             DAVRequestHeaders aHeaders;
193 
194             getUserRequestHeaders( xEnv,
195                                    getRequestURI(),
196                                    rtl::OUString::createFromAscii(
197                                        "PROPFIND" ),
198                                    aHeaders );
199 
200             m_xSession->PROPFIND( getRequestURI(),
201                                   nDepth,
202                                   rPropertyNames,
203                                   rResources,
204                                   DAVRequestEnvironment(
205                                       getRequestURI(),
206                                       new DAVAuthListener_Impl( xEnv, m_aURL ),
207                                       aHeaders, xEnv ) );
208         }
209         catch ( DAVException & e )
210         {
211             errorCount++;
212             bRetry = handleException( e, errorCount );
213             if ( !bRetry )
214                 throw;
215         }
216     }
217     while ( bRetry );
218 }
219 
220 //=========================================================================
221 void DAVResourceAccess::PROPFIND(
222     const Depth nDepth,
223     std::vector< DAVResourceInfo > & rResInfo,
224     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
225   throw( DAVException )
226 {
227     initialize();
228 
229     int errorCount = 0;
230     bool bRetry;
231     do
232     {
233         bRetry = false;
234         try
235         {
236             DAVRequestHeaders aHeaders;
237             getUserRequestHeaders( xEnv,
238                                    getRequestURI(),
239                                    rtl::OUString::createFromAscii(
240                                        "PROPFIND" ),
241                                    aHeaders );
242 
243             m_xSession->PROPFIND( getRequestURI(),
244                                   nDepth,
245                                   rResInfo,
246                                   DAVRequestEnvironment(
247                                       getRequestURI(),
248                                       new DAVAuthListener_Impl( xEnv, m_aURL ),
249                                       aHeaders, xEnv ) ) ;
250         }
251         catch ( DAVException & e )
252         {
253             errorCount++;
254             bRetry = handleException( e, errorCount );
255             if ( !bRetry )
256                 throw;
257         }
258     }
259     while ( bRetry );
260 }
261 
262 //=========================================================================
263 void DAVResourceAccess::PROPPATCH(
264     const std::vector< ProppatchValue >& rValues,
265     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
266   throw( DAVException )
267 {
268     initialize();
269 
270     int errorCount = 0;
271     bool bRetry;
272     do
273     {
274         bRetry = false;
275         try
276         {
277             DAVRequestHeaders aHeaders;
278             getUserRequestHeaders( xEnv,
279                                    getRequestURI(),
280                                    rtl::OUString::createFromAscii(
281                                        "PROPPATCH" ),
282                                    aHeaders );
283 
284             m_xSession->PROPPATCH( getRequestURI(),
285                                    rValues,
286                                    DAVRequestEnvironment(
287                                        getRequestURI(),
288                                        new DAVAuthListener_Impl( xEnv, m_aURL ),
289                                        aHeaders, xEnv ) );
290         }
291         catch ( DAVException & e )
292         {
293             errorCount++;
294             bRetry = handleException( e, errorCount );
295             if ( !bRetry )
296                 throw;
297         }
298     }
299     while ( bRetry );
300 }
301 
302 //=========================================================================
303 void DAVResourceAccess::HEAD(
304     const std::vector< rtl::OUString > & rHeaderNames,
305     DAVResource & rResource,
306     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
307   throw( DAVException )
308 {
309     initialize();
310 
311     int errorCount = 0;
312     bool bRetry;
313     do
314     {
315         bRetry = false;
316         try
317         {
318             DAVRequestHeaders aHeaders;
319             getUserRequestHeaders( xEnv,
320                                    getRequestURI(),
321                                    rtl::OUString::createFromAscii( "HEAD" ),
322                                    aHeaders );
323 
324             m_xSession->HEAD( getRequestURI(),
325                               rHeaderNames,
326                               rResource,
327                               DAVRequestEnvironment(
328                                   getRequestURI(),
329                                   new DAVAuthListener_Impl( xEnv, m_aURL ),
330                                   aHeaders, xEnv ) );
331         }
332         catch ( DAVException & e )
333         {
334             errorCount++;
335             bRetry = handleException( e, errorCount );
336             if ( !bRetry )
337                 throw;
338         }
339     }
340     while ( bRetry );
341 }
342 
343 //=========================================================================
344 uno::Reference< io::XInputStream > DAVResourceAccess::GET(
345     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
346   throw( DAVException )
347 {
348     initialize();
349 
350     uno::Reference< io::XInputStream > xStream;
351     int errorCount = 0;
352     bool bRetry;
353     do
354     {
355         bRetry = false;
356         try
357         {
358             DAVRequestHeaders aHeaders;
359             getUserRequestHeaders( xEnv,
360                                    getRequestURI(),
361                                    rtl::OUString::createFromAscii( "GET" ),
362                                    aHeaders );
363 
364             xStream = m_xSession->GET( getRequestURI(),
365                                        DAVRequestEnvironment(
366                                            getRequestURI(),
367                                            new DAVAuthListener_Impl(
368                                                xEnv, m_aURL ),
369                                            aHeaders, xEnv ) );
370         }
371         catch ( DAVException & e )
372         {
373             errorCount++;
374             bRetry = handleException( e, errorCount );
375             if ( !bRetry )
376                 throw;
377         }
378     }
379     while ( bRetry );
380 
381     return xStream;
382 }
383 
384 //=========================================================================
385 void DAVResourceAccess::GET(
386     uno::Reference< io::XOutputStream > & rStream,
387     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
388   throw( DAVException )
389 {
390     initialize();
391 
392     int errorCount = 0;
393     bool bRetry;
394     do
395     {
396         bRetry = false;
397         try
398         {
399             DAVRequestHeaders aHeaders;
400             getUserRequestHeaders( xEnv,
401                                    getRequestURI(),
402                                    rtl::OUString::createFromAscii( "GET" ),
403                                    aHeaders );
404 
405             m_xSession->GET( getRequestURI(),
406                              rStream,
407                              DAVRequestEnvironment(
408                                  getRequestURI(),
409                                  new DAVAuthListener_Impl( xEnv, m_aURL ),
410                                  aHeaders, xEnv ) );
411         }
412         catch ( DAVException & e )
413         {
414             errorCount++;
415             bRetry = handleException( e, errorCount );
416             if ( !bRetry )
417                 throw;
418         }
419     }
420     while ( bRetry );
421 }
422 
423 //=========================================================================
424 uno::Reference< io::XInputStream > DAVResourceAccess::GET(
425     const std::vector< rtl::OUString > & rHeaderNames,
426     DAVResource & rResource,
427     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
428   throw( DAVException )
429 {
430     initialize();
431 
432     uno::Reference< io::XInputStream > xStream;
433     int errorCount = 0;
434     bool bRetry;
435     do
436     {
437         bRetry = false;
438         try
439         {
440             DAVRequestHeaders aHeaders;
441             getUserRequestHeaders( xEnv,
442                                    getRequestURI(),
443                                    rtl::OUString::createFromAscii( "GET" ),
444                                    aHeaders );
445 
446             xStream = m_xSession->GET( getRequestURI(),
447                                        rHeaderNames,
448                                        rResource,
449                                        DAVRequestEnvironment(
450                                            getRequestURI(),
451                                            new DAVAuthListener_Impl(
452                                                xEnv, m_aURL ),
453                                            aHeaders, xEnv ) );
454         }
455         catch ( DAVException & e )
456         {
457             errorCount++;
458             bRetry = handleException( e, errorCount );
459             if ( !bRetry )
460                 throw;
461         }
462     }
463     while ( bRetry );
464 
465     return xStream;
466 }
467 
468 //=========================================================================
469 void DAVResourceAccess::GET(
470     uno::Reference< io::XOutputStream > & rStream,
471     const std::vector< rtl::OUString > & rHeaderNames,
472     DAVResource & rResource,
473     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
474   throw( DAVException )
475 {
476     initialize();
477 
478     bool bRetry;
479     int errorCount = 0;
480     do
481     {
482         bRetry = false;
483         try
484         {
485             DAVRequestHeaders aHeaders;
486             getUserRequestHeaders( xEnv,
487                                    getRequestURI(),
488                                    rtl::OUString::createFromAscii( "GET" ),
489                                    aHeaders );
490 
491             m_xSession->GET( getRequestURI(),
492                              rStream,
493                              rHeaderNames,
494                              rResource,
495                              DAVRequestEnvironment(
496                                  getRequestURI(),
497                                  new DAVAuthListener_Impl( xEnv, m_aURL ),
498                                  aHeaders, xEnv ) );
499         }
500         catch ( DAVException & e )
501         {
502             errorCount++;
503             bRetry = handleException( e, errorCount );
504             if ( !bRetry )
505                 throw;
506         }
507     }
508     while ( bRetry );
509 }
510 
511 //=========================================================================
512 void DAVResourceAccess::abort()
513   throw( DAVException )
514 {
515     // 17.11.09 (tkr): abort currently disabled caused by issue i106766
516     // initialize();
517     // m_xSession->abort();
518     OSL_TRACE( "Not implemented. -> #i106766#" );
519 }
520 
521 //=========================================================================
522 namespace {
523 
524     void resetInputStream( const uno::Reference< io::XInputStream > & rStream )
525         throw( DAVException )
526     {
527         try
528         {
529             uno::Reference< io::XSeekable > xSeekable(
530                 rStream, uno::UNO_QUERY );
531             if ( xSeekable.is() )
532             {
533                 xSeekable->seek( 0 );
534                 return;
535             }
536         }
537         catch ( lang::IllegalArgumentException const & )
538         {
539         }
540         catch ( io::IOException const & )
541         {
542         }
543 
544         throw DAVException( DAVException::DAV_INVALID_ARG );
545     }
546 
547 } // namespace
548 
549 //=========================================================================
550 void DAVResourceAccess::PUT(
551     const uno::Reference< io::XInputStream > & rStream,
552     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
553   throw( DAVException )
554 {
555     initialize();
556 
557     // Make stream seekable, if it not. Needed, if request must be retried.
558     uno::Reference< io::XInputStream > xSeekableStream
559         = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
560             rStream, m_xSMgr );
561 
562     int errorCount = 0;
563     bool bRetry = false;
564     do
565     {
566         if ( bRetry )
567             resetInputStream( xSeekableStream );
568 
569         bRetry = false;
570         try
571         {
572             DAVRequestHeaders aHeaders;
573             getUserRequestHeaders( xEnv,
574                                    getRequestURI(),
575                                    rtl::OUString::createFromAscii( "PUT" ),
576                                    aHeaders );
577 
578             m_xSession->PUT( getRequestURI(),
579                              xSeekableStream,
580                              DAVRequestEnvironment(
581                                  getRequestURI(),
582                                  new DAVAuthListener_Impl( xEnv, m_aURL ),
583                                  aHeaders, xEnv ) );
584         }
585         catch ( DAVException & e )
586         {
587             errorCount++;
588             bRetry = handleException( e, errorCount );
589             if ( !bRetry )
590                 throw;
591         }
592     }
593     while ( bRetry );
594 }
595 
596 //=========================================================================
597 uno::Reference< io::XInputStream > DAVResourceAccess::POST(
598     const rtl::OUString & rContentType,
599     const rtl::OUString & rReferer,
600     const uno::Reference< io::XInputStream > & rInputStream,
601     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
602   throw ( DAVException )
603 {
604     initialize();
605 
606     // Make stream seekable, if it not. Needed, if request must be retried.
607     uno::Reference< io::XInputStream > xSeekableStream
608         = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
609             rInputStream, m_xSMgr );
610 
611     uno::Reference< io::XInputStream > xStream;
612     int errorCount = 0;
613     bool bRetry = false;
614     do
615     {
616         if ( bRetry )
617         {
618             resetInputStream( xSeekableStream );
619             bRetry = false;
620         }
621 
622         try
623         {
624             DAVRequestHeaders aHeaders;
625             getUserRequestHeaders( xEnv,
626                                    getRequestURI(),
627                                    rtl::OUString::createFromAscii( "POST" ),
628                                    aHeaders );
629 
630             xStream = m_xSession->POST( getRequestURI(),
631                                         rContentType,
632                                         rReferer,
633                                         xSeekableStream,
634                                         DAVRequestEnvironment(
635                                             getRequestURI(),
636                                             new DAVAuthListener_Impl(
637                                                 xEnv, m_aURL ),
638                                             aHeaders, xEnv ) );
639         }
640         catch ( DAVException & e )
641         {
642             errorCount++;
643             bRetry = handleException( e, errorCount );
644             if ( !bRetry )
645                 throw;
646 
647             if ( e.getError() == DAVException::DAV_HTTP_REDIRECT )
648             {
649                 // #i74980# - Upon POST redirect, do a GET.
650                 return GET( xEnv );
651             }
652         }
653     }
654     while ( bRetry );
655 
656     return xStream;
657 }
658 
659 //=========================================================================
660 void DAVResourceAccess::POST(
661     const rtl::OUString & rContentType,
662     const rtl::OUString & rReferer,
663     const uno::Reference< io::XInputStream > & rInputStream,
664     uno::Reference< io::XOutputStream > & rOutputStream,
665     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
666   throw ( DAVException )
667 {
668     initialize();
669 
670     // Make stream seekable, if it not. Needed, if request must be retried.
671     uno::Reference< io::XInputStream > xSeekableStream
672         = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap(
673             rInputStream, m_xSMgr );
674 
675     int errorCount = 0;
676     bool bRetry  = false;
677     do
678     {
679         if ( bRetry )
680         {
681             resetInputStream( xSeekableStream );
682             bRetry = false;
683         }
684 
685         try
686         {
687             DAVRequestHeaders aHeaders;
688             getUserRequestHeaders( xEnv,
689                                    getRequestURI(),
690                                    rtl::OUString::createFromAscii( "POST" ),
691                                    aHeaders );
692 
693             m_xSession->POST( getRequestURI(),
694                               rContentType,
695                               rReferer,
696                               xSeekableStream,
697                               rOutputStream,
698                               DAVRequestEnvironment(
699                                   getRequestURI(),
700                                   new DAVAuthListener_Impl( xEnv, m_aURL ),
701                                   aHeaders, xEnv ) );
702         }
703         catch ( DAVException & e )
704         {
705             errorCount++;
706             bRetry = handleException( e, errorCount );
707             if ( !bRetry )
708                 throw;
709 
710             if ( e.getError() == DAVException::DAV_HTTP_REDIRECT )
711             {
712                 // #i74980# - Upon POST redirect, do a GET.
713                 GET( rOutputStream, xEnv );
714                 return;
715             }
716         }
717     }
718     while ( bRetry );
719 }
720 
721 //=========================================================================
722 void DAVResourceAccess::MKCOL(
723     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
724   throw( DAVException )
725 {
726     initialize();
727 
728     int errorCount = 0;
729     bool bRetry;
730     do
731     {
732         bRetry = false;
733         try
734         {
735             DAVRequestHeaders aHeaders;
736             getUserRequestHeaders( xEnv,
737                                    getRequestURI(),
738                                    rtl::OUString::createFromAscii( "MKCOL" ),
739                                    aHeaders );
740 
741             m_xSession->MKCOL( getRequestURI(),
742                                DAVRequestEnvironment(
743                                    getRequestURI(),
744                                    new DAVAuthListener_Impl( xEnv, m_aURL ),
745                                    aHeaders, xEnv ) );
746         }
747         catch ( DAVException & e )
748         {
749             errorCount++;
750             bRetry = handleException( e, errorCount );
751             if ( !bRetry )
752                 throw;
753         }
754     }
755     while ( bRetry );
756 }
757 
758 //=========================================================================
759 void DAVResourceAccess::COPY(
760     const ::rtl::OUString & rSourcePath,
761     const ::rtl::OUString & rDestinationURI,
762     sal_Bool bOverwrite,
763     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
764   throw( DAVException )
765 {
766     initialize();
767 
768     int errorCount = 0;
769     bool bRetry;
770     do
771     {
772         bRetry = false;
773         try
774         {
775             DAVRequestHeaders aHeaders;
776             getUserRequestHeaders( xEnv,
777                                    getRequestURI(),
778                                    rtl::OUString::createFromAscii( "COPY" ),
779                                    aHeaders );
780 
781             m_xSession->COPY( rSourcePath,
782                               rDestinationURI,
783                               DAVRequestEnvironment(
784                                   getRequestURI(),
785                                   new DAVAuthListener_Impl( xEnv, m_aURL ),
786                                   aHeaders, xEnv ),
787                               bOverwrite );
788         }
789         catch ( DAVException & e )
790         {
791             errorCount++;
792             bRetry = handleException( e, errorCount );
793             if ( !bRetry )
794                 throw;
795         }
796     }
797     while ( bRetry );
798 }
799 
800 //=========================================================================
801 void DAVResourceAccess::MOVE(
802     const ::rtl::OUString & rSourcePath,
803     const ::rtl::OUString & rDestinationURI,
804     sal_Bool bOverwrite,
805     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
806   throw( DAVException )
807 {
808     initialize();
809 
810     int errorCount = 0;
811     bool bRetry;
812     do
813     {
814         bRetry = false;
815         try
816         {
817             DAVRequestHeaders aHeaders;
818             getUserRequestHeaders( xEnv,
819                                    getRequestURI(),
820                                    rtl::OUString::createFromAscii( "MOVE" ),
821                                    aHeaders );
822 
823             m_xSession->MOVE( rSourcePath,
824                               rDestinationURI,
825                               DAVRequestEnvironment(
826                                   getRequestURI(),
827                                   new DAVAuthListener_Impl( xEnv, m_aURL ),
828                                   aHeaders, xEnv ),
829                               bOverwrite );
830         }
831         catch ( DAVException & e )
832         {
833             errorCount++;
834             bRetry = handleException( e, errorCount );
835             if ( !bRetry )
836                 throw;
837         }
838     }
839     while ( bRetry );
840 }
841 
842 //=========================================================================
843 void DAVResourceAccess::DESTROY(
844     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
845   throw( DAVException )
846 {
847     initialize();
848 
849     int errorCount = 0;
850     bool bRetry;
851     do
852     {
853         bRetry = false;
854         try
855         {
856             DAVRequestHeaders aHeaders;
857             getUserRequestHeaders( xEnv,
858                                    getRequestURI(),
859                                    rtl::OUString::createFromAscii(
860                                        "DESTROY" ),
861                                    aHeaders );
862 
863             m_xSession->DESTROY( getRequestURI(),
864                                  DAVRequestEnvironment(
865                                      getRequestURI(),
866                                      new DAVAuthListener_Impl( xEnv, m_aURL ),
867                                      aHeaders, xEnv ) );
868         }
869         catch ( DAVException & e )
870         {
871             errorCount++;
872             bRetry = handleException( e, errorCount );
873             if ( !bRetry )
874                 throw;
875         }
876     }
877     while ( bRetry );
878 }
879 
880 //=========================================================================
881 // set new lock.
882 void DAVResourceAccess::LOCK(
883     ucb::Lock & inLock,
884     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
885   throw ( DAVException )
886 {
887     initialize();
888 
889     int errorCount = 0;
890     bool bRetry;
891     do
892     {
893         bRetry = false;
894         try
895         {
896             DAVRequestHeaders aHeaders;
897             getUserRequestHeaders( xEnv,
898                                    getRequestURI(),
899                                    rtl::OUString::createFromAscii( "LOCK" ),
900                                    aHeaders );
901 
902             m_xSession->LOCK( getRequestURI(),
903                               inLock,
904                               DAVRequestEnvironment(
905                                   getRequestURI(),
906                                   new DAVAuthListener_Impl( xEnv, m_aURL ),
907                                   aHeaders, xEnv ) );
908         }
909         catch ( DAVException & e )
910         {
911             errorCount++;
912             bRetry = handleException( e, errorCount );
913             if ( !bRetry )
914                 throw;
915         }
916     }
917     while ( bRetry );
918 }
919 
920 #if 0 // currently not used, but please don't remove code
921 //=========================================================================
922 // refresh existing lock.
923 sal_Int64 DAVResourceAccess::LOCK(
924     sal_Int64 nTimeout,
925     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
926   throw ( DAVException )
927 {
928     initialize();
929 
930     sal_Int64 nNewTimeout = 0;
931     int errorCount = 0;
932     bool bRetry;
933     do
934     {
935         bRetry = false;
936         try
937         {
938             DAVRequestHeaders aHeaders;
939             getUserRequestHeaders( xEnv,
940                                    getRequestURI(),
941                                    rtl::OUString::createFromAscii( "LOCK" ),
942                                    aHeaders );
943 
944             nNewTimeout = m_xSession->LOCK( getRequestURI(),
945                                             nTimeout,
946                                             DAVRequestEnvironment(
947                                                 getRequestURI(),
948                                                 new DAVAuthListener_Impl(
949                                                     xEnv, m_aURL ),
950                                             aHeaders, xEnv ) );
951         }
952         catch ( DAVException & e )
953         {
954             errorCount++;
955             bRetry = handleException( e, errorCount );
956             if ( !bRetry )
957                 throw;
958         }
959     }
960     while ( bRetry );
961 
962     return nNewTimeout;
963 }
964 #endif
965 
966 //=========================================================================
967 void DAVResourceAccess::UNLOCK(
968     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
969   throw ( DAVException )
970 {
971     initialize();
972 
973     int errorCount = 0;
974     bool bRetry;
975     do
976     {
977         bRetry = false;
978         try
979         {
980             DAVRequestHeaders aHeaders;
981             getUserRequestHeaders( xEnv,
982                                    getRequestURI(),
983                                    rtl::OUString::createFromAscii( "UNLOCK" ),
984                                    aHeaders );
985 
986             m_xSession->UNLOCK( getRequestURI(),
987                                 DAVRequestEnvironment(
988                                     getRequestURI(),
989                                     new DAVAuthListener_Impl( xEnv, m_aURL ),
990                                     aHeaders, xEnv ) );
991         }
992         catch ( DAVException & e )
993         {
994             errorCount++;
995             bRetry = handleException( e, errorCount );
996             if ( !bRetry )
997                 throw;
998         }
999     }
1000     while ( bRetry );
1001 }
1002 
1003 //=========================================================================
1004 void DAVResourceAccess::setURL( const rtl::OUString & rNewURL )
1005     throw( DAVException )
1006 {
1007     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1008     m_aURL  = rNewURL;
1009     m_aPath = rtl::OUString(); // Next initialize() will create new session.
1010 }
1011 
1012 //=========================================================================
1013 // init dav session and path
1014 void DAVResourceAccess::initialize()
1015     throw ( DAVException )
1016 {
1017     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1018     if ( m_aPath.getLength() == 0 )
1019     {
1020         SerfUri aURI( m_aURL );
1021         rtl::OUString aPath( aURI.GetPath() );
1022 
1023         /* #134089# - Check URI */
1024         if ( !aPath.getLength() )
1025             throw DAVException( DAVException::DAV_INVALID_ARG );
1026 
1027         /* #134089# - Check URI */
1028         if ( !aURI.GetHost().getLength() )
1029             throw DAVException( DAVException::DAV_INVALID_ARG );
1030 
1031         if ( !m_xSession.is() || !m_xSession->CanUse( m_aURL ) )
1032         {
1033             m_xSession.clear();
1034 
1035             // create new webdav session
1036             m_xSession
1037                 = m_xSessionFactory->createDAVSession( m_aURL, m_xSMgr );
1038 
1039             if ( !m_xSession.is() )
1040                 return;
1041         }
1042 
1043         // Own URI is needed for redirect cycle detection.
1044         m_aRedirectURIs.push_back( aURI );
1045 
1046         // Success.
1047         m_aPath = aPath;
1048 
1049         // Not only the path has to be encoded
1050         m_aURL = aURI.GetURI();
1051     }
1052 }
1053 
1054 //=========================================================================
1055 const rtl::OUString & DAVResourceAccess::getRequestURI() const
1056 {
1057     OSL_ENSURE( m_xSession.is(),
1058                 "DAVResourceAccess::getRequestURI - Not initialized!" );
1059 
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;
1063 
1064     return m_aPath;
1065 }
1066 
1067 //=========================================================================
1068 // static
1069 void DAVResourceAccess::getUserRequestHeaders(
1070     const uno::Reference< ucb::XCommandEnvironment > & xEnv,
1071     const rtl::OUString & rURI,
1072     const rtl::OUString & rMethod,
1073     DAVRequestHeaders & rRequestHeaders )
1074 {
1075     if ( xEnv.is() )
1076     {
1077         uno::Reference< ucb::XWebDAVCommandEnvironment > xDAVEnv(
1078             xEnv, uno::UNO_QUERY );
1079 
1080         if ( xDAVEnv.is() )
1081         {
1082             uno::Sequence< beans::NamedValue > aRequestHeaders
1083                 = xDAVEnv->getUserRequestHeaders( rURI, rMethod );
1084 
1085             for ( sal_Int32 n = 0; n < aRequestHeaders.getLength(); ++n )
1086             {
1087                 rtl::OUString aValue;
1088                 sal_Bool isString = aRequestHeaders[ n ].Value >>= aValue;
1089 
1090                 if ( !isString )
1091                 {
1092                     OSL_ENSURE( isString,
1093                         "DAVResourceAccess::getUserRequestHeaders :"
1094                         "Value is not a string! Ignoring..." );
1095                 }
1096 
1097                 rRequestHeaders.push_back(
1098                     DAVRequestHeader( aRequestHeaders[ n ].Name, aValue ) );
1099             }
1100         }
1101     }
1102 }
1103 
1104 //=========================================================================
1105 sal_Bool DAVResourceAccess::detectRedirectCycle(
1106                                 const rtl::OUString& rRedirectURL )
1107     throw ( DAVException )
1108 {
1109     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1110 
1111     SerfUri aUri( rRedirectURL );
1112 
1113     std::vector< SerfUri >::const_iterator it  = m_aRedirectURIs.begin();
1114     std::vector< SerfUri >::const_iterator end = m_aRedirectURIs.end();
1115 
1116     while ( it != end )
1117     {
1118         if ( aUri == (*it) )
1119             return sal_True;
1120 
1121         it++;
1122     }
1123 
1124     return sal_False;
1125 }
1126 
1127 //=========================================================================
1128 void DAVResourceAccess::resetUri()
1129 {
1130     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1131     if ( m_aRedirectURIs.size() > 0 )
1132     {
1133         std::vector< SerfUri >::const_iterator it  = m_aRedirectURIs.begin();
1134 
1135         SerfUri aUri( (*it) );
1136         m_aRedirectURIs.clear();
1137         setURL ( aUri.GetURI() );
1138         initialize();
1139     }
1140 }
1141 
1142 //=========================================================================
1143 sal_Bool DAVResourceAccess::handleException( DAVException & e, int errorCount )
1144     throw ( DAVException )
1145 {
1146     switch ( e.getError() )
1147     {
1148     case DAVException::DAV_HTTP_REDIRECT:
1149         if ( !detectRedirectCycle( e.getData() ) )
1150         {
1151             // set new URL and path.
1152             setURL( e.getData() );
1153             initialize();
1154             return sal_True;
1155         }
1156         return sal_False;
1157     // --> tkr #67048# copy & paste images doesn't display.
1158     // if we have a bad connection try again. Up to three times.
1159     case DAVException::DAV_HTTP_ERROR:
1160         // retry up to three times, if not a client-side error.
1161         if ( ( e.getStatus() < 400 || e.getStatus() >= 500 ) &&
1162              errorCount < 3 )
1163         {
1164             return sal_True;
1165         }
1166         return sal_False;
1167     // <--
1168     // --> tkr: if connection has said retry then retry!
1169     case DAVException::DAV_HTTP_RETRY:
1170         return sal_True;
1171     // <--
1172     default:
1173         return sal_False; // Abort
1174     }
1175 }
1176