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_webdav.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 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 //========================================================================= 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 //========================================================================= 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 //========================================================================= 157 ContentProperties::ContentProperties() 158 : m_xProps( new PropertyValueMap ), 159 m_bTrailingSlash( sal_False ) 160 { 161 } 162 163 //========================================================================= 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 //========================================================================= 174 bool ContentProperties::contains( const rtl::OUString & rName ) const 175 { 176 if ( get( rName ) ) 177 return true; 178 else 179 return false; 180 } 181 182 //========================================================================= 183 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 //========================================================================= 194 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 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 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 //========================================================================= 374 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 //========================================================================= 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 //========================================================================= 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 //========================================================================= 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 //========================================================================= 452 void ContentProperties::addProperty( const DAVPropertyValue & rProp ) 453 { 454 addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive ); 455 } 456 457 //========================================================================= 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 { 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 //========================================================================= 626 CachableContentProperties::CachableContentProperties( 627 const ContentProperties & rProps ) 628 { 629 addProperties( rProps ); 630 } 631 632 //========================================================================= 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 //========================================================================= 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