LibreOffice Module ucb (master)  1
neon/DAVResourceAccess.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * Copyright 2000, 2010 Oracle and/or its affiliates.
7  *
8  * OpenOffice.org - a multi-platform office productivity suite
9  *
10  * This file is part of OpenOffice.org.
11  *
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.
15  *
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).
21  *
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.
26  *
27  ************************************************************************/
28 
29 
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>
34 
37 
38 #include "DAVAuthListenerImpl.hxx"
39 #include "DAVResourceAccess.hxx"
40 
41 using namespace webdav_ucp;
42 using namespace com::sun::star;
43 
44 
45 // DAVAuthListener_Impl Implementation.
46 
47 static constexpr sal_uInt32 g_nRedirectLimit = 5;
48 
49 // virtual
51  const OUString & inRealm,
52  const OUString & inHostName,
53  OUString & inoutUserName,
54  OUString & outPassWord,
55  bool bCanUseSystemCredentials )
56 {
57  if ( m_xEnv.is() )
58  {
59  uno::Reference< task::XInteractionHandler > xIH
60  = m_xEnv->getInteractionHandler();
61 
62  if ( xIH.is() )
63  {
64  // #102871# - Supply username and password from previous try.
65  // Password container service depends on this!
66  if ( inoutUserName.isEmpty() )
67  inoutUserName = m_aPrevUsername;
68 
69  if ( outPassWord.isEmpty() )
70  outPassWord = m_aPrevPassword;
71 
74  m_aURL, inHostName, inRealm, inoutUserName,
75  outPassWord, bCanUseSystemCredentials );
76  xIH->handle( xRequest.get() );
77 
79  = xRequest->getSelection();
80 
81  if ( xSelection.is() )
82  {
83  // Handler handled the request.
84  uno::Reference< task::XInteractionAbort > xAbort(
85  xSelection.get(), uno::UNO_QUERY );
86  if ( !xAbort.is() )
87  {
88  const rtl::Reference<
90  = xRequest->getAuthenticationSupplier();
91 
92  bool bUseSystemCredentials = false;
93 
94  if ( bCanUseSystemCredentials )
95  bUseSystemCredentials
96  = xSupp->getUseSystemCredentials();
97 
98  if ( bUseSystemCredentials )
99  {
100  // This is the (strange) way to tell neon to use
101  // system credentials.
102  inoutUserName.clear();
103  outPassWord.clear();
104  }
105  else
106  {
107  inoutUserName = xSupp->getUserName();
108  outPassWord = xSupp->getPassword();
109  }
110 
111  // #102871# - Remember username and password.
112  m_aPrevUsername = inoutUserName;
113  m_aPrevPassword = outPassWord;
114 
115  // go on.
116  return 0;
117  }
118  }
119  }
120  }
121  // Abort.
122  return -1;
123 }
124 
125 
126 // DAVResourceAccess Implementation.
127 
128 
130  const uno::Reference< uno::XComponentContext > & rxContext,
131  rtl::Reference< DAVSessionFactory > const & rSessionFactory,
132  const OUString & rURL )
133 : m_aURL( rURL ),
134  m_xSessionFactory( rSessionFactory ),
135  m_xContext( rxContext )
136 {
137 }
138 
139 
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 )
148 {
149 }
150 
151 
153  const DAVResourceAccess & rOther )
154 {
155  m_aURL = rOther.m_aURL;
156  m_aPath = rOther.m_aPath;
157  m_aFlags = rOther.m_aFlags;
158  m_xSession = rOther.m_xSession;
160  m_xContext = rOther.m_xContext;
162 
163  return *this;
164 }
165 
167  DAVOptions & rOptions,
168  const css::uno::Reference<
169  css::ucb::XCommandEnvironment > & xEnv )
170 {
171  initialize();
172 
173  int errorCount = 0;
174  bool bRetry;
175  do
176  {
177  bRetry = false;
178  try
179  {
180  DAVRequestHeaders aHeaders;
181 
182  getUserRequestHeaders( xEnv,
183  getRequestURI(),
184  css::ucb::WebDAVHTTPMethod_OPTIONS,
185  aHeaders );
186 
187  m_xSession->OPTIONS( getRequestURI(),
188  rOptions,
190  getRequestURI(),
191  new DAVAuthListener_Impl( xEnv, m_aURL ),
192  aHeaders, xEnv ) );
193  }
194  catch ( const DAVException & e )
195  {
196  errorCount++;
197  bRetry = handleException( e, errorCount );
198  if ( !bRetry )
199  throw;
200  }
201  }
202  while ( bRetry );
203 }
204 
206  const Depth nDepth,
207  const std::vector< OUString > & rPropertyNames,
208  std::vector< DAVResource > & rResources,
209  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
210 {
211  initialize();
212 
213  int errorCount = 0;
214  bool bRetry;
215  do
216  {
217  bRetry = false;
218  try
219  {
220  DAVRequestHeaders aHeaders;
221 
222  getUserRequestHeaders( xEnv,
223  getRequestURI(),
224  ucb::WebDAVHTTPMethod_PROPFIND,
225  aHeaders );
226 
227  m_xSession->PROPFIND( getRequestURI(),
228  nDepth,
229  rPropertyNames,
230  rResources,
232  getRequestURI(),
233  new DAVAuthListener_Impl( xEnv, m_aURL ),
234  aHeaders, xEnv ) );
235  }
236  catch ( const DAVException & e )
237  {
238  errorCount++;
239  bRetry = handleException( e, errorCount );
240  if ( !bRetry )
241  throw;
242  }
243  }
244  while ( bRetry );
245 }
246 
247 
249  const Depth nDepth,
250  std::vector< DAVResourceInfo > & rResInfo,
251  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
252 {
253  initialize();
254 
255  int errorCount = 0;
256  bool bRetry;
257  do
258  {
259  bRetry = false;
260  try
261  {
262  DAVRequestHeaders aHeaders;
263  getUserRequestHeaders( xEnv,
264  getRequestURI(),
265  ucb::WebDAVHTTPMethod_PROPFIND,
266  aHeaders );
267 
268  m_xSession->PROPFIND( getRequestURI(),
269  nDepth,
270  rResInfo,
272  getRequestURI(),
273  new DAVAuthListener_Impl( xEnv, m_aURL ),
274  aHeaders, xEnv ) ) ;
275  }
276  catch ( const DAVException & e )
277  {
278  errorCount++;
279  bRetry = handleException( e, errorCount );
280  if ( !bRetry )
281  throw;
282  }
283  }
284  while ( bRetry );
285 }
286 
287 
289  const std::vector< ProppatchValue >& rValues,
290  const uno::Reference< ucb::XCommandEnvironment >& xEnv )
291 {
292  initialize();
293 
294  int errorCount = 0;
295  bool bRetry;
296  do
297  {
298  bRetry = false;
299  try
300  {
301  DAVRequestHeaders aHeaders;
302  getUserRequestHeaders( xEnv,
303  getRequestURI(),
304  ucb::WebDAVHTTPMethod_PROPPATCH,
305  aHeaders );
306 
307  m_xSession->PROPPATCH( getRequestURI(),
308  rValues,
310  getRequestURI(),
311  new DAVAuthListener_Impl( xEnv, m_aURL ),
312  aHeaders, xEnv ) );
313  }
314  catch ( const DAVException & e )
315  {
316  errorCount++;
317  bRetry = handleException( e, errorCount );
318  if ( !bRetry )
319  throw;
320  }
321  }
322  while ( bRetry );
323 }
324 
325 
327  const std::vector< OUString > & rHeaderNames,
328  DAVResource & rResource,
329  const uno::Reference< ucb::XCommandEnvironment >& xEnv )
330 {
331  initialize();
332 
333  int errorCount = 0;
334  bool bRetry;
335  do
336  {
337  bRetry = false;
338  try
339  {
340  DAVRequestHeaders aHeaders;
341  getUserRequestHeaders( xEnv,
342  getRequestURI(),
343  ucb::WebDAVHTTPMethod_HEAD,
344  aHeaders );
345 
346  m_xSession->HEAD( getRequestURI(),
347  rHeaderNames,
348  rResource,
350  getRequestURI(),
351  new DAVAuthListener_Impl( xEnv, m_aURL ),
352  aHeaders, xEnv ) );
353  }
354  catch ( const DAVException & e )
355  {
356  errorCount++;
357  bRetry = handleException( e, errorCount );
358  if ( !bRetry )
359  throw;
360  }
361  }
362  while ( bRetry );
363 }
364 
365 
366 uno::Reference< io::XInputStream > DAVResourceAccess::GET(
367  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
368 {
369  initialize();
370 
371  uno::Reference< io::XInputStream > xStream;
372  int errorCount = 0;
373  bool bRetry;
374  do
375  {
376  bRetry = false;
377  try
378  {
379  DAVRequestHeaders aHeaders;
380  getUserRequestHeaders( xEnv,
381  getRequestURI(),
382  ucb::WebDAVHTTPMethod_GET,
383  aHeaders );
384 
385  xStream = m_xSession->GET( getRequestURI(),
387  getRequestURI(),
389  xEnv, m_aURL ),
390  aHeaders, xEnv ) );
391  }
392  catch ( const DAVException & e )
393  {
394  errorCount++;
395  bRetry = handleException( e, errorCount );
396  if ( !bRetry )
397  throw;
398  }
399  }
400  while ( bRetry );
401 
402  return xStream;
403 }
404 
405 
407  uno::Reference< io::XOutputStream > & rStream,
408  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
409 {
410  initialize();
411 
412  int errorCount = 0;
413  bool bRetry;
414  do
415  {
416  bRetry = false;
417  try
418  {
419  DAVRequestHeaders aHeaders;
420  getUserRequestHeaders( xEnv,
421  getRequestURI(),
422  ucb::WebDAVHTTPMethod_GET,
423  aHeaders );
424 
425  m_xSession->GET( getRequestURI(),
426  rStream,
428  getRequestURI(),
429  new DAVAuthListener_Impl( xEnv, m_aURL ),
430  aHeaders, xEnv ) );
431  }
432  catch ( const DAVException & e )
433  {
434  errorCount++;
435  bRetry = handleException( e, errorCount );
436  if ( !bRetry )
437  throw;
438  }
439  }
440  while ( bRetry );
441 }
442 
443 uno::Reference< io::XInputStream > DAVResourceAccess::GET(
444  const std::vector< OUString > & rHeaderNames,
445  DAVResource & rResource,
446  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
447 {
448  initialize();
449 
450  uno::Reference< io::XInputStream > xStream;
451  int errorCount = 0;
452  bool bRetry;
453  do
454  {
455  bRetry = false;
456  try
457  {
458  DAVRequestHeaders aHeaders;
459  getUserRequestHeaders( xEnv,
460  getRequestURI(),
461  ucb::WebDAVHTTPMethod_GET,
462  aHeaders );
463 
464  xStream = m_xSession->GET( getRequestURI(),
465  rHeaderNames,
466  rResource,
468  getRequestURI(),
470  xEnv, m_aURL ),
471  aHeaders, xEnv ) );
472  }
473  catch ( const DAVException & e )
474  {
475  errorCount++;
476  bRetry = handleException( e, errorCount );
477  if ( !bRetry )
478  throw;
479  }
480  }
481  while ( bRetry );
482 
483  return xStream;
484 }
485 
486 // used as HEAD substitute when HEAD is not implemented on server
488  DAVRequestHeaders &rRequestHeaders,
489  const std::vector< OUString > & rHeaderNames,
490  DAVResource & rResource,
491  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
492 {
493  initialize();
494 
495  int errorCount = 0;
496  bool bRetry;
497  do
498  {
499  bRetry = false;
500  try
501  {
502  getUserRequestHeaders( xEnv,
503  getRequestURI(),
504  ucb::WebDAVHTTPMethod_GET,
505  rRequestHeaders );
506 
507  m_xSession->GET0( getRequestURI(),
508  rHeaderNames,
509  rResource,
511  getRequestURI(),
513  xEnv, m_aURL ),
514  rRequestHeaders, xEnv ) );
515  }
516  catch ( const DAVException & e )
517  {
518  errorCount++;
519  bRetry = handleException( e, errorCount );
520  if ( !bRetry )
521  throw;
522  }
523  }
524  while ( bRetry );
525 }
526 
527 
529  uno::Reference< io::XOutputStream > & rStream,
530  const std::vector< OUString > & rHeaderNames,
531  DAVResource & rResource,
532  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
533 {
534  initialize();
535 
536  bool bRetry;
537  int errorCount = 0;
538  do
539  {
540  bRetry = false;
541  try
542  {
543  DAVRequestHeaders aHeaders;
544  getUserRequestHeaders( xEnv,
545  getRequestURI(),
546  ucb::WebDAVHTTPMethod_GET,
547  aHeaders );
548 
549  m_xSession->GET( getRequestURI(),
550  rStream,
551  rHeaderNames,
552  rResource,
554  getRequestURI(),
555  new DAVAuthListener_Impl( xEnv, m_aURL ),
556  aHeaders, xEnv ) );
557  }
558  catch ( const DAVException & e )
559  {
560  errorCount++;
561  bRetry = handleException( e, errorCount );
562  if ( !bRetry )
563  throw;
564  }
565  }
566  while ( bRetry );
567 }
568 
569 
571 {
572  initialize();
573  m_xSession->abort();
574 }
575 
576 
577 namespace {
578 
580  void resetInputStream( const uno::Reference< io::XInputStream > & rStream )
581  {
582  try
583  {
584  uno::Reference< io::XSeekable > xSeekable(
585  rStream, uno::UNO_QUERY );
586  if ( xSeekable.is() )
587  {
588  xSeekable->seek( 0 );
589  return;
590  }
591  }
592  catch ( lang::IllegalArgumentException const & )
593  {
594  }
595  catch ( io::IOException const & )
596  {
597  }
598 
600  }
601 
602 } // namespace
603 
604 
606  const uno::Reference< io::XInputStream > & rStream,
607  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
608 {
609  initialize();
610 
611  // Make stream seekable, if it not. Needed, if request must be retried.
612  uno::Reference< io::XInputStream > xSeekableStream
614  rStream, m_xContext );
615 
616  int errorCount = 0;
617  bool bRetry = false;
618  do
619  {
620  if ( bRetry )
621  resetInputStream( xSeekableStream );
622 
623  bRetry = false;
624  try
625  {
626  DAVRequestHeaders aHeaders;
627  getUserRequestHeaders( xEnv,
628  getRequestURI(),
629  ucb::WebDAVHTTPMethod_PUT,
630  aHeaders );
631 
632  m_xSession->PUT( getRequestURI(),
633  xSeekableStream,
635  getRequestURI(),
636  new DAVAuthListener_Impl( xEnv, m_aURL ),
637  aHeaders, xEnv ) );
638  }
639  catch ( const DAVException & e )
640  {
641  errorCount++;
642  bRetry = handleException( e, errorCount );
643  if ( !bRetry )
644  throw;
645  }
646  }
647  while ( bRetry );
648 }
649 
650 
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 )
656 {
657  initialize();
658 
659  // Make stream seekable, if it not. Needed, if request must be retried.
660  uno::Reference< io::XInputStream > xSeekableStream
662  rInputStream, m_xContext );
663 
664  uno::Reference< io::XInputStream > xStream;
665  int errorCount = 0;
666  bool bRetry = false;
667  do
668  {
669  if ( bRetry )
670  {
671  resetInputStream( xSeekableStream );
672  bRetry = false;
673  }
674 
675  try
676  {
677  DAVRequestHeaders aHeaders;
678  getUserRequestHeaders( xEnv,
679  getRequestURI(),
680  ucb::WebDAVHTTPMethod_POST,
681  aHeaders );
682 
683  xStream = m_xSession->POST( getRequestURI(),
684  rContentType,
685  rReferer,
686  xSeekableStream,
688  getRequestURI(),
690  xEnv, m_aURL ),
691  aHeaders, xEnv ) );
692  }
693  catch ( const DAVException & e )
694  {
695  errorCount++;
696  bRetry = handleException( e, errorCount );
697  if ( !bRetry )
698  throw;
699 
701  {
702  // #i74980# - Upon POST redirect, do a GET.
703  return GET( xEnv );
704  }
705  }
706  }
707  while ( bRetry );
708 
709  return xStream;
710 }
711 
712 
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 )
719 {
720  initialize();
721 
722  // Make stream seekable, if it not. Needed, if request must be retried.
723  uno::Reference< io::XInputStream > xSeekableStream
725  rInputStream, m_xContext );
726 
727  int errorCount = 0;
728  bool bRetry = false;
729  do
730  {
731  if ( bRetry )
732  {
733  resetInputStream( xSeekableStream );
734  bRetry = false;
735  }
736 
737  try
738  {
739  DAVRequestHeaders aHeaders;
740  getUserRequestHeaders( xEnv,
741  getRequestURI(),
742  ucb::WebDAVHTTPMethod_POST,
743  aHeaders );
744 
745  m_xSession->POST( getRequestURI(),
746  rContentType,
747  rReferer,
748  xSeekableStream,
749  rOutputStream,
751  getRequestURI(),
752  new DAVAuthListener_Impl( xEnv, m_aURL ),
753  aHeaders, xEnv ) );
754  }
755  catch ( const DAVException & e )
756  {
757  errorCount++;
758  bRetry = handleException( e, errorCount );
759  if ( !bRetry )
760  throw;
761 
763  {
764  // #i74980# - Upon POST redirect, do a GET.
765  GET( rOutputStream, xEnv );
766  return;
767  }
768  }
769  }
770  while ( bRetry );
771 }
772 
773 
775  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
776 {
777  initialize();
778 
779  int errorCount = 0;
780  bool bRetry;
781  do
782  {
783  bRetry = false;
784  try
785  {
786  DAVRequestHeaders aHeaders;
787  getUserRequestHeaders( xEnv,
788  getRequestURI(),
789  ucb::WebDAVHTTPMethod_MKCOL,
790  aHeaders );
791 
792  m_xSession->MKCOL( getRequestURI(),
794  getRequestURI(),
795  new DAVAuthListener_Impl( xEnv, m_aURL ),
796  aHeaders, xEnv ) );
797  }
798  catch ( const DAVException & e )
799  {
800  errorCount++;
801  bRetry = handleException( e, errorCount );
802  if ( !bRetry )
803  throw;
804  }
805  }
806  while ( bRetry );
807 }
808 
809 
811  const OUString & rSourcePath,
812  const OUString & rDestinationURI,
813  bool bOverwrite,
814  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
815 {
816  initialize();
817 
818  int errorCount = 0;
819  bool bRetry;
820  do
821  {
822  bRetry = false;
823  try
824  {
825  DAVRequestHeaders aHeaders;
826  getUserRequestHeaders( xEnv,
827  getRequestURI(),
828  ucb::WebDAVHTTPMethod_COPY,
829  aHeaders );
830 
831  m_xSession->COPY( rSourcePath,
832  rDestinationURI,
834  getRequestURI(),
835  new DAVAuthListener_Impl( xEnv, m_aURL ),
836  aHeaders, xEnv ),
837  bOverwrite );
838  }
839  catch ( const DAVException & e )
840  {
841  errorCount++;
842  bRetry = handleException( e, errorCount );
843  if ( !bRetry )
844  throw;
845  }
846  }
847  while ( bRetry );
848 }
849 
850 
852  const OUString & rSourcePath,
853  const OUString & rDestinationURI,
854  bool bOverwrite,
855  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
856 {
857  initialize();
858 
859  int errorCount = 0;
860  bool bRetry;
861  do
862  {
863  bRetry = false;
864  try
865  {
866  DAVRequestHeaders aHeaders;
867  getUserRequestHeaders( xEnv,
868  getRequestURI(),
869  ucb::WebDAVHTTPMethod_MOVE,
870  aHeaders );
871 
872  m_xSession->MOVE( rSourcePath,
873  rDestinationURI,
875  getRequestURI(),
876  new DAVAuthListener_Impl( xEnv, m_aURL ),
877  aHeaders, xEnv ),
878  bOverwrite );
879  }
880  catch ( const DAVException & e )
881  {
882  errorCount++;
883  bRetry = handleException( e, errorCount );
884  if ( !bRetry )
885  throw;
886  }
887  }
888  while ( bRetry );
889 }
890 
891 
893  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
894 {
895  initialize();
896 
897  int errorCount = 0;
898  bool bRetry;
899  do
900  {
901  bRetry = false;
902  try
903  {
904  DAVRequestHeaders aHeaders;
905  getUserRequestHeaders( xEnv,
906  getRequestURI(),
907  ucb::WebDAVHTTPMethod_DELETE,
908  aHeaders );
909 
910  m_xSession->DESTROY( getRequestURI(),
912  getRequestURI(),
913  new DAVAuthListener_Impl( xEnv, m_aURL ),
914  aHeaders, xEnv ) );
915  }
916  catch ( const DAVException & e )
917  {
918  errorCount++;
919  bRetry = handleException( e, errorCount );
920  if ( !bRetry )
921  throw;
922  }
923  }
924  while ( bRetry );
925 }
926 
927 
928 // set new lock.
930  ucb::Lock & inLock,
931  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
932 {
933  initialize();
934 
935  int errorCount = 0;
936  bool bRetry;
937  do
938  {
939  bRetry = false;
940  try
941  {
942  DAVRequestHeaders aHeaders;
943  getUserRequestHeaders( xEnv,
944  getRequestURI(),
945  ucb::WebDAVHTTPMethod_LOCK,
946  aHeaders );
947 
948  m_xSession->LOCK( getRequestURI(),
949  inLock,
951  getRequestURI(),
952  new DAVAuthListener_Impl( xEnv, m_aURL ),
953  aHeaders, xEnv ) );
954  }
955  catch ( const DAVException & e )
956  {
957  errorCount++;
958  bRetry = handleException( e, errorCount );
959  if ( !bRetry )
960  throw;
961  }
962  }
963  while ( bRetry );
964 }
965 
967  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
968 {
969  initialize();
970 
971  int errorCount = 0;
972  bool bRetry;
973  do
974  {
975  bRetry = false;
976  try
977  {
978  DAVRequestHeaders aHeaders;
979  getUserRequestHeaders( xEnv,
980  getRequestURI(),
981  ucb::WebDAVHTTPMethod_UNLOCK,
982  aHeaders );
983 
984  m_xSession->UNLOCK( getRequestURI(),
986  getRequestURI(),
987  new DAVAuthListener_Impl( xEnv, m_aURL ),
988  aHeaders, xEnv ) );
989  }
990  catch ( const DAVException & e )
991  {
992  errorCount++;
993  bRetry = handleException( e, errorCount );
994  if ( !bRetry )
995  throw;
996  }
997  }
998  while ( bRetry );
999 }
1000 
1001 
1002 void DAVResourceAccess::setFlags( const uno::Sequence< beans::NamedValue >& rFlags )
1003 {
1004  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1005  m_aFlags = rFlags;
1006 }
1007 
1008 
1009 void DAVResourceAccess::setURL( const OUString & rNewURL )
1010 {
1011  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1012  m_aURL = rNewURL;
1013  m_aPath.clear(); // Next initialize() will create new session.
1014 }
1015 
1016 
1017 // init dav session and path
1019 {
1020  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1021  if ( m_aPath.isEmpty() )
1022  {
1023  NeonUri aURI( m_aURL );
1024  const OUString& aPath( aURI.GetPath() );
1025 
1026  /* #134089# - Check URI */
1027  if ( aPath.isEmpty() )
1029 
1030  /* #134089# - Check URI */
1031  if ( aURI.GetHost().isEmpty() )
1033 
1034  if ( !m_xSession.is() || !m_xSession->CanUse( m_aURL, m_aFlags ) )
1035  {
1036  m_xSession.clear();
1037 
1038  // create new webdav session
1039  m_xSession
1040  = m_xSessionFactory->createDAVSession( m_aURL, m_aFlags, m_xContext );
1041 
1042  if ( !m_xSession.is() )
1043  return;
1044  }
1045 
1046  // Own URI is needed to redirect cycle detection.
1047  m_aRedirectURIs.push_back( aURI );
1048 
1049  // Success.
1050  m_aPath = aPath;
1051 
1052  // Not only the path has to be encoded
1053  m_aURL = aURI.GetURI();
1054  }
1055 }
1056 
1057 
1058 const OUString & DAVResourceAccess::getRequestURI() const
1059 {
1060  assert( m_xSession.is() && "DAVResourceAccess::getRequestURI - Not initialized!" );
1061 
1062  // In case a proxy is used we have to use the absolute URI for a request.
1063  if ( m_xSession->UsesProxy() )
1064  return m_aURL;
1065 
1066  return m_aPath;
1067 }
1068 
1069 
1070 // static
1072  const uno::Reference< ucb::XCommandEnvironment > & xEnv,
1073  const OUString & rURI,
1074  ucb::WebDAVHTTPMethod eMethod,
1075  DAVRequestHeaders & rRequestHeaders )
1076 {
1077  if ( xEnv.is() )
1078  {
1079  uno::Reference< ucb::XWebDAVCommandEnvironment > xDAVEnv(
1080  xEnv, uno::UNO_QUERY );
1081 
1082  if ( xDAVEnv.is() )
1083  {
1084  const uno::Sequence< beans::StringPair > aRequestHeaders
1085  = xDAVEnv->getUserRequestHeaders( rURI, eMethod );
1086 
1087  for ( const auto& rRequestHeader : aRequestHeaders )
1088  {
1089  rRequestHeaders.emplace_back(
1090  rRequestHeader.First,
1091  rRequestHeader.Second );
1092  }
1093  }
1094  }
1095 
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" ); }) )
1102  {
1103  return;
1104  }
1105  rRequestHeaders.emplace_back( "User-Agent", "LibreOffice" );
1106 }
1107 
1108 // This function member implements the control on cyclical redirections
1110  const OUString& rRedirectURL )
1111 {
1112  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1113 
1114  NeonUri aUri( rRedirectURL );
1115 
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() )
1122  return true;
1123 
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; });
1129 }
1130 
1131 
1133 {
1134  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1135  if ( !m_aRedirectURIs.empty() )
1136  {
1137  std::vector< NeonUri >::const_iterator it = m_aRedirectURIs.begin();
1138 
1139  NeonUri aUri( *it );
1140  m_aRedirectURIs.clear();
1141  setURL ( aUri.GetURI() );
1142  initialize();
1143  }
1144 }
1145 
1146 
1147 bool DAVResourceAccess::handleException( const DAVException & e, int errorCount )
1148 {
1149  switch ( e.getError() )
1150  {
1152  if ( !detectRedirectCycle( e.getData() ) )
1153  {
1154  // set new URL and path.
1155  setURL( e.getData() );
1156  initialize();
1157  return true;
1158  }
1159  return false;
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.
1164  // retry up to three times, if not a client-side error (4xx error codes)
1165  if ( e.getStatus() < SC_BAD_REQUEST && errorCount < 3 )
1166  return true;
1167  // check the server side errors
1168  switch( e.getStatus() )
1169  {
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
1175  {
1176  return errorCount < 3;
1177  }
1178  break;
1179  // all the other HTTP server response status codes are NOT retry
1180  default:
1181  return false;
1182  }
1183  break;
1184  // if connection has said retry then retry!
1186  return true;
1187  default:
1188  return false; // Abort
1189  }
1190 }
1191 
1192 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const OUString & getRequestURI() const
void UNLOCK(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const sal_uInt16 SC_BAD_REQUEST
void setFlags(const css::uno::Sequence< css::beans::NamedValue > &rFlags)
rtl::Reference< DAVSessionFactory > m_xSessionFactory
DAVResourceAccess(const css::uno::Reference< css::uno::XComponentContext > &rxContext, rtl::Reference< DAVSessionFactory > const &rSessionFactory, const OUString &rURL)
const sal_uInt16 SC_GATEWAY_TIMEOUT
std::vector< DAVRequestHeader > DAVRequestHeaders
static constexpr sal_uInt32 g_nRedirectLimit
void MKCOL(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void GET0(DAVRequestHeaders &rRequestHeaders, const std::vector< OUString > &rHeaderNames, DAVResource &rResource, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const ExceptionCode & getError() const
rtl::Reference< DAVSession > m_xSession
void PROPPATCH(const std::vector< ProppatchValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void PROPFIND(const Depth nDepth, const std::vector< OUString > &rPropertyNames, std::vector< DAVResource > &rResources, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const OUString & GetPath() const
Definition: NeonUri.hxx:77
Reference< XInputStream > xStream
const sal_uInt16 SC_INSUFFICIENT_STORAGE
css::uno::Reference< css::uno::XComponentContext > m_xContext
const OUString & getData() const
void LOCK(css::ucb::Lock &inLock, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual int authenticate(const OUString &inRealm, const OUString &inHostName, OUString &inoutUserName, OUString &outPassWord, bool bCanUseSystemCredentials) override
const sal_uInt16 SC_SERVICE_UNAVAILABLE
sal_uInt16 getStatus() const
void MOVE(const OUString &rSourcePath, const OUString &rDestinationURI, bool bOverwrite, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void COPY(const OUString &rSourcePath, const OUString &rDestinationURI, bool bOverwrite, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const sal_uInt16 SC_BAD_GATEWAY
const OUString & GetHost() const
Definition: NeonUri.hxx:73
std::pair< OUString, OUString > DAVRequestHeader
void PUT(const css::uno::Reference< css::io::XInputStream > &rStream, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
DAVResourceAccess & operator=(const DAVResourceAccess &rOther)
void DESTROY(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
static css::uno::Reference< css::io::XInputStream > CheckSeekableCanWrap(const css::uno::Reference< css::io::XInputStream > &xInStream, const css::uno::Reference< css::uno::XComponentContext > &rxContext)
static void getUserRequestHeaders(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, const OUString &rURI, css::ucb::WebDAVHTTPMethod eMethod, DAVRequestHeaders &rRequestHeaders)
css::uno::Sequence< css::beans::NamedValue > m_aFlags
void OPTIONS(DAVOptions &rOptions, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const OUString & GetURI() const
Definition: NeonUri.hxx:67
css::uno::Reference< css::io::XInputStream > POST(const OUString &rContentType, const OUString &rReferer, const css::uno::Reference< css::io::XInputStream > &rInputStream, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
std::vector< NeonUri > m_aRedirectURIs
void HEAD(const std::vector< OUString > &rHeaderNames, DAVResource &rResource, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void setURL(const OUString &rNewURL)
bool detectRedirectCycle(const OUString &rRedirectURL)
css::uno::Reference< css::io::XInputStream > GET(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
const uno::Reference< uno::XComponentContext > m_xContext
bool handleException(const DAVException &e, int errorCount)