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 /**************************************************************************
28 TODO
29 **************************************************************************
30
31 *************************************************************************/
32 #include <osl/diagnose.h>
33 #include <com/sun/star/util/DateTime.hpp>
34 #include "SerfUri.hxx"
35 #include "DAVResource.hxx"
36 #include "DAVProperties.hxx"
37 #include "DateTimeHelper.hxx"
38 #include "webdavprovider.hxx"
39 #include "ContentProperties.hxx"
40
41 using namespace com::sun::star;
42 using namespace http_dav_ucp;
43
44 /*
45 =============================================================================
46
47 Property Mapping
48
49 =============================================================================
50 HTTP (entity header) WebDAV (property) UCB (property)
51 =============================================================================
52
53 Allow
54 Content-Encoding
55 Content-Language getcontentlanguage
56 Content-Length getcontentlength Size
57 Content-Location
58 Content-MD5
59 Content-Range
60 Content-Type getcontenttype MediaType
61 Expires
62 Last-Modified getlastmodified DateModified
63 creationdate DateCreated
64 resourcetype IsFolder,IsDocument,ContentType
65 displayname
66 ETag (actually getetag
67 a response header )
68 lockdiscovery
69 supportedlock
70 source
71 Title (always taken from URI)
72
73 =============================================================================
74
75 Important: HTTP headers will not be mapped to DAV properties; only to UCB
76 properties. (Content-Length,Content-Type,Last-Modified)
77 */
78
79 //=========================================================================
80 //=========================================================================
81 //
82 // ContentProperties Implementation.
83 //
84 //=========================================================================
85 //=========================================================================
86
87 // static member!
88 uno::Any ContentProperties::m_aEmptyAny;
89
ContentProperties(const DAVResource & rResource)90 ContentProperties::ContentProperties( const DAVResource& rResource )
91 : m_xProps( new PropertyValueMap ),
92 m_bTrailingSlash( false )
93 {
94 OSL_ENSURE( rResource.uri.getLength(),
95 "ContentProperties ctor - Empty resource URI!" );
96
97 // Title
98 try
99 {
100 SerfUri aURI( rResource.uri );
101 m_aEscapedTitle = aURI.GetPathBaseName();
102
103 (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ]
104 = PropertyValue(
105 uno::makeAny( aURI.GetPathBaseNameUnescaped() ), true );
106 }
107 catch ( DAVException const & )
108 {
109 (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ]
110 = PropertyValue(
111 uno::makeAny(
112 rtl::OUString(
113 RTL_CONSTASCII_USTRINGPARAM( "*** unknown ***" ) ) ),
114 true );
115 }
116
117 std::vector< DAVPropertyValue >::const_iterator it
118 = rResource.properties.begin();
119 std::vector< DAVPropertyValue >::const_iterator end
120 = rResource.properties.end();
121
122 while ( it != end )
123 {
124 addProperty( (*it) );
125 ++it;
126 }
127
128 if ( rResource.uri.getStr()[ rResource.uri.getLength() - 1 ]
129 == sal_Unicode( '/' ) )
130 m_bTrailingSlash = sal_True;
131 }
132
133 //=========================================================================
ContentProperties(const rtl::OUString & rTitle,sal_Bool bFolder)134 ContentProperties::ContentProperties(
135 const rtl::OUString & rTitle, sal_Bool bFolder )
136 : m_xProps( new PropertyValueMap ),
137 m_bTrailingSlash( sal_False )
138 {
139 (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ]
140 = PropertyValue( uno::makeAny( rTitle ), true );
141 (*m_xProps)[ rtl::OUString::createFromAscii( "IsFolder" ) ]
142 = PropertyValue( uno::makeAny( bFolder ), true );
143 (*m_xProps)[ rtl::OUString::createFromAscii( "IsDocument" ) ]
144 = PropertyValue( uno::makeAny( sal_Bool( !bFolder ) ), true );
145 }
146
147 //=========================================================================
ContentProperties(const rtl::OUString & rTitle)148 ContentProperties::ContentProperties( const rtl::OUString & rTitle )
149 : m_xProps( new PropertyValueMap ),
150 m_bTrailingSlash( sal_False )
151 {
152 (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ]
153 = PropertyValue( uno::makeAny( rTitle ), true );
154 }
155
156 //=========================================================================
ContentProperties()157 ContentProperties::ContentProperties()
158 : m_xProps( new PropertyValueMap ),
159 m_bTrailingSlash( sal_False )
160 {
161 }
162
163 //=========================================================================
ContentProperties(const ContentProperties & rOther)164 ContentProperties::ContentProperties( const ContentProperties & rOther )
165 : m_aEscapedTitle( rOther.m_aEscapedTitle ),
166 m_xProps( rOther.m_xProps.get()
167 ? new PropertyValueMap( *rOther.m_xProps )
168 : new PropertyValueMap ),
169 m_bTrailingSlash( rOther.m_bTrailingSlash )
170 {
171 }
172
173 //=========================================================================
contains(const rtl::OUString & rName) const174 bool ContentProperties::contains( const rtl::OUString & rName ) const
175 {
176 if ( get( rName ) )
177 return true;
178 else
179 return false;
180 }
181
182 //=========================================================================
getValue(const rtl::OUString & rName) const183 const uno::Any & ContentProperties::getValue(
184 const rtl::OUString & rName ) const
185 {
186 const PropertyValue * pProp = get( rName );
187 if ( pProp )
188 return pProp->value();
189 else
190 return m_aEmptyAny;
191 }
192
193 //=========================================================================
get(const rtl::OUString & rName) const194 const PropertyValue * ContentProperties::get(
195 const rtl::OUString & rName ) const
196 {
197 PropertyValueMap::const_iterator it = m_xProps->find( rName );
198 const PropertyValueMap::const_iterator end = m_xProps->end();
199
200 if ( it == end )
201 {
202 it = m_xProps->begin();
203 while ( it != end )
204 {
205 if ( (*it).first.equalsIgnoreAsciiCase( rName ) )
206 return &(*it).second;
207
208 ++it;
209 }
210 return 0;
211 }
212 else
213 return &(*it).second;
214 }
215
216 //=========================================================================
217 // static
UCBNamesToDAVNames(const uno::Sequence<beans::Property> & rProps,std::vector<rtl::OUString> & propertyNames,bool bIncludeUnmatched)218 void ContentProperties::UCBNamesToDAVNames(
219 const uno::Sequence< beans::Property > & rProps,
220 std::vector< rtl::OUString > & propertyNames,
221 bool bIncludeUnmatched /* = true */ )
222 {
223 //////////////////////////////////////////////////////////////
224 // Assemble list of DAV properties to obtain from server.
225 // Append DAV properties needed to obtain requested UCB props.
226 //////////////////////////////////////////////////////////////
227
228 // DAV UCB
229 // creationdate <- DateCreated
230 // getlastmodified <- DateModified
231 // getcontenttype <- MediaType
232 // getcontentlength <- Size
233 // resourcetype <- IsFolder, IsDocument, ContentType
234 // (taken from URI) <- Title
235
236 sal_Bool bCreationDate = sal_False;
237 sal_Bool bLastModified = sal_False;
238 sal_Bool bContentType = sal_False;
239 sal_Bool bContentLength = sal_False;
240 sal_Bool bResourceType = sal_False;
241
242 sal_Int32 nCount = rProps.getLength();
243 for ( sal_Int32 n = 0; n < nCount; ++n )
244 {
245 const beans::Property & rProp = rProps[ n ];
246
247 if ( rProp.Name.equalsAsciiL(
248 RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
249 {
250 // Title is always obtained from resource's URI.
251 continue;
252 }
253 else if ( rProp.Name.equalsAsciiL(
254 RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) )
255 ||
256 ( rProp.Name == DAVProperties::CREATIONDATE ) )
257 {
258 if ( !bCreationDate )
259 {
260 propertyNames.push_back( DAVProperties::CREATIONDATE );
261 bCreationDate = sal_True;
262 }
263 }
264 else if ( rProp.Name.equalsAsciiL(
265 RTL_CONSTASCII_STRINGPARAM( "DateModified" ) )
266 ||
267 ( rProp.Name == DAVProperties::GETLASTMODIFIED ) )
268 {
269 if ( !bLastModified )
270 {
271 propertyNames.push_back(
272 DAVProperties::GETLASTMODIFIED );
273 bLastModified = sal_True;
274 }
275 }
276 else if ( rProp.Name.equalsAsciiL(
277 RTL_CONSTASCII_STRINGPARAM( "MediaType" ) )
278 ||
279 ( rProp.Name == DAVProperties::GETCONTENTTYPE ) )
280 {
281 if ( !bContentType )
282 {
283 propertyNames.push_back(
284 DAVProperties::GETCONTENTTYPE );
285 bContentType = sal_True;
286 }
287 }
288 else if ( rProp.Name.equalsAsciiL(
289 RTL_CONSTASCII_STRINGPARAM( "Size" ) )
290 ||
291 ( rProp.Name == DAVProperties::GETCONTENTLENGTH ) )
292 {
293 if ( !bContentLength )
294 {
295 propertyNames.push_back(
296 DAVProperties::GETCONTENTLENGTH );
297 bContentLength = sal_True;
298 }
299 }
300 else if ( rProp.Name.equalsAsciiL(
301 RTL_CONSTASCII_STRINGPARAM( "ContentType" ) )
302 ||
303 rProp.Name.equalsAsciiL(
304 RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) )
305 ||
306 rProp.Name.equalsAsciiL(
307 RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) )
308 ||
309 ( rProp.Name == DAVProperties::RESOURCETYPE ) )
310 {
311 if ( !bResourceType )
312 {
313 propertyNames.push_back( DAVProperties::RESOURCETYPE );
314 bResourceType = sal_True;
315 }
316 }
317 else
318 {
319 if ( bIncludeUnmatched )
320 propertyNames.push_back( rProp.Name );
321 }
322 }
323 }
324
325 //=========================================================================
326 // static
UCBNamesToHTTPNames(const uno::Sequence<beans::Property> & rProps,std::vector<rtl::OUString> & propertyNames,bool bIncludeUnmatched)327 void ContentProperties::UCBNamesToHTTPNames(
328 const uno::Sequence< beans::Property > & rProps,
329 std::vector< rtl::OUString > & propertyNames,
330 bool bIncludeUnmatched /* = true */ )
331 {
332 //////////////////////////////////////////////////////////////
333 // Assemble list of HTTP header names to obtain from server.
334 // Append HTTP headers needed to obtain requested UCB props.
335 //////////////////////////////////////////////////////////////
336
337 // HTTP UCB
338 // Last-Modified <- DateModified
339 // Content-Type <- MediaType
340 // Content-Length <- Size
341
342 sal_Int32 nCount = rProps.getLength();
343 for ( sal_Int32 n = 0; n < nCount; ++n )
344 {
345 const beans::Property & rProp = rProps[ n ];
346
347 if ( rProp.Name.equalsAsciiL(
348 RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
349 {
350 propertyNames.push_back(
351 rtl::OUString::createFromAscii( "Last-Modified" ) );
352 }
353 else if ( rProp.Name.equalsAsciiL(
354 RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
355 {
356 propertyNames.push_back(
357 rtl::OUString::createFromAscii( "Content-Type" ) );
358 }
359 else if ( rProp.Name.equalsAsciiL(
360 RTL_CONSTASCII_STRINGPARAM( "Size" ) ) )
361 {
362 propertyNames.push_back(
363 rtl::OUString::createFromAscii( "Content-Length" ) );
364 }
365 else
366 {
367 if ( bIncludeUnmatched )
368 propertyNames.push_back( rProp.Name );
369 }
370 }
371 }
372
373 //=========================================================================
containsAllNames(const uno::Sequence<beans::Property> & rProps,std::vector<rtl::OUString> & rNamesNotContained) const374 bool ContentProperties::containsAllNames(
375 const uno::Sequence< beans::Property >& rProps,
376 std::vector< rtl::OUString > & rNamesNotContained ) const
377 {
378 rNamesNotContained.clear();
379
380 sal_Int32 nCount = rProps.getLength();
381 for ( sal_Int32 n = 0; n < nCount; ++n )
382 {
383 const rtl::OUString & rName = rProps[ n ].Name;
384 if ( !contains( rName ) )
385 {
386 // Not found.
387 rNamesNotContained.push_back( rName );
388 }
389 }
390
391 return ( rNamesNotContained.size() == 0 );
392 }
393
394 //=========================================================================
addProperties(const std::vector<rtl::OUString> & rProps,const ContentProperties & rContentProps)395 void ContentProperties::addProperties(
396 const std::vector< rtl::OUString > & rProps,
397 const ContentProperties & rContentProps )
398 {
399 std::vector< rtl::OUString >::const_iterator it = rProps.begin();
400 std::vector< rtl::OUString >::const_iterator end = rProps.end();
401
402 while ( it != end )
403 {
404 const rtl::OUString & rName = (*it);
405
406 if ( !contains( rName ) ) // ignore duplicates
407 {
408 const PropertyValue * pProp = rContentProps.get( rName );
409 if ( pProp )
410 {
411 // Add it.
412 addProperty( rName, pProp->value(), pProp->isCaseSensitive() );
413 }
414 else
415 {
416 addProperty( rName, uno::Any(), false );
417 }
418 }
419 ++it;
420 }
421 }
422
423 //=========================================================================
addProperties(const ContentProperties & rProps)424 void ContentProperties::addProperties( const ContentProperties & rProps )
425 {
426 PropertyValueMap::const_iterator it = rProps.m_xProps->begin();
427 const PropertyValueMap::const_iterator end = rProps.m_xProps->end();
428
429 while ( it != end )
430 {
431 addProperty(
432 (*it).first, (*it).second.value(), (*it).second.isCaseSensitive() );
433 ++it;
434 }
435 }
436
437 //=========================================================================
addProperties(const std::vector<DAVPropertyValue> & rProps)438 void ContentProperties::addProperties(
439 const std::vector< DAVPropertyValue > & rProps )
440 {
441 std::vector< DAVPropertyValue >::const_iterator it = rProps.begin();
442 const std::vector< DAVPropertyValue >::const_iterator end = rProps.end();
443
444 while ( it != end )
445 {
446 addProperty( (*it) );
447 ++it;
448 }
449 }
450
451 //=========================================================================
addProperty(const DAVPropertyValue & rProp)452 void ContentProperties::addProperty( const DAVPropertyValue & rProp )
453 {
454 addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive );
455 }
456
457 //=========================================================================
addProperty(const rtl::OUString & rName,const com::sun::star::uno::Any & rValue,bool bIsCaseSensitive)458 void ContentProperties::addProperty( const rtl::OUString & rName,
459 const com::sun::star::uno::Any & rValue,
460 bool bIsCaseSensitive )
461 {
462 if ( rName.equals( DAVProperties::CREATIONDATE ) )
463 {
464 // Map DAV:creationdate to UCP:DateCreated
465 rtl::OUString aValue;
466 rValue >>= aValue;
467 util::DateTime aDate;
468 DateTimeHelper::convert( aValue, aDate );
469
470 (*m_xProps)[ rtl::OUString::createFromAscii( "DateCreated" ) ]
471 = PropertyValue( uno::makeAny( aDate ), true );
472 }
473 // else if ( rName.equals( DAVProperties::DISPLAYNAME ) )
474 // {
475 // }
476 // else if ( rName.equals( DAVProperties::GETCONTENTLANGUAGE ) )
477 // {
478 // }
479 else if ( rName.equals( DAVProperties::GETCONTENTLENGTH ) )
480 {
481 // Map DAV:getcontentlength to UCP:Size
482 rtl::OUString aValue;
483 rValue >>= aValue;
484
485 (*m_xProps)[ rtl::OUString::createFromAscii( "Size" ) ]
486 = PropertyValue( uno::makeAny( aValue.toInt64() ), true );
487 }
488 else if ( rName.equalsAsciiL(
489 RTL_CONSTASCII_STRINGPARAM( "Content-Length" ) ) )
490 {
491 // Do NOT map Content-Lenght entity header to DAV:getcontentlength!
492 // Only DAV resources have this property.
493
494 // Map Content-Length entity header to UCP:Size
495 rtl::OUString aValue;
496 rValue >>= aValue;
497
498 (*m_xProps)[ rtl::OUString::createFromAscii( "Size" ) ]
499 = PropertyValue( uno::makeAny( aValue.toInt64() ), true );
500 }
501 else if ( rName.equals( DAVProperties::GETCONTENTTYPE ) )
502 {
503 // Map DAV:getcontenttype to UCP:MediaType (1:1)
504 (*m_xProps)[ rtl::OUString::createFromAscii( "MediaType" ) ]
505 = PropertyValue( rValue, true );
506 }
507 else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Content-Type" ) ) )
508 {
509 // Do NOT map Content-Type entity header to DAV:getcontenttype!
510 // Only DAV resources have this property.
511
512 // Map DAV:getcontenttype to UCP:MediaType (1:1)
513 (*m_xProps)[ rtl::OUString::createFromAscii( "MediaType" ) ]
514 = PropertyValue( rValue, true );
515 }
516 // else if ( rName.equals( DAVProperties::GETETAG ) )
517 // {
518 // }
519 else if ( rName.equals( DAVProperties::GETLASTMODIFIED ) )
520 {
521 // Map the DAV:getlastmodified entity header to UCP:DateModified
522 rtl::OUString aValue;
523 rValue >>= aValue;
524 util::DateTime aDate;
525 DateTimeHelper::convert( aValue, aDate );
526
527 (*m_xProps)[ rtl::OUString::createFromAscii( "DateModified" ) ]
528 = PropertyValue( uno::makeAny( aDate ), true );
529 }
530 else if ( rName.equalsAsciiL(
531 RTL_CONSTASCII_STRINGPARAM( "Last-Modified" ) ) )
532 {
533 // Do not map Last-Modified entity header to DAV:getlastmodified!
534 // Only DAV resources have this property.
535
536 // Map the Last-Modified entity header to UCP:DateModified
537 rtl::OUString aValue;
538 rValue >>= aValue;
539 util::DateTime aDate;
540 DateTimeHelper::convert( aValue, aDate );
541
542 (*m_xProps)[ rtl::OUString::createFromAscii( "DateModified" ) ]
543 = PropertyValue( uno::makeAny( aDate ), true );
544 }
545 // else if ( rName.equals( DAVProperties::LOCKDISCOVERY ) )
546 // {
547 // }
548 else if ( rName.equals( DAVProperties::RESOURCETYPE ) )
549 {
550 rtl::OUString aValue;
551 rValue >>= aValue;
552
553 // Map DAV:resourceype to UCP:IsFolder, UCP:IsDocument, UCP:ContentType
554 sal_Bool bFolder =
555 aValue.equalsIgnoreAsciiCaseAsciiL(
556 RTL_CONSTASCII_STRINGPARAM( "collection" ) );
557
558 (*m_xProps)[ rtl::OUString::createFromAscii( "IsFolder" ) ]
559 = PropertyValue( uno::makeAny( bFolder ), true );
560 (*m_xProps)[ rtl::OUString::createFromAscii( "IsDocument" ) ]
561 = PropertyValue( uno::makeAny( sal_Bool( !bFolder ) ), true );
562 (*m_xProps)[ rtl::OUString::createFromAscii( "ContentType" ) ]
563 = PropertyValue( uno::makeAny( bFolder
564 ? rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE )
565 : rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE ) ), true );
566 }
567 // else if ( rName.equals( DAVProperties::SUPPORTEDLOCK ) )
568 // {
569 // }
570
571 // Save property.
572 (*m_xProps)[ rName ] = PropertyValue( rValue, bIsCaseSensitive );
573 }
574
575 //=========================================================================
576 //=========================================================================
577 //
578 // CachableContentProperties Implementation.
579 //
580 //=========================================================================
581 //=========================================================================
582
583 namespace
584 {
isCachable(rtl::OUString const & rName,bool isCaseSensitive)585 bool isCachable( rtl::OUString const & rName,
586 bool isCaseSensitive )
587 {
588 static rtl::OUString aNonCachableProps [] =
589 {
590 DAVProperties::LOCKDISCOVERY,
591
592 DAVProperties::GETETAG,
593 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ETag" ) ),
594
595 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ),
596 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Last-Modified" ) ),
597 DAVProperties::GETLASTMODIFIED,
598
599 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ),
600 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Content-Length" ) ),
601 DAVProperties::GETCONTENTLENGTH,
602
603 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Date" ) )
604 };
605
606 for ( sal_uInt32 n = 0;
607 n < ( sizeof( aNonCachableProps )
608 / sizeof( aNonCachableProps[ 0 ] ) );
609 ++n )
610 {
611 if ( isCaseSensitive )
612 {
613 if ( rName.equals( aNonCachableProps[ n ] ) )
614 return false;
615 }
616 else
617 if ( rName.equalsIgnoreAsciiCase( aNonCachableProps[ n ] ) )
618 return false;
619 }
620 return true;
621 }
622
623 } // namespace
624
625 //=========================================================================
CachableContentProperties(const ContentProperties & rProps)626 CachableContentProperties::CachableContentProperties(
627 const ContentProperties & rProps )
628 {
629 addProperties( rProps );
630 }
631
632 //=========================================================================
addProperties(const ContentProperties & rProps)633 void CachableContentProperties::addProperties(
634 const ContentProperties & rProps )
635 {
636 const std::auto_ptr< PropertyValueMap > & props = rProps.getProperties();
637
638 PropertyValueMap::const_iterator it = props->begin();
639 const PropertyValueMap::const_iterator end = props->end();
640
641 while ( it != end )
642 {
643 if ( isCachable( (*it).first, (*it).second.isCaseSensitive() ) )
644 m_aProps.addProperty( (*it).first,
645 (*it).second.value(),
646 (*it).second.isCaseSensitive() );
647
648 ++it;
649 }
650 }
651
652 //=========================================================================
addProperties(const std::vector<DAVPropertyValue> & rProps)653 void CachableContentProperties::addProperties(
654 const std::vector< DAVPropertyValue > & rProps )
655 {
656 std::vector< DAVPropertyValue >::const_iterator it = rProps.begin();
657 const std::vector< DAVPropertyValue >::const_iterator end = rProps.end();
658
659 while ( it != end )
660 {
661 if ( isCachable( (*it).Name, (*it).IsCaseSensitive ) )
662 m_aProps.addProperty( (*it) );
663
664 ++it;
665 }
666 }
667