LibreOffice Module ucb (master)  1
webdavdatasupplier.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <utility>
24 
25 #include <rtl/ustrbuf.hxx>
26 #include <com/sun/star/ucb/OpenMode.hpp>
29 #include "webdavdatasupplier.hxx"
30 #include "webdavcontent.hxx"
31 #include "DAVProperties.hxx"
32 #include "CurlUri.hxx"
33 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
34 #include <com/sun/star/ucb/ResultSetException.hpp>
35 #include <tools/diagnose_ex.h>
36 
37 using namespace com::sun::star;
38 using namespace http_dav_ucp;
39 
40 namespace http_dav_ucp
41 {
42 
43 namespace {
44 
45 auto DumpResources(std::vector<DAVResource> const& rResources) -> OUString
46 {
47  OUStringBuffer buf;
48  for (auto const& rResource : rResources)
49  {
50  buf.append("resource URL: <");
51  buf.append(rResource.uri);
52  try {
53  CurlUri const uri(rResource.uri);
54  buf.append("> parsed URL: <");
55  buf.append(DecodeURI(uri.GetRelativeReference()));
56  buf.append("> ");
57  } catch (...) {
58  // parsing uri could fail
59  buf.append("> parsing URL failed! ");
60  }
61  buf.append("properties: ");
62  for (auto const& it : rResource.properties)
63  {
64  buf.append("\"");
65  buf.append(it.Name);
66  buf.append("\" ");
67  }
68  buf.append("\n");
69  }
70  buf.stripEnd('\n'); // the last newline is superfluous, remove it
71  return buf.makeStringAndClear();
72 }
73 
74 }
75 
76 }
77 
78 
79 // DataSupplier Implementation.
80 
81 
82 DataSupplier::DataSupplier(
83  const uno::Reference< uno::XComponentContext >& rxContext,
84  const rtl::Reference< Content >& rContent,
85  sal_Int32 nOpenMode )
86  : m_xContent( rContent ), m_xContext( rxContext ), m_nOpenMode( nOpenMode ),
87  m_bCountFinal( false ), m_bThrowException( false )
88 {
89 }
90 
91 
92 // virtual
94 {}
95 
96 
97 // virtual
98 OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
99 {
100  osl::Guard< osl::Mutex > aGuard( m_aMutex );
101 
102  if (nIndex < m_Results.size())
103  {
104  OUString aId = m_Results[ nIndex ]->aId;
105  if ( aId.getLength() )
106  {
107  // Already cached.
108  return aId;
109  }
110  }
111 
112  if ( getResult( nIndex ) )
113  {
114  OUString aId = m_xContent->getResourceAccess().getURL();
115 
116  const ContentProperties& props(*(m_Results[ nIndex ]->pData));
117 
118  if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
119  aId += "/";
120 
121  aId += props.getEscapedTitle();
122 
123  if ( props.isTrailingSlash() )
124  aId += "/";
125 
126  m_Results[ nIndex ]->aId = aId;
127  return aId;
128  }
129  return OUString();
130 }
131 
132 
133 // virtual
134 uno::Reference< ucb::XContentIdentifier >
136 {
137  osl::Guard< osl::Mutex > aGuard( m_aMutex );
138 
139  if (nIndex < m_Results.size())
140  {
141  uno::Reference< ucb::XContentIdentifier > xId
142  = m_Results[ nIndex ]->xId;
143  if ( xId.is() )
144  {
145  // Already cached.
146  return xId;
147  }
148  }
149 
150  OUString aId = queryContentIdentifierString( nIndex );
151  if ( aId.getLength() )
152  {
153  uno::Reference< ucb::XContentIdentifier > xId
154  = new ::ucbhelper::ContentIdentifier( aId );
155  m_Results[ nIndex ]->xId = xId;
156  return xId;
157  }
158  return uno::Reference< ucb::XContentIdentifier >();
159 }
160 
161 
162 // virtual
163 uno::Reference< ucb::XContent >
164 DataSupplier::queryContent( sal_uInt32 nIndex )
165 {
166  osl::Guard< osl::Mutex > aGuard( m_aMutex );
167 
168  if (nIndex < m_Results.size())
169  {
170  uno::Reference< ucb::XContent > xContent
171  = m_Results[ nIndex ]->xContent;
172  if ( xContent.is() )
173  {
174  // Already cached.
175  return xContent;
176  }
177  }
178 
179  uno::Reference< ucb::XContentIdentifier > xId
180  = queryContentIdentifier( nIndex );
181  if ( xId.is() )
182  {
183  try
184  {
185  uno::Reference< ucb::XContent > xContent
186  = m_xContent->getProvider()->queryContent( xId );
187  m_Results[ nIndex ]->xContent = xContent;
188  return xContent;
189 
190  }
191  catch ( ucb::IllegalIdentifierException& )
192  {
193  }
194  }
195  return uno::Reference< ucb::XContent >();
196 }
197 
198 
199 // virtual
200 bool DataSupplier::getResult( sal_uInt32 nIndex )
201 {
202  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
203 
204  if (nIndex < m_Results.size())
205  {
206  // Result already present.
207  return true;
208  }
209 
210  // Obtain values...
211  if ( getData() )
212  {
213  if (nIndex < m_Results.size())
214  {
215  // Result already present.
216  return true;
217  }
218  }
219 
220  return false;
221 }
222 
223 
224 // virtual
226 {
227  // Obtain values...
228  getData();
229 
230  return m_Results.size();
231 }
232 
233 
234 // virtual
236 {
237  return m_Results.size();
238 }
239 
240 
241 // virtual
243 {
244  return m_bCountFinal;
245 }
246 
247 
248 // virtual
249 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues(
250  sal_uInt32 nIndex )
251 {
252  osl::Guard< osl::Mutex > aGuard( m_aMutex );
253 
254  if (nIndex < m_Results.size())
255  {
256  uno::Reference< sdbc::XRow > xRow = m_Results[ nIndex ]->xRow;
257  if ( xRow.is() )
258  {
259  // Already cached.
260  return xRow;
261  }
262  }
263 
264  if ( getResult( nIndex ) )
265  {
266  uno::Reference< sdbc::XRow > xRow
268  m_xContext,
269  getResultSet()->getProperties(),
270  *(m_Results[ nIndex ]->pData),
271  m_xContent->getProvider(),
272  queryContentIdentifierString( nIndex ) );
273  m_Results[ nIndex ]->xRow = xRow;
274  return xRow;
275  }
276 
277  return uno::Reference< sdbc::XRow >();
278 }
279 
280 
281 // virtual
282 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
283 {
284  osl::Guard< osl::Mutex > aGuard( m_aMutex );
285 
286  if (nIndex < m_Results.size())
287  m_Results[ nIndex ]->xRow.clear();
288 }
289 
290 
291 // virtual
293 {
294 }
295 
296 
297 // virtual
299 {
300  if ( m_bThrowException )
301  throw ucb::ResultSetException();
302 }
303 
305 {
306  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
307 
308  if ( !m_bCountFinal )
309  {
310  std::vector< OUString > propertyNames;
312  getResultSet()->getProperties(), propertyNames );
313 
314  // Append "resourcetype", if not already present. It's value is
315  // needed to get a valid ContentProperties::pIsFolder value, which
316  // is needed for OpenMode handling.
317 
318  bool isNoResourceType = std::none_of(propertyNames.begin(), propertyNames.end(),
319  [](const OUString& rPropName) { return rPropName.equals(DAVProperties::RESOURCETYPE); });
320 
321  if ( isNoResourceType )
322  propertyNames.push_back( DAVProperties::RESOURCETYPE );
323 
324  std::vector< DAVResource > resources;
325  try
326  {
327  // propfind depth 1, get property values for parent AND for each
328  // child
329  m_xContent->getResourceAccess()
330  .PROPFIND( DAVONE,
331  propertyNames,
332  resources,
334  SAL_INFO("ucb.ucp.webdav", "getData() - " << DumpResources(resources));
335  }
336  catch ( DAVException & )
337  {
338  TOOLS_WARN_EXCEPTION( "ucb.ucp.webdav", "PROPFIND : DAVException" );
339  m_bThrowException = true;
340  }
341 
342  if ( !m_bThrowException )
343  {
344  try
345  {
346  CurlUri const aURI(
347  m_xContent->getResourceAccess().getURL() );
348  OUString aPath = aURI.GetPath();
349 
350  if ( aPath.endsWith("/") )
351  aPath = aPath.copy( 0, aPath.getLength() - 1 );
352 
353  aPath = DecodeURI(aPath);
354  bool bFoundParent = false;
355 
356  for ( size_t n = 0; n < resources.size(); ++n )
357  {
358  const DAVResource & rRes = resources[ n ];
359 
360  // Filter parent, which is contained somewhere(!) in
361  // the vector.
362  if ( !bFoundParent )
363  {
364  try
365  {
366  CurlUri const aCurrURI( rRes.uri );
367  OUString aCurrPath = aCurrURI.GetPath();
368  if ( aCurrPath.endsWith("/") )
369  aCurrPath
370  = aCurrPath.copy(
371  0,
372  aCurrPath.getLength() - 1 );
373 
374  aCurrPath = DecodeURI(aCurrPath);
375  if ( aPath == aCurrPath )
376  {
377  bFoundParent = true;
378  continue;
379  }
380  }
381  catch ( DAVException const & )
382  {
383  // do nothing, ignore error. continue.
384  }
385  }
386 
387  std::unique_ptr<ContentProperties> pContentProperties
388  = std::make_unique<ContentProperties>( rRes );
389 
390  // Check resource against open mode.
391  switch ( m_nOpenMode )
392  {
393  case ucb::OpenMode::FOLDERS:
394  {
395  bool bFolder = false;
396 
397  const uno::Any & rValue
398  = pContentProperties->getValue( "IsFolder" );
399  rValue >>= bFolder;
400 
401  if ( !bFolder )
402  continue;
403 
404  break;
405  }
406 
407  case ucb::OpenMode::DOCUMENTS:
408  {
409  bool bDocument = false;
410 
411  const uno::Any & rValue
412  = pContentProperties->getValue( "IsDocument" );
413  rValue >>= bDocument;
414 
415  if ( !bDocument )
416  continue;
417 
418  break;
419  }
420 
421  case ucb::OpenMode::ALL:
422  default:
423  break;
424  }
425 
426  m_Results.push_back(
427  std::make_unique<ResultListEntry>(std::move(pContentProperties)));
428  }
429  }
430  catch ( DAVException const & )
431  {
432  }
433  }
434 
435  m_bCountFinal = true;
436 
437  // Callback possible, because listeners may be informed!
438  aGuard.clear();
439  getResultSet()->rowCountFinal();
440  }
441  return !m_bThrowException;
442 }
443 
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Environment getEnvironment(OUString const &name, OUString const &implementation)
css::uno::Reference< css::uno::XComponentContext > m_xContext
Reference< XRow > xRow
std::unique_ptr< sal_Int32[]> pData
sal_Int64 n
virtual css::uno::Reference< css::sdbc::XRow > queryPropertyValues(sal_uInt32 nIndex) override
virtual void releasePropertyValues(sal_uInt32 nIndex) override
virtual ~DataSupplier() override
virtual bool isCountFinal() override
static void UCBNamesToDAVNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources)
virtual bool getResult(sal_uInt32 nIndex) override
const OUString & getEscapedTitle() const
static constexpr OUStringLiteral RESOURCETYPE
#define TOOLS_WARN_EXCEPTION(area, stream)
uno::Reference< ucb::XContent > m_xContent
virtual sal_uInt32 totalCount() override
virtual sal_uInt32 currentCount() override
dictionary props
virtual css::uno::Reference< css::ucb::XContentIdentifier > queryContentIdentifier(sal_uInt32 nIndex) override
rtl::Reference< ResultSet > getResultSet() const
virtual void close() override
#define SAL_INFO(area, stream)
virtual css::uno::Reference< css::ucb::XContent > queryContent(sal_uInt32 nIndex) override
OUString DecodeURI(OUString const &rURI)
Definition: CurlUri.cxx:296
virtual OUString queryContentIdentifierString(sal_uInt32 nIndex) override
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
OUString const & GetPath() const
Definition: CurlUri.hxx:72
rtl::Reference< Content > m_xContent
::rtl::Reference< OContentHelper > xContent
Reference< XComponentContext > m_xContext
virtual void validate() override
Reference< XContentIdentifier > xId
exports com.sun.star. uri
OUString aId