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